1
1
//! Detecting usage of the `#[debugger_visualizer]` attribute.
2
2
3
- use hir:: CRATE_HIR_ID ;
4
- use rustc_data_structures:: fx:: FxHashSet ;
3
+ use rustc_ast:: Attribute ;
5
4
use rustc_data_structures:: sync:: Lrc ;
6
5
use 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 ;
11
7
use rustc_span:: { sym, DebuggerVisualizerFile , DebuggerVisualizerType } ;
12
8
13
- use crate :: errors:: DebugVisualizerUnreadable ;
9
+ use crate :: errors:: { DebugVisualizerInvalid , DebugVisualizerUnreadable } ;
14
10
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 ) {
22
13
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 ;
25
17
} ;
26
18
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 ;
33
24
} ;
34
25
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 ;
39
29
} ;
40
30
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 )
46
36
}
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
+ } ;
50
51
51
52
match std:: fs:: read ( & file) {
52
53
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
+ ) ) ;
55
59
}
56
60
Err ( error) => {
57
- tcx . sess . emit_err ( DebugVisualizerUnreadable {
61
+ self . sess . emit_err ( DebugVisualizerUnreadable {
58
62
span : meta_item. span ,
59
63
file : & file,
60
64
error,
@@ -65,31 +69,25 @@ fn check_for_debugger_visualizer(
65
69
}
66
70
}
67
71
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
+ }
81
76
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
+ }
84
83
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) ;
87
89
88
90
// 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
95
93
}
0 commit comments