@@ -46,6 +46,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode};
46
46
use rustc:: hir;
47
47
use rustc:: hir:: def_id:: DefId ;
48
48
use rustc:: hir:: itemlikevisit:: ItemLikeVisitor ;
49
+ use rustc:: hir:: intravisit;
49
50
use syntax:: ast:: { self , Attribute , NestedMetaItem } ;
50
51
use rustc_data_structures:: fx:: { FxHashSet , FxHashMap } ;
51
52
use syntax_pos:: Span ;
@@ -73,17 +74,29 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
73
74
let query = tcx. dep_graph . query ( ) ;
74
75
debug ! ( "query-nodes: {:?}" , query. nodes( ) ) ;
75
76
let krate = tcx. hir . krate ( ) ;
76
- krate . visit_all_item_likes ( & mut DirtyCleanVisitor {
77
+ let mut dirty_clean_visitor = DirtyCleanVisitor {
77
78
tcx : tcx,
78
79
query : & query,
79
80
dirty_inputs : dirty_inputs,
80
- } ) ;
81
+ checked_attrs : FxHashSet ( ) ,
82
+ } ;
83
+ krate. visit_all_item_likes ( & mut dirty_clean_visitor) ;
84
+
85
+ let mut all_attrs = FindAllAttrs {
86
+ tcx : tcx,
87
+ attr_names : vec ! [ ATTR_DIRTY , ATTR_CLEAN ] ,
88
+ found_attrs : vec ! [ ] ,
89
+ } ;
90
+ intravisit:: walk_crate ( & mut all_attrs, krate) ;
91
+
92
+ all_attrs. report_unchecked_attrs ( & dirty_clean_visitor. checked_attrs ) ;
81
93
}
82
94
83
95
pub struct DirtyCleanVisitor < ' a , ' tcx : ' a > {
84
96
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
85
97
query : & ' a DepGraphQuery < DefId > ,
86
98
dirty_inputs : FxHashSet < DepNode < DefId > > ,
99
+ checked_attrs : FxHashSet < ast:: AttrId > ,
87
100
}
88
101
89
102
impl < ' a , ' tcx > DirtyCleanVisitor < ' a , ' tcx > {
@@ -109,7 +122,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
109
122
dep_node. map_def ( |& def_id| Some ( self . tcx . item_path_str ( def_id) ) ) . unwrap ( )
110
123
}
111
124
112
- fn assert_dirty ( & self , item : & hir :: Item , dep_node : DepNode < DefId > ) {
125
+ fn assert_dirty ( & self , item_span : Span , dep_node : DepNode < DefId > ) {
113
126
debug ! ( "assert_dirty({:?})" , dep_node) ;
114
127
115
128
match dep_node {
@@ -121,7 +134,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
121
134
if !self . dirty_inputs . contains ( & dep_node) {
122
135
let dep_node_str = self . dep_node_str ( & dep_node) ;
123
136
self . tcx . sess . span_err (
124
- item . span ,
137
+ item_span ,
125
138
& format ! ( "`{:?}` not found in dirty set, but should be dirty" ,
126
139
dep_node_str) ) ;
127
140
}
@@ -132,14 +145,14 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
132
145
if self . query . contains_node ( & dep_node) {
133
146
let dep_node_str = self . dep_node_str ( & dep_node) ;
134
147
self . tcx . sess . span_err (
135
- item . span ,
148
+ item_span ,
136
149
& format ! ( "`{:?}` found in dep graph, but should be dirty" , dep_node_str) ) ;
137
150
}
138
151
}
139
152
}
140
153
}
141
154
142
- fn assert_clean ( & self , item : & hir :: Item , dep_node : DepNode < DefId > ) {
155
+ fn assert_clean ( & self , item_span : Span , dep_node : DepNode < DefId > ) {
143
156
debug ! ( "assert_clean({:?})" , dep_node) ;
144
157
145
158
match dep_node {
@@ -150,7 +163,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
150
163
if self . dirty_inputs . contains ( & dep_node) {
151
164
let dep_node_str = self . dep_node_str ( & dep_node) ;
152
165
self . tcx . sess . span_err (
153
- item . span ,
166
+ item_span ,
154
167
& format ! ( "`{:?}` found in dirty-node set, but should be clean" ,
155
168
dep_node_str) ) ;
156
169
}
@@ -160,35 +173,43 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
160
173
if !self . query . contains_node ( & dep_node) {
161
174
let dep_node_str = self . dep_node_str ( & dep_node) ;
162
175
self . tcx . sess . span_err (
163
- item . span ,
176
+ item_span ,
164
177
& format ! ( "`{:?}` not found in dep graph, but should be clean" ,
165
178
dep_node_str) ) ;
166
179
}
167
180
}
168
181
}
169
182
}
170
- }
171
183
172
- impl < ' a , ' tcx > ItemLikeVisitor < ' tcx > for DirtyCleanVisitor < ' a , ' tcx > {
173
- fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
174
- let def_id = self . tcx . hir . local_def_id ( item. id ) ;
184
+ fn check_item ( & mut self , item_id : ast:: NodeId , item_span : Span ) {
185
+ let def_id = self . tcx . hir . local_def_id ( item_id) ;
175
186
for attr in self . tcx . get_attrs ( def_id) . iter ( ) {
176
187
if attr. check_name ( ATTR_DIRTY ) {
177
188
if check_config ( self . tcx , attr) {
178
- self . assert_dirty ( item, self . dep_node ( attr, def_id) ) ;
189
+ self . checked_attrs . insert ( attr. id ) ;
190
+ self . assert_dirty ( item_span, self . dep_node ( attr, def_id) ) ;
179
191
}
180
192
} else if attr. check_name ( ATTR_CLEAN ) {
181
193
if check_config ( self . tcx , attr) {
182
- self . assert_clean ( item, self . dep_node ( attr, def_id) ) ;
194
+ self . checked_attrs . insert ( attr. id ) ;
195
+ self . assert_clean ( item_span, self . dep_node ( attr, def_id) ) ;
183
196
}
184
197
}
185
198
}
186
199
}
200
+ }
187
201
188
- fn visit_trait_item ( & mut self , _trait_item : & hir:: TraitItem ) {
202
+ impl < ' a , ' tcx > ItemLikeVisitor < ' tcx > for DirtyCleanVisitor < ' a , ' tcx > {
203
+ fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
204
+ self . check_item ( item. id , item. span ) ;
189
205
}
190
206
191
- fn visit_impl_item ( & mut self , _impl_item : & hir:: ImplItem ) {
207
+ fn visit_trait_item ( & mut self , item : & hir:: TraitItem ) {
208
+ self . check_item ( item. id , item. span ) ;
209
+ }
210
+
211
+ fn visit_impl_item ( & mut self , item : & hir:: ImplItem ) {
212
+ self . check_item ( item. id , item. span ) ;
192
213
}
193
214
}
194
215
@@ -201,46 +222,66 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
201
222
202
223
tcx. dep_graph . with_ignore ( ||{
203
224
let krate = tcx. hir . krate ( ) ;
204
- krate . visit_all_item_likes ( & mut DirtyCleanMetadataVisitor {
225
+ let mut dirty_clean_visitor = DirtyCleanMetadataVisitor {
205
226
tcx : tcx,
206
227
prev_metadata_hashes : prev_metadata_hashes,
207
228
current_metadata_hashes : current_metadata_hashes,
208
- } ) ;
229
+ checked_attrs : FxHashSet ( ) ,
230
+ } ;
231
+ krate. visit_all_item_likes ( & mut dirty_clean_visitor) ;
232
+
233
+ let mut all_attrs = FindAllAttrs {
234
+ tcx : tcx,
235
+ attr_names : vec ! [ ATTR_DIRTY_METADATA , ATTR_CLEAN_METADATA ] ,
236
+ found_attrs : vec ! [ ] ,
237
+ } ;
238
+ intravisit:: walk_crate ( & mut all_attrs, krate) ;
239
+
240
+ all_attrs. report_unchecked_attrs ( & dirty_clean_visitor. checked_attrs ) ;
209
241
} ) ;
210
242
}
211
243
212
244
pub struct DirtyCleanMetadataVisitor < ' a , ' tcx : ' a , ' m > {
213
245
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
214
246
prev_metadata_hashes : & ' m FxHashMap < DefId , Fingerprint > ,
215
247
current_metadata_hashes : & ' m FxHashMap < DefId , Fingerprint > ,
248
+ checked_attrs : FxHashSet < ast:: AttrId > ,
216
249
}
217
250
218
251
impl < ' a , ' tcx , ' m > ItemLikeVisitor < ' tcx > for DirtyCleanMetadataVisitor < ' a , ' tcx , ' m > {
219
252
fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
220
- let def_id = self . tcx . hir . local_def_id ( item. id ) ;
253
+ self . check_item ( item. id , item. span ) ;
254
+ }
255
+
256
+ fn visit_trait_item ( & mut self , item : & hir:: TraitItem ) {
257
+ self . check_item ( item. id , item. span ) ;
258
+ }
259
+
260
+ fn visit_impl_item ( & mut self , item : & hir:: ImplItem ) {
261
+ self . check_item ( item. id , item. span ) ;
262
+ }
263
+ }
264
+
265
+ impl < ' a , ' tcx , ' m > DirtyCleanMetadataVisitor < ' a , ' tcx , ' m > {
266
+
267
+ fn check_item ( & mut self , item_id : ast:: NodeId , item_span : Span ) {
268
+ let def_id = self . tcx . hir . local_def_id ( item_id) ;
221
269
222
270
for attr in self . tcx . get_attrs ( def_id) . iter ( ) {
223
271
if attr. check_name ( ATTR_DIRTY_METADATA ) {
224
272
if check_config ( self . tcx , attr) {
225
- self . assert_state ( false , def_id, item. span ) ;
273
+ self . checked_attrs . insert ( attr. id ) ;
274
+ self . assert_state ( false , def_id, item_span) ;
226
275
}
227
276
} else if attr. check_name ( ATTR_CLEAN_METADATA ) {
228
277
if check_config ( self . tcx , attr) {
229
- self . assert_state ( true , def_id, item. span ) ;
278
+ self . checked_attrs . insert ( attr. id ) ;
279
+ self . assert_state ( true , def_id, item_span) ;
230
280
}
231
281
}
232
282
}
233
283
}
234
284
235
- fn visit_trait_item ( & mut self , _trait_item : & hir:: TraitItem ) {
236
- }
237
-
238
- fn visit_impl_item ( & mut self , _impl_item : & hir:: ImplItem ) {
239
- }
240
- }
241
-
242
- impl < ' a , ' tcx , ' m > DirtyCleanMetadataVisitor < ' a , ' tcx , ' m > {
243
-
244
285
fn assert_state ( & self , should_be_clean : bool , def_id : DefId , span : Span ) {
245
286
let item_path = self . tcx . item_path_str ( def_id) ;
246
287
debug ! ( "assert_state({})" , item_path) ;
@@ -274,7 +315,7 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
274
315
/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
275
316
/// for a `cfg="foo"` attribute and check whether we have a cfg
276
317
/// flag called `foo`.
277
- fn check_config ( tcx : TyCtxt , attr : & ast :: Attribute ) -> bool {
318
+ fn check_config ( tcx : TyCtxt , attr : & Attribute ) -> bool {
278
319
debug ! ( "check_config(attr={:?})" , attr) ;
279
320
let config = & tcx. sess . parse_sess . config ;
280
321
debug ! ( "check_config: config={:?}" , config) ;
@@ -304,3 +345,47 @@ fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name {
304
345
tcx. sess . span_fatal ( item. span , & msg) ;
305
346
}
306
347
}
348
+
349
+
350
+ // A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from
351
+ // the HIR. It is used to verfiy that we really ran checks for all annotated
352
+ // nodes.
353
+ pub struct FindAllAttrs < ' a , ' tcx : ' a > {
354
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
355
+ attr_names : Vec < & ' static str > ,
356
+ found_attrs : Vec < & ' tcx Attribute > ,
357
+ }
358
+
359
+ impl < ' a , ' tcx > FindAllAttrs < ' a , ' tcx > {
360
+
361
+ fn is_active_attr ( & mut self , attr : & Attribute ) -> bool {
362
+ for attr_name in & self . attr_names {
363
+ if attr. check_name ( attr_name) && check_config ( self . tcx , attr) {
364
+ return true ;
365
+ }
366
+ }
367
+
368
+ false
369
+ }
370
+
371
+ fn report_unchecked_attrs ( & self , checked_attrs : & FxHashSet < ast:: AttrId > ) {
372
+ for attr in & self . found_attrs {
373
+ if !checked_attrs. contains ( & attr. id ) {
374
+ self . tcx . sess . span_err ( attr. span , & format ! ( "found unchecked \
375
+ #[rustc_dirty]/#[rustc_clean] attribute") ) ;
376
+ }
377
+ }
378
+ }
379
+ }
380
+
381
+ impl < ' a , ' tcx > intravisit:: Visitor < ' tcx > for FindAllAttrs < ' a , ' tcx > {
382
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> intravisit:: NestedVisitorMap < ' this , ' tcx > {
383
+ intravisit:: NestedVisitorMap :: All ( & self . tcx . hir )
384
+ }
385
+
386
+ fn visit_attribute ( & mut self , attr : & ' tcx Attribute ) {
387
+ if self . is_active_attr ( attr) {
388
+ self . found_attrs . push ( attr) ;
389
+ }
390
+ }
391
+ }
0 commit comments