11//! Detecting usage of the `#[debugger_visualizer]` attribute.
22
3- use hir:: CRATE_HIR_ID ;
4- use rustc_data_structures:: fx:: FxHashSet ;
3+ use rustc_ast:: Attribute ;
54use rustc_data_structures:: sync:: Lrc ;
65use rustc_expand:: base:: resolve_path;
7- use rustc_hir as hir;
8- use rustc_hir:: HirId ;
9- use rustc_middle:: query:: { LocalCrate , Providers } ;
10- use rustc_middle:: ty:: TyCtxt ;
6+ use rustc_session:: Session ;
117use rustc_span:: { sym, DebuggerVisualizerFile , DebuggerVisualizerType } ;
128
13- use crate :: errors:: DebugVisualizerUnreadable ;
9+ use crate :: errors:: { DebugVisualizerInvalid , DebugVisualizerUnreadable } ;
1410
15- fn check_for_debugger_visualizer (
16- tcx : TyCtxt < ' _ > ,
17- hir_id : HirId ,
18- debugger_visualizers : & mut FxHashSet < DebuggerVisualizerFile > ,
19- ) {
20- let attrs = tcx. hir ( ) . attrs ( hir_id) ;
21- for attr in attrs {
11+ impl DebuggerVisualizerCollector < ' _ > {
12+ fn check_for_debugger_visualizer ( & mut self , attr : & Attribute ) {
2213 if attr. has_name ( sym:: debugger_visualizer) {
23- let Some ( list) = attr. meta_item_list ( ) else {
24- continue
14+ let Some ( hints) = attr. meta_item_list ( ) else {
15+ self . sess . emit_err ( DebugVisualizerInvalid { span : attr. span } ) ;
16+ return ;
2517 } ;
2618
27- let meta_item = match list. len ( ) {
28- 1 => match list[ 0 ] . meta_item ( ) {
29- Some ( meta_item) => meta_item,
30- _ => continue ,
31- } ,
32- _ => continue ,
19+ let hint = if hints. len ( ) == 1 {
20+ & hints[ 0 ]
21+ } else {
22+ self . sess . emit_err ( DebugVisualizerInvalid { span : attr. span } ) ;
23+ return ;
3324 } ;
3425
35- let visualizer_type = match meta_item. name_or_empty ( ) {
36- sym:: natvis_file => DebuggerVisualizerType :: Natvis ,
37- sym:: gdb_script_file => DebuggerVisualizerType :: GdbPrettyPrinter ,
38- _ => continue ,
26+ let Some ( meta_item) = hint. meta_item ( ) else {
27+ self . sess . emit_err ( DebugVisualizerInvalid { span : attr. span } ) ;
28+ return ;
3929 } ;
4030
41- let file = match meta_item . value_str ( ) {
42- Some ( value ) => {
43- match resolve_path ( & tcx . sess . parse_sess , value . as_str ( ) , attr . span ) {
44- Ok ( file ) => file ,
45- _ => continue ,
31+ let ( visualizer_type , visualizer_path ) =
32+ match ( meta_item . name_or_empty ( ) , meta_item . value_str ( ) ) {
33+ ( sym :: natvis_file , Some ( value ) ) => ( DebuggerVisualizerType :: Natvis , value ) ,
34+ ( sym :: gdb_script_file , Some ( value ) ) => {
35+ ( DebuggerVisualizerType :: GdbPrettyPrinter , value )
4636 }
47- }
48- None => continue ,
49- } ;
37+ ( _, _) => {
38+ self . sess . emit_err ( DebugVisualizerInvalid { span : meta_item. span } ) ;
39+ return ;
40+ }
41+ } ;
42+
43+ let file =
44+ match resolve_path ( & self . sess . parse_sess , visualizer_path. as_str ( ) , attr. span ) {
45+ Ok ( file) => file,
46+ Err ( mut err) => {
47+ err. emit ( ) ;
48+ return ;
49+ }
50+ } ;
5051
5152 match std:: fs:: read ( & file) {
5253 Ok ( contents) => {
53- debugger_visualizers
54- . insert ( DebuggerVisualizerFile :: new ( Lrc :: from ( contents) , visualizer_type) ) ;
54+ self . visualizers . push ( DebuggerVisualizerFile :: new (
55+ Lrc :: from ( contents) ,
56+ visualizer_type,
57+ file,
58+ ) ) ;
5559 }
5660 Err ( error) => {
57- tcx . sess . emit_err ( DebugVisualizerUnreadable {
61+ self . sess . emit_err ( DebugVisualizerUnreadable {
5862 span : meta_item. span ,
5963 file : & file,
6064 error,
@@ -65,31 +69,25 @@ fn check_for_debugger_visualizer(
6569 }
6670}
6771
68- /// Traverses and collects the debugger visualizers for a specific crate.
69- fn debugger_visualizers ( tcx : TyCtxt < ' _ > , _: LocalCrate ) -> Vec < DebuggerVisualizerFile > {
70- // Initialize the collector.
71- let mut debugger_visualizers = FxHashSet :: default ( ) ;
72-
73- // Collect debugger visualizers in this crate.
74- tcx. hir ( ) . for_each_module ( |id| {
75- check_for_debugger_visualizer (
76- tcx,
77- tcx. hir ( ) . local_def_id_to_hir_id ( id) ,
78- & mut debugger_visualizers,
79- )
80- } ) ;
72+ struct DebuggerVisualizerCollector < ' a > {
73+ sess : & ' a Session ,
74+ visualizers : Vec < DebuggerVisualizerFile > ,
75+ }
8176
82- // Collect debugger visualizers on the crate attributes.
83- check_for_debugger_visualizer ( tcx, CRATE_HIR_ID , & mut debugger_visualizers) ;
77+ impl < ' ast > rustc_ast:: visit:: Visitor < ' ast > for DebuggerVisualizerCollector < ' _ > {
78+ fn visit_attribute ( & mut self , attr : & ' ast Attribute ) {
79+ self . check_for_debugger_visualizer ( attr) ;
80+ rustc_ast:: visit:: walk_attribute ( self , attr) ;
81+ }
82+ }
8483
85- // Extract out the found debugger_visualizer items.
86- let mut visualizers = debugger_visualizers. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
84+ /// Traverses and collects the debugger visualizers for a specific crate.
85+ pub fn collect ( sess : & Session , krate : & rustc_ast:: ast:: Crate ) -> Vec < DebuggerVisualizerFile > {
86+ // Initialize the collector.
87+ let mut visitor = DebuggerVisualizerCollector { sess, visualizers : Vec :: new ( ) } ;
88+ rustc_ast:: visit:: Visitor :: visit_crate ( & mut visitor, krate) ;
8789
8890 // Sort the visualizers so we always get a deterministic query result.
89- visualizers. sort ( ) ;
90- visualizers
91- }
92-
93- pub fn provide ( providers : & mut Providers ) {
94- providers. debugger_visualizers = debugger_visualizers;
91+ visitor. visualizers . sort_unstable ( ) ;
92+ visitor. visualizers
9593}
0 commit comments