@@ -56,15 +56,27 @@ impl LintLevelSource {
5656/// A tuple of a lint level and its source.
5757pub type LevelAndSource = ( Level , LintLevelSource ) ;
5858
59+ /// Return type for the `shallow_lint_levels_on` query.
60+ ///
61+ /// This map represents the set of allowed lints and allowance levels given
62+ /// by the attributes for *a single HirId*.
63+ #[ derive( Default , Debug , HashStable ) ]
64+ pub struct ShallowLintLevelMap {
65+ pub specs : FxHashMap < LintId , LevelAndSource > ,
66+ }
67+
68+ /// From an initial level and source, verify the effect of special annotations:
69+ /// `warnings` lint level and lint caps.
70+ ///
71+ /// The return of this function is suitable for diagnostics.
5972pub fn reveal_actual_level (
6073 level : Option < Level > ,
6174 src : & mut LintLevelSource ,
6275 sess : & Session ,
6376 lint : LintId ,
64- get_lint_id_level : impl FnOnce ( LintId ) -> ( Option < Level > , LintLevelSource ) ,
77+ probe_for_lint_level : impl FnOnce ( LintId ) -> ( Option < Level > , LintLevelSource ) ,
6578) -> Level {
66- // If `level` is none then we actually assume the default level for this
67- // lint.
79+ // If `level` is none then we actually assume the default level for this lint.
6880 let mut level = level. unwrap_or_else ( || lint. lint . default_level ( sess. edition ( ) ) ) ;
6981
7082 // If we're about to issue a warning, check at the last minute for any
@@ -76,7 +88,7 @@ pub fn reveal_actual_level(
7688 // and so if we turned that into an error, it'd defeat the purpose of the
7789 // future compatibility warning.
7890 if level == Level :: Warn && lint != LintId :: of ( FORBIDDEN_LINT_GROUPS ) {
79- let ( warnings_level, warnings_src) = get_lint_id_level ( LintId :: of ( builtin:: WARNINGS ) ) ;
91+ let ( warnings_level, warnings_src) = probe_for_lint_level ( LintId :: of ( builtin:: WARNINGS ) ) ;
8092 if let Some ( configured_warning_level) = warnings_level {
8193 if configured_warning_level != Level :: Warn {
8294 level = configured_warning_level;
@@ -85,8 +97,7 @@ pub fn reveal_actual_level(
8597 }
8698 }
8799
88- // Ensure that we never exceed the `--cap-lints` argument
89- // unless the source is a --force-warn
100+ // Ensure that we never exceed the `--cap-lints` argument unless the source is a --force-warn
90101 level = if let LintLevelSource :: CommandLine ( _, Level :: ForceWarn ( _) ) = src {
91102 level
92103 } else {
@@ -101,59 +112,76 @@ pub fn reveal_actual_level(
101112 level
102113}
103114
104- pub struct LintLevelQueryMap < ' tcx > {
105- pub tcx : TyCtxt < ' tcx > ,
106- pub cur : HirId ,
107- pub specs : FxHashMap < LintId , LevelAndSource > ,
108- }
109-
110- impl < ' tcx > LintLevelQueryMap < ' tcx > {
111- pub fn lint_id_level ( & self , id : LintId ) -> ( Option < Level > , LintLevelSource ) {
112- Self :: get_lint_id_level ( id, self . cur , self . tcx , & self . specs )
113- }
114-
115- pub fn lint_level ( & self , lint : & ' static Lint ) -> LevelAndSource {
116- Self :: get_lint_level ( LintId :: of ( lint) , self . cur , self . tcx , & self . specs )
117- }
118-
119- pub fn get_lint_id_level (
115+ impl ShallowLintLevelMap {
116+ /// Perform a deep probe in the HIR tree looking for the actual level for the lint.
117+ /// This lint level is not usable for diagnostics, it needs to be corrected by
118+ /// `reveal_actual_level` beforehand.
119+ fn probe_for_lint_level (
120+ & self ,
121+ tcx : TyCtxt < ' _ > ,
120122 id : LintId ,
121- cur : HirId ,
122- tcx : TyCtxt < ' tcx > ,
123- specs : & FxHashMap < LintId , LevelAndSource > ,
123+ start : HirId ,
124124 ) -> ( Option < Level > , LintLevelSource ) {
125- if let Some ( & ( level, src) ) = specs. get ( & id) {
125+ if let Some ( & ( level, src) ) = self . specs . get ( & id) {
126126 return ( Some ( level) , src) ;
127127 }
128- let mut cur = cur ;
128+ let mut cur = start ;
129129
130130 loop {
131131 let parent = tcx. hir ( ) . get_parent_node ( cur) ;
132132 if cur == parent {
133133 return ( None , LintLevelSource :: Default ) ;
134134 }
135- let specs = tcx. lint_levels_on ( parent) ;
136- if let Some ( & ( level, src) ) = specs. get ( & id) {
135+ let specs = tcx. shallow_lint_levels_on ( parent) ;
136+ if let Some ( & ( level, src) ) = specs. specs . get ( & id) {
137137 return ( Some ( level) , src) ;
138138 }
139139 cur = parent
140140 }
141141 }
142142
143- pub fn get_lint_level (
144- id : LintId ,
143+ /// Fetch and return the user-visible lint level for the given lint at the given HirId.
144+ pub fn lint_level_id_at_node (
145+ & self ,
146+ tcx : TyCtxt < ' _ > ,
147+ lint : LintId ,
145148 cur : HirId ,
146- tcx : TyCtxt < ' tcx > ,
147- specs : & FxHashMap < LintId , LevelAndSource > ,
148149 ) -> ( Level , LintLevelSource ) {
149- let ( level, mut src) = Self :: get_lint_id_level ( id , cur , tcx , specs ) ;
150- let level = reveal_actual_level ( level, & mut src, tcx. sess , id , |id | {
151- Self :: get_lint_id_level ( id , cur , tcx , specs )
150+ let ( level, mut src) = self . probe_for_lint_level ( tcx , lint , cur ) ;
151+ let level = reveal_actual_level ( level, & mut src, tcx. sess , lint , |lint | {
152+ self . probe_for_lint_level ( tcx , lint , cur )
152153 } ) ;
153154 ( level, src)
154155 }
155156}
156157
158+ impl TyCtxt < ' _ > {
159+ /// Fetch and return the user-visible lint level for the given lint at the given HirId.
160+ pub fn lint_level_at_node ( self , lint : & ' static Lint , id : HirId ) -> ( Level , LintLevelSource ) {
161+ self . shallow_lint_levels_on ( id) . lint_level_id_at_node ( self , LintId :: of ( lint) , id)
162+ }
163+
164+ /// Walks upwards from `id` to find a node which might change lint levels with attributes.
165+ /// It stops at `bound` and just returns it if reached.
166+ pub fn maybe_lint_level_root_bounded ( self , mut id : HirId , bound : HirId ) -> HirId {
167+ let hir = self . hir ( ) ;
168+ loop {
169+ if id == bound {
170+ return bound;
171+ }
172+
173+ if hir. attrs ( id) . iter ( ) . any ( |attr| Level :: from_attr ( attr) . is_some ( ) ) {
174+ return id;
175+ }
176+ let next = hir. get_parent_node ( id) ;
177+ if next == id {
178+ bug ! ( "lint traversal reached the root of the crate" ) ;
179+ }
180+ id = next;
181+ }
182+ }
183+ }
184+
157185/// This struct represents a lint expectation and holds all required information
158186/// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
159187/// the `LateLintPass` has completed.
0 commit comments