1
1
use rustc_ast_pretty:: pprust;
2
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
2
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
3
+ use rustc_data_structures:: unord:: UnordSet ;
3
4
use rustc_errors:: { Diag , LintDiagnostic , MultiSpan } ;
4
5
use rustc_feature:: { Features , GateIssue } ;
6
+ use rustc_hir:: HirId ;
5
7
use rustc_hir:: intravisit:: { self , Visitor } ;
6
- use rustc_hir:: { CRATE_HIR_ID , HirId } ;
7
8
use rustc_index:: IndexVec ;
8
9
use rustc_middle:: bug;
9
10
use rustc_middle:: hir:: nested_filter;
@@ -115,12 +116,10 @@ impl LintLevelSets {
115
116
}
116
117
}
117
118
118
- fn lints_that_dont_need_to_run ( tcx : TyCtxt < ' _ > , ( ) : ( ) ) -> FxIndexSet < LintId > {
119
+ fn lints_that_dont_need_to_run ( tcx : TyCtxt < ' _ > , ( ) : ( ) ) -> UnordSet < LintId > {
119
120
let store = unerased_lint_store ( & tcx. sess ) ;
120
121
121
- let map = tcx. shallow_lint_levels_on ( rustc_hir:: CRATE_OWNER_ID ) ;
122
-
123
- let dont_need_to_run: FxIndexSet < LintId > = store
122
+ let mut dont_need_to_run: FxHashSet < LintId > = store
124
123
. get_lints ( )
125
124
. into_iter ( )
126
125
. filter ( |lint| {
@@ -129,24 +128,28 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LintId> {
129
128
lint. future_incompatible . is_some_and ( |fut| fut. reason . has_future_breakage ( ) ) ;
130
129
!has_future_breakage && !lint. eval_always
131
130
} )
132
- . filter_map ( |lint| {
133
- let lint_level = map. lint_level_id_at_node ( tcx, LintId :: of ( lint) , CRATE_HIR_ID ) ;
134
- if matches ! ( lint_level, ( Level :: Allow , ..) )
135
- || ( matches ! ( lint_level, ( .., LintLevelSource :: Default ) ) )
136
- && lint. default_level ( tcx. sess . edition ( ) ) == Level :: Allow
137
- {
138
- Some ( LintId :: of ( lint) )
139
- } else {
140
- None
141
- }
142
- } )
131
+ . map ( |lint| LintId :: of ( * lint) )
143
132
. collect ( ) ;
144
133
145
- let mut visitor = LintLevelMaximum { tcx, dont_need_to_run } ;
146
- visitor. process_opts ( ) ;
147
- tcx. hir ( ) . walk_attributes ( & mut visitor) ;
134
+ let mut remove_non_allow_lints_from_owner = |owner| {
135
+ let map = tcx. shallow_lint_levels_on ( owner) ;
148
136
149
- visitor. dont_need_to_run
137
+ // All lints that appear with a non-allow level must be run.
138
+ for ( _, specs) in map. specs . iter ( ) {
139
+ for ( lint, ( level, _) ) in specs. iter ( ) {
140
+ if !matches ! ( level, Level :: Allow ) {
141
+ dont_need_to_run. remove ( lint) ;
142
+ }
143
+ }
144
+ }
145
+ } ;
146
+
147
+ remove_non_allow_lints_from_owner ( rustc_hir:: CRATE_OWNER_ID ) ;
148
+ for owner in tcx. hir_crate_items ( ( ) ) . owners ( ) {
149
+ remove_non_allow_lints_from_owner ( owner) ;
150
+ }
151
+
152
+ dont_need_to_run. into ( )
150
153
}
151
154
152
155
#[ instrument( level = "trace" , skip( tcx) , ret) ]
@@ -335,83 +338,6 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
335
338
}
336
339
}
337
340
338
- /// Visitor with the only function of visiting every item-like in a crate and
339
- /// computing the highest level that every lint gets put to.
340
- ///
341
- /// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
342
- /// uses #[warn(lint)], this visitor will set that lint level as `Warn`
343
- struct LintLevelMaximum < ' tcx > {
344
- tcx : TyCtxt < ' tcx > ,
345
- /// The actual list of detected lints.
346
- dont_need_to_run : FxIndexSet < LintId > ,
347
- }
348
-
349
- impl < ' tcx > LintLevelMaximum < ' tcx > {
350
- fn process_opts ( & mut self ) {
351
- let store = unerased_lint_store ( self . tcx . sess ) ;
352
- for ( lint_group, level) in & self . tcx . sess . opts . lint_opts {
353
- if * level != Level :: Allow {
354
- let Ok ( lints) = store. find_lints ( lint_group) else {
355
- return ;
356
- } ;
357
- for lint in lints {
358
- self . dont_need_to_run . swap_remove ( & lint) ;
359
- }
360
- }
361
- }
362
- }
363
- }
364
-
365
- impl < ' tcx > Visitor < ' tcx > for LintLevelMaximum < ' tcx > {
366
- type NestedFilter = nested_filter:: All ;
367
-
368
- fn nested_visit_map ( & mut self ) -> Self :: Map {
369
- self . tcx . hir ( )
370
- }
371
-
372
- /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
373
- /// but that is handled with more care
374
- fn visit_attribute ( & mut self , attribute : & ' tcx ast:: Attribute ) {
375
- if matches ! (
376
- Level :: from_attr( attribute) ,
377
- Some (
378
- Level :: Warn
379
- | Level :: Deny
380
- | Level :: Forbid
381
- | Level :: Expect ( ..)
382
- | Level :: ForceWarn ( ..) ,
383
- )
384
- ) {
385
- let store = unerased_lint_store ( self . tcx . sess ) ;
386
- let Some ( meta) = attribute. meta ( ) else { return } ;
387
- // Lint attributes are always a metalist inside a
388
- // metalist (even with just one lint).
389
- let Some ( meta_item_list) = meta. meta_item_list ( ) else { return } ;
390
-
391
- for meta_list in meta_item_list {
392
- // Convert Path to String
393
- let Some ( meta_item) = meta_list. meta_item ( ) else { return } ;
394
- let ident: & str = & meta_item
395
- . path
396
- . segments
397
- . iter ( )
398
- . map ( |segment| segment. ident . as_str ( ) )
399
- . collect :: < Vec < & str > > ( )
400
- . join ( "::" ) ;
401
- let Ok ( lints) = store. find_lints (
402
- // Lint attributes can only have literals
403
- ident,
404
- ) else {
405
- return ;
406
- } ;
407
- for lint in lints {
408
- self . dont_need_to_run . swap_remove ( & lint) ;
409
- }
410
- }
411
- }
412
- }
413
- }
414
-
415
341
pub struct LintLevelsBuilder < ' s , P > {
416
342
sess : & ' s Session ,
417
343
features : & ' s Features ,
0 commit comments