@@ -5,7 +5,8 @@ use rustc_ast_pretty::pprust;
55use rustc_data_structures:: fx:: FxHashMap ;
66use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , DiagnosticMessage , MultiSpan } ;
77use rustc_hir as hir;
8- use rustc_hir:: { intravisit, HirId } ;
8+ use rustc_hir:: intravisit:: { self , Visitor } ;
9+ use rustc_hir:: HirId ;
910use rustc_index:: vec:: IndexVec ;
1011use rustc_middle:: hir:: nested_filter;
1112use rustc_middle:: lint:: {
@@ -115,6 +116,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
115116 specs : ShallowLintLevelMap :: default ( ) ,
116117 expectations : Vec :: new ( ) ,
117118 unstable_to_stable_ids : FxHashMap :: default ( ) ,
119+ empty : FxHashMap :: default ( ) ,
118120 } ,
119121 warn_about_weird_lints : false ,
120122 store,
@@ -130,25 +132,39 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
130132 builder. provider . expectations
131133}
132134
133- fn shallow_lint_levels_on ( tcx : TyCtxt < ' _ > , hir_id : HirId ) -> ShallowLintLevelMap {
135+ #[ instrument( level = "trace" , skip( tcx) , ret) ]
136+ fn shallow_lint_levels_on ( tcx : TyCtxt < ' _ > , owner : hir:: OwnerId ) -> ShallowLintLevelMap {
134137 let store = unerased_lint_store ( tcx) ;
135138
136139 let mut levels = LintLevelsBuilder {
137140 sess : tcx. sess ,
138- provider : LintLevelQueryMap { tcx, cur : hir_id, specs : ShallowLintLevelMap :: default ( ) } ,
141+ provider : LintLevelQueryMap {
142+ tcx,
143+ cur : owner. into ( ) ,
144+ specs : ShallowLintLevelMap :: default ( ) ,
145+ empty : FxHashMap :: default ( ) ,
146+ } ,
139147 warn_about_weird_lints : false ,
140148 store,
141149 registered_tools : & tcx. resolutions ( ( ) ) . registered_tools ,
142150 } ;
143151
144- let is_crate = hir:: CRATE_HIR_ID == hir_id;
145- if is_crate {
146- levels. add_command_line ( ) ;
147- }
148- debug ! ( ?hir_id) ;
149- levels. add ( tcx. hir ( ) . attrs ( hir_id) , is_crate, Some ( hir_id) ) ;
152+ match tcx. hir ( ) . expect_owner ( owner) {
153+ hir:: OwnerNode :: Item ( item) => levels. visit_item ( item) ,
154+ hir:: OwnerNode :: ForeignItem ( item) => levels. visit_foreign_item ( item) ,
155+ hir:: OwnerNode :: TraitItem ( item) => levels. visit_trait_item ( item) ,
156+ hir:: OwnerNode :: ImplItem ( item) => levels. visit_impl_item ( item) ,
157+ hir:: OwnerNode :: Crate ( mod_) => {
158+ levels. add_command_line ( ) ;
159+ levels. add_id ( hir:: CRATE_HIR_ID ) ;
160+ levels. visit_mod ( mod_, mod_. spans . inner_span , hir:: CRATE_HIR_ID )
161+ }
162+ } ;
163+
164+ let mut specs = levels. provider . specs ;
165+ specs. specs . retain ( |( _, v) | !v. is_empty ( ) ) ;
150166
151- levels . provider . specs
167+ specs
152168}
153169
154170pub struct TopDown {
@@ -181,14 +197,16 @@ struct LintLevelQueryMap<'tcx> {
181197 tcx : TyCtxt < ' tcx > ,
182198 cur : HirId ,
183199 specs : ShallowLintLevelMap ,
200+ /// Empty hash map to simplify code.
201+ empty : FxHashMap < LintId , LevelAndSource > ,
184202}
185203
186204impl LintLevelsProvider for LintLevelQueryMap < ' _ > {
187205 fn current_specs ( & self ) -> & FxHashMap < LintId , LevelAndSource > {
188- & self . specs . specs
206+ self . specs . specs . get ( & self . cur . local_id ) . unwrap_or ( & self . empty )
189207 }
190208 fn current_specs_mut ( & mut self ) -> & mut FxHashMap < LintId , LevelAndSource > {
191- & mut self . specs . specs
209+ self . specs . specs . get_mut_or_insert_default ( self . cur . local_id )
192210 }
193211 fn get_lint_level ( & self , lint : & ' static Lint , _: & Session ) -> LevelAndSource {
194212 self . specs . lint_level_id_at_node ( self . tcx , LintId :: of ( lint) , self . cur )
@@ -201,15 +219,18 @@ struct QueryMapExpectationsWrapper<'tcx> {
201219 specs : ShallowLintLevelMap ,
202220 expectations : Vec < ( LintExpectationId , LintExpectation ) > ,
203221 unstable_to_stable_ids : FxHashMap < LintExpectationId , LintExpectationId > ,
222+ /// Empty hash map to simplify code.
223+ empty : FxHashMap < LintId , LevelAndSource > ,
204224}
205225
206226impl LintLevelsProvider for QueryMapExpectationsWrapper < ' _ > {
207227 fn current_specs ( & self ) -> & FxHashMap < LintId , LevelAndSource > {
208- & self . specs . specs
228+ self . specs . specs . get ( & self . cur . local_id ) . unwrap_or ( & self . empty )
209229 }
210230 fn current_specs_mut ( & mut self ) -> & mut FxHashMap < LintId , LevelAndSource > {
211- self . specs . specs . clear ( ) ;
212- & mut self . specs . specs
231+ let specs = self . specs . specs . get_mut_or_insert_default ( self . cur . local_id ) ;
232+ specs. clear ( ) ;
233+ specs
213234 }
214235 fn get_lint_level ( & self , lint : & ' static Lint , _: & Session ) -> LevelAndSource {
215236 self . specs . lint_level_id_at_node ( self . tcx , LintId :: of ( lint) , self . cur )
@@ -229,13 +250,86 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
229250 }
230251}
231252
253+ impl < ' tcx > LintLevelsBuilder < ' _ , LintLevelQueryMap < ' tcx > > {
254+ fn add_id ( & mut self , hir_id : HirId ) {
255+ self . provider . cur = hir_id;
256+ self . add ( self . provider . tcx . hir ( ) . attrs ( hir_id) , hir_id == hir:: CRATE_HIR_ID , Some ( hir_id) ) ;
257+ }
258+ }
259+
260+ impl < ' tcx > Visitor < ' tcx > for LintLevelsBuilder < ' _ , LintLevelQueryMap < ' tcx > > {
261+ type NestedFilter = nested_filter:: OnlyBodies ;
262+
263+ fn nested_visit_map ( & mut self ) -> Self :: Map {
264+ self . provider . tcx . hir ( )
265+ }
266+
267+ fn visit_param ( & mut self , param : & ' tcx hir:: Param < ' tcx > ) {
268+ self . add_id ( param. hir_id ) ;
269+ intravisit:: walk_param ( self , param) ;
270+ }
271+
272+ fn visit_item ( & mut self , it : & ' tcx hir:: Item < ' tcx > ) {
273+ self . add_id ( it. hir_id ( ) ) ;
274+ intravisit:: walk_item ( self , it) ;
275+ }
276+
277+ fn visit_foreign_item ( & mut self , it : & ' tcx hir:: ForeignItem < ' tcx > ) {
278+ self . add_id ( it. hir_id ( ) ) ;
279+ intravisit:: walk_foreign_item ( self , it) ;
280+ }
281+
282+ fn visit_stmt ( & mut self , e : & ' tcx hir:: Stmt < ' tcx > ) {
283+ // We will call `add_id` when we walk
284+ // the `StmtKind`. The outer statement itself doesn't
285+ // define the lint levels.
286+ intravisit:: walk_stmt ( self , e) ;
287+ }
288+
289+ fn visit_expr ( & mut self , e : & ' tcx hir:: Expr < ' tcx > ) {
290+ self . add_id ( e. hir_id ) ;
291+ intravisit:: walk_expr ( self , e) ;
292+ }
293+
294+ fn visit_field_def ( & mut self , s : & ' tcx hir:: FieldDef < ' tcx > ) {
295+ self . add_id ( s. hir_id ) ;
296+ intravisit:: walk_field_def ( self , s) ;
297+ }
298+
299+ fn visit_variant ( & mut self , v : & ' tcx hir:: Variant < ' tcx > ) {
300+ self . add_id ( v. id ) ;
301+ intravisit:: walk_variant ( self , v) ;
302+ }
303+
304+ fn visit_local ( & mut self , l : & ' tcx hir:: Local < ' tcx > ) {
305+ self . add_id ( l. hir_id ) ;
306+ intravisit:: walk_local ( self , l) ;
307+ }
308+
309+ fn visit_arm ( & mut self , a : & ' tcx hir:: Arm < ' tcx > ) {
310+ self . add_id ( a. hir_id ) ;
311+ intravisit:: walk_arm ( self , a) ;
312+ }
313+
314+ fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
315+ self . add_id ( trait_item. hir_id ( ) ) ;
316+ intravisit:: walk_trait_item ( self , trait_item) ;
317+ }
318+
319+ fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
320+ self . add_id ( impl_item. hir_id ( ) ) ;
321+ intravisit:: walk_impl_item ( self , impl_item) ;
322+ }
323+ }
324+
232325impl < ' tcx > LintLevelsBuilder < ' _ , QueryMapExpectationsWrapper < ' tcx > > {
233326 fn add_id ( & mut self , hir_id : HirId ) {
327+ self . provider . cur = hir_id;
234328 self . add ( self . provider . tcx . hir ( ) . attrs ( hir_id) , hir_id == hir:: CRATE_HIR_ID , Some ( hir_id) ) ;
235329 }
236330}
237331
238- impl < ' tcx > intravisit :: Visitor < ' tcx > for LintLevelsBuilder < ' _ , QueryMapExpectationsWrapper < ' tcx > > {
332+ impl < ' tcx > Visitor < ' tcx > for LintLevelsBuilder < ' _ , QueryMapExpectationsWrapper < ' tcx > > {
239333 type NestedFilter = nested_filter:: All ;
240334
241335 fn nested_visit_map ( & mut self ) -> Self :: Map {
0 commit comments