1
1
use rustc_ast:: attr:: AttributeExt ;
2
2
use rustc_ast_pretty:: pprust;
3
- use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
3
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
4
+ use rustc_data_structures:: unord:: UnordSet ;
4
5
use rustc_errors:: { Diag , LintDiagnostic , MultiSpan } ;
5
6
use rustc_feature:: { Features , GateIssue } ;
7
+ use rustc_hir:: HirId ;
6
8
use rustc_hir:: intravisit:: { self , Visitor } ;
7
- use rustc_hir:: { CRATE_HIR_ID , HirId } ;
8
9
use rustc_index:: IndexVec ;
9
10
use rustc_middle:: bug;
10
11
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) ]
@@ -340,82 +343,6 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
340
343
}
341
344
}
342
345
343
- /// Visitor with the only function of visiting every item-like in a crate and
344
- /// computing the highest level that every lint gets put to.
345
- ///
346
- /// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
347
- /// uses #[warn(lint)], this visitor will set that lint level as `Warn`
348
- struct LintLevelMaximum < ' tcx > {
349
- tcx : TyCtxt < ' tcx > ,
350
- /// The actual list of detected lints.
351
- dont_need_to_run : FxIndexSet < LintId > ,
352
- }
353
-
354
- impl < ' tcx > LintLevelMaximum < ' tcx > {
355
- fn process_opts ( & mut self ) {
356
- let store = unerased_lint_store ( self . tcx . sess ) ;
357
- for ( lint_group, level) in & self . tcx . sess . opts . lint_opts {
358
- if * level != Level :: Allow {
359
- let Ok ( lints) = store. find_lints ( lint_group) else {
360
- return ;
361
- } ;
362
- for lint in lints {
363
- self . dont_need_to_run . swap_remove ( & lint) ;
364
- }
365
- }
366
- }
367
- }
368
- }
369
-
370
- impl < ' tcx > Visitor < ' tcx > for LintLevelMaximum < ' tcx > {
371
- type NestedFilter = nested_filter:: All ;
372
-
373
- fn maybe_tcx ( & mut self ) -> Self :: MaybeTyCtxt {
374
- self . tcx
375
- }
376
-
377
- /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
378
- /// but that is handled with more care
379
- fn visit_attribute ( & mut self , attribute : & ' tcx hir:: Attribute ) {
380
- if matches ! (
381
- Level :: from_attr( attribute) ,
382
- Some (
383
- Level :: Warn
384
- | Level :: Deny
385
- | Level :: Forbid
386
- | Level :: Expect ( ..)
387
- | Level :: ForceWarn ( ..) ,
388
- )
389
- ) {
390
- let store = unerased_lint_store ( self . tcx . sess ) ;
391
- // Lint attributes are always a metalist inside a
392
- // metalist (even with just one lint).
393
- let Some ( meta_item_list) = attribute. meta_item_list ( ) else { return } ;
394
-
395
- for meta_list in meta_item_list {
396
- // Convert Path to String
397
- let Some ( meta_item) = meta_list. meta_item ( ) else { return } ;
398
- let ident: & str = & meta_item
399
- . path
400
- . segments
401
- . iter ( )
402
- . map ( |segment| segment. ident . as_str ( ) )
403
- . collect :: < Vec < & str > > ( )
404
- . join ( "::" ) ;
405
- let Ok ( lints) = store. find_lints (
406
- // Lint attributes can only have literals
407
- ident,
408
- ) else {
409
- return ;
410
- } ;
411
- for lint in lints {
412
- self . dont_need_to_run . swap_remove ( & lint) ;
413
- }
414
- }
415
- }
416
- }
417
- }
418
-
419
346
pub struct LintLevelsBuilder < ' s , P > {
420
347
sess : & ' s Session ,
421
348
features : & ' s Features ,
0 commit comments