]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_lint/src/levels.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_lint / src / levels.rs
CommitLineData
dfeec247
XL
1use crate::context::{CheckLintNameResult, LintStore};
2use crate::late::unerased_lint_store;
3dfed10e 3use rustc_ast as ast;
74b04a01 4use rustc_ast_pretty::pprust;
dfeec247 5use rustc_data_structures::fx::FxHashMap;
fc512014 6use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
dfeec247 7use rustc_hir as hir;
5099ac24
FG
8use rustc_hir::{intravisit, HirId};
9use rustc_middle::hir::nested_filter;
5869c6ff 10use rustc_middle::lint::LevelAndSource;
ba9703b0 11use rustc_middle::lint::LintDiagnosticBuilder;
fc512014 12use rustc_middle::lint::{
136023e0
XL
13 struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet, LintStackIndex,
14 COMMAND_LINE,
fc512014 15};
ba9703b0 16use rustc_middle::ty::query::Providers;
5099ac24 17use rustc_middle::ty::{RegisteredTools, TyCtxt};
fc512014
XL
18use rustc_session::lint::{
19 builtin::{self, FORBIDDEN_LINT_GROUPS},
20 Level, Lint, LintId,
21};
74b04a01 22use rustc_session::parse::feature_err;
dfeec247 23use rustc_session::Session;
74b04a01 24use rustc_span::symbol::{sym, Symbol};
f9f354fc 25use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
fc512014 26use tracing::debug;
dfeec247 27
17df50a5 28fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
dfeec247 29 let store = unerased_lint_store(tcx);
5099ac24
FG
30 let levels =
31 LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools);
32 let mut builder = LintLevelMapBuilder { levels, tcx };
dfeec247
XL
33 let krate = tcx.hir().krate();
34
94222f64 35 builder.levels.id_to_set.reserve(krate.owners.len() + 1);
fc512014 36
5099ac24 37 let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true);
dfeec247 38 builder.levels.register_id(hir::CRATE_HIR_ID);
c295e0f8 39 tcx.hir().walk_toplevel_module(&mut builder);
dfeec247 40 builder.levels.pop(push);
60c5eb7d 41
f9f354fc 42 builder.levels.build_map()
3b2f2976
XL
43}
44
74b04a01
XL
45pub struct LintLevelsBuilder<'s> {
46 sess: &'s Session,
dfeec247 47 sets: LintLevelSets,
136023e0
XL
48 id_to_set: FxHashMap<HirId, LintStackIndex>,
49 cur: LintStackIndex,
dfeec247 50 warn_about_weird_lints: bool,
fc512014 51 store: &'s LintStore,
5099ac24 52 registered_tools: &'s RegisteredTools,
3b2f2976
XL
53}
54
dfeec247 55pub struct BuilderPush {
136023e0 56 prev: LintStackIndex,
dfeec247
XL
57 pub changed: bool,
58}
3b2f2976 59
74b04a01 60impl<'s> LintLevelsBuilder<'s> {
6a06907d
XL
61 pub fn new(
62 sess: &'s Session,
63 warn_about_weird_lints: bool,
64 store: &'s LintStore,
5099ac24 65 registered_tools: &'s RegisteredTools,
6a06907d 66 ) -> Self {
dfeec247
XL
67 let mut builder = LintLevelsBuilder {
68 sess,
69 sets: LintLevelSets::new(),
136023e0 70 cur: COMMAND_LINE,
dfeec247
XL
71 id_to_set: Default::default(),
72 warn_about_weird_lints,
fc512014 73 store,
5099ac24 74 registered_tools,
dfeec247
XL
75 };
76 builder.process_command_line(sess, store);
77 assert_eq!(builder.sets.list.len(), 1);
78 builder
3b2f2976
XL
79 }
80
5099ac24
FG
81 pub(crate) fn sess(&self) -> &Session {
82 self.sess
83 }
84
85 pub(crate) fn lint_store(&self) -> &LintStore {
86 self.store
87 }
88
e74abb32 89 fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
0bf4aa26 90 let mut specs = FxHashMap::default();
dfeec247 91 self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
3b2f2976
XL
92
93 for &(ref lint_name, level) in &sess.opts.lint_opts {
5099ac24 94 store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
29967ef6 95 let orig_level = level;
3b2f2976 96 let lint_flag_val = Symbol::intern(lint_name);
f9f354fc 97
3b2f2976
XL
98 let ids = match store.find_lints(&lint_name) {
99 Ok(ids) => ids,
100 Err(_) => continue, // errors handled in check_lint_name_cmdline above
101 };
102 for id in ids {
136023e0
XL
103 // ForceWarn and Forbid cannot be overriden
104 if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
105 continue;
106 }
107
f9f354fc 108 self.check_gated_lint(id, DUMMY_SP);
fc512014 109 let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
3b2f2976
XL
110 specs.insert(id, (level, src));
111 }
112 }
113
136023e0 114 self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
3b2f2976
XL
115 }
116
fc512014
XL
117 /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
118 /// (e.g. if a forbid was already inserted on the same scope), then emits a
119 /// diagnostic with no change to `specs`.
120 fn insert_spec(
121 &mut self,
5869c6ff 122 specs: &mut FxHashMap<LintId, LevelAndSource>,
fc512014 123 id: LintId,
5869c6ff 124 (level, src): LevelAndSource,
fc512014 125 ) {
136023e0
XL
126 let (old_level, old_src) =
127 self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
fc512014
XL
128 // Setting to a non-forbid level is an error if the lint previously had
129 // a forbid level. Note that this is not necessarily true even with a
130 // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
131 //
132 // This means that this only errors if we're truly lowering the lint
133 // level from forbid.
134 if level != Level::Forbid {
136023e0 135 if let Level::Forbid = old_level {
fc512014
XL
136 // Backwards compatibility check:
137 //
138 // We used to not consider `forbid(lint_group)`
139 // as preventing `allow(lint)` for some lint `lint` in
140 // `lint_group`. For now, issue a future-compatibility
141 // warning for this case.
142 let id_name = id.lint.name_lower();
143 let fcw_warning = match old_src {
144 LintLevelSource::Default => false,
145 LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
146 LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
147 };
148 debug!(
149 "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
150 fcw_warning, specs, old_src, id_name
151 );
152
153 let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| {
154 diag_builder.span_label(src.span(), "overruled by previous forbid");
155 match old_src {
156 LintLevelSource::Default => {
157 diag_builder.note(&format!(
158 "`forbid` lint level is the default for {}",
159 id.to_string()
160 ));
161 }
162 LintLevelSource::Node(_, forbid_source_span, reason) => {
163 diag_builder.span_label(forbid_source_span, "`forbid` level set here");
164 if let Some(rationale) = reason {
a2a8927a 165 diag_builder.note(rationale.as_str());
fc512014
XL
166 }
167 }
168 LintLevelSource::CommandLine(_, _) => {
169 diag_builder.note("`forbid` lint level was set on command line");
170 }
171 }
172 diag_builder.emit();
173 };
174 if !fcw_warning {
175 let diag_builder = struct_span_err!(
176 self.sess,
177 src.span(),
178 E0453,
179 "{}({}) incompatible with previous forbid",
180 level.as_str(),
181 src.name(),
182 );
183 decorate_diag_builder(diag_builder);
184 } else {
185 self.struct_lint(
186 FORBIDDEN_LINT_GROUPS,
187 Some(src.span().into()),
188 |diag_builder| {
189 let diag_builder = diag_builder.build(&format!(
190 "{}({}) incompatible with previous forbid",
191 level.as_str(),
192 src.name(),
193 ));
194 decorate_diag_builder(diag_builder);
195 },
196 );
197 }
198
199 // Retain the forbid lint level, unless we are
200 // issuing a FCW. In the FCW case, we want to
201 // respect the new setting.
202 if !fcw_warning {
203 return;
204 }
205 }
206 }
136023e0
XL
207 if let Level::ForceWarn = old_level {
208 specs.insert(id, (old_level, old_src));
209 } else {
210 specs.insert(id, (level, src));
211 }
fc512014
XL
212 }
213
3b2f2976
XL
214 /// Pushes a list of AST lint attributes onto this context.
215 ///
0731742a
XL
216 /// This function will return a `BuilderPush` object which should be passed
217 /// to `pop` when this scope for the attributes provided is exited.
3b2f2976
XL
218 ///
219 /// This function will perform a number of tasks:
220 ///
221 /// * It'll validate all lint-related attributes in `attrs`
a1dfa0c6 222 /// * It'll mark all lint-related attributes as used
3b2f2976 223 /// * Lint levels will be updated based on the attributes provided
f9f354fc
XL
224 /// * Lint attributes are validated, e.g., a `#[forbid]` can't be switched to
225 /// `#[allow]`
3b2f2976
XL
226 ///
227 /// Don't forget to call `pop`!
5099ac24 228 pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
0bf4aa26 229 let mut specs = FxHashMap::default();
3b2f2976 230 let sess = self.sess;
dfeec247 231 let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
3b2f2976 232 for attr in attrs {
a2a8927a
XL
233 let Some(level) = Level::from_symbol(attr.name_or_empty()) else {
234 continue
3b2f2976
XL
235 };
236
a2a8927a
XL
237 let Some(mut metas) = attr.meta_item_list() else {
238 continue
c295e0f8 239 };
3b2f2976 240
a1dfa0c6
XL
241 if metas.is_empty() {
242 // FIXME (#55112): issue unused-attributes lint for `#[level()]`
243 continue;
244 }
245
246 // Before processing the lint names, look for a reason (RFC 2383)
247 // at the end.
248 let mut reason = None;
dfeec247 249 let tail_li = &metas[metas.len() - 1];
a1dfa0c6 250 if let Some(item) = tail_li.meta_item() {
e74abb32 251 match item.kind {
dfeec247 252 ast::MetaItemKind::Word => {} // actual lint names handled later
a1dfa0c6 253 ast::MetaItemKind::NameValue(ref name_value) => {
48663c56 254 if item.path == sym::reason {
a1dfa0c6
XL
255 // FIXME (#55112): issue unused-attributes lint if we thereby
256 // don't have any lint names (`#[level(reason = "foo")]`)
e74abb32 257 if let ast::LitKind::Str(rationale, _) = name_value.kind {
0731742a 258 if !self.sess.features_untracked().lint_reasons {
dfeec247 259 feature_err(
a1dfa0c6 260 &self.sess.parse_sess,
48663c56 261 sym::lint_reasons,
a1dfa0c6 262 item.span,
dfeec247 263 "lint reasons are experimental",
60c5eb7d
XL
264 )
265 .emit();
a1dfa0c6 266 }
0731742a 267 reason = Some(rationale);
a1dfa0c6 268 } else {
dc9dc135
XL
269 bad_attr(name_value.span)
270 .span_label(name_value.span, "reason must be a string literal")
271 .emit();
a1dfa0c6 272 }
cdc7bbd5
XL
273 // found reason, reslice meta list to exclude it
274 metas.pop().unwrap();
a1dfa0c6 275 } else {
dc9dc135
XL
276 bad_attr(item.span)
277 .span_label(item.span, "bad attribute argument")
278 .emit();
a1dfa0c6 279 }
dfeec247 280 }
a1dfa0c6 281 ast::MetaItemKind::List(_) => {
dfeec247 282 bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
a1dfa0c6
XL
283 }
284 }
285 }
286
3b2f2976 287 for li in metas {
cdc7bbd5
XL
288 let sp = li.span();
289 let mut meta_item = match li {
290 ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item,
9fa01778 291 _ => {
dc9dc135
XL
292 let mut err = bad_attr(sp);
293 let mut add_label = true;
a1dfa0c6 294 if let Some(item) = li.meta_item() {
e74abb32 295 if let ast::MetaItemKind::NameValue(_) = item.kind {
48663c56 296 if item.path == sym::reason {
dc9dc135
XL
297 err.span_label(sp, "reason in lint attribute must come last");
298 add_label = false;
a1dfa0c6
XL
299 }
300 }
301 }
dc9dc135
XL
302 if add_label {
303 err.span_label(sp, "bad attribute argument");
304 }
a1dfa0c6
XL
305 err.emit();
306 continue;
3b2f2976
XL
307 }
308 };
136023e0
XL
309 let tool_ident = if meta_item.path.segments.len() > 1 {
310 Some(meta_item.path.segments.remove(0).ident)
b7449926
XL
311 } else {
312 None
313 };
136023e0 314 let tool_name = tool_ident.map(|ident| ident.name);
cdc7bbd5 315 let name = pprust::path_to_string(&meta_item.path);
5099ac24
FG
316 let lint_result =
317 self.store.check_lint_name(&name, tool_name, self.registered_tools);
6a06907d 318 match &lint_result {
3b2f2976 319 CheckLintNameResult::Ok(ids) => {
cdc7bbd5
XL
320 let src = LintLevelSource::Node(
321 meta_item.path.segments.last().expect("empty lint name").ident.name,
322 sp,
323 reason,
324 );
6a06907d 325 for &id in *ids {
f035d41b 326 self.check_gated_lint(id, attr.span);
fc512014 327 self.insert_spec(&mut specs, id, (level, src));
3b2f2976
XL
328 }
329 }
330
b7449926 331 CheckLintNameResult::Tool(result) => {
6a06907d 332 match *result {
b7449926 333 Ok(ids) => {
136023e0
XL
334 let complete_name =
335 &format!("{}::{}", tool_ident.unwrap().name, name);
fc512014 336 let src = LintLevelSource::Node(
dfeec247 337 Symbol::intern(complete_name),
cdc7bbd5 338 sp,
dfeec247 339 reason,
a1dfa0c6 340 );
b7449926 341 for id in ids {
fc512014 342 self.insert_spec(&mut specs, *id, (level, src));
b7449926
XL
343 }
344 }
6a06907d 345 Err((Some(ids), ref new_lint_name)) => {
b7449926
XL
346 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
347 let (lvl, src) =
dfeec247 348 self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
dfeec247 349 struct_lint_level(
b7449926
XL
350 self.sess,
351 lint,
352 lvl,
353 src,
cdc7bbd5 354 Some(sp.into()),
74b04a01
XL
355 |lint| {
356 let msg = format!(
357 "lint name `{}` is deprecated \
5869c6ff 358 and may not have an effect in the future.",
74b04a01
XL
359 name
360 );
361 lint.build(&msg)
362 .span_suggestion(
cdc7bbd5 363 sp,
74b04a01
XL
364 "change it to",
365 new_lint_name.to_string(),
366 Applicability::MachineApplicable,
367 )
368 .emit();
369 },
370 );
b7449926 371
fc512014 372 let src = LintLevelSource::Node(
dfeec247 373 Symbol::intern(&new_lint_name),
cdc7bbd5 374 sp,
dfeec247 375 reason,
a1dfa0c6 376 );
b7449926 377 for id in ids {
fc512014 378 self.insert_spec(&mut specs, *id, (level, src));
b7449926
XL
379 }
380 }
381 Err((None, _)) => {
382 // If Tool(Err(None, _)) is returned, then either the lint does not
383 // exist in the tool or the code was not compiled with the tool and
384 // therefore the lint was never added to the `LintStore`. To detect
385 // this is the responsibility of the lint tool.
386 }
387 }
388 }
389
136023e0
XL
390 &CheckLintNameResult::NoTool => {
391 let mut err = struct_span_err!(
392 sess,
393 tool_ident.map_or(DUMMY_SP, |ident| ident.span),
394 E0710,
395 "unknown tool name `{}` found in scoped lint: `{}::{}`",
396 tool_name.unwrap(),
397 tool_name.unwrap(),
398 pprust::path_to_string(&meta_item.path),
399 );
400 if sess.is_nightly_build() {
401 err.help(&format!(
402 "add `#![register_tool({})]` to the crate root",
403 tool_name.unwrap()
404 ));
405 }
406 err.emit();
407 continue;
408 }
409
3b2f2976
XL
410 _ if !self.warn_about_weird_lints => {}
411
8faf50e0 412 CheckLintNameResult::Warning(msg, renamed) => {
3b2f2976 413 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
6a06907d 414 let (renamed_lint_level, src) =
dfeec247 415 self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
74b04a01 416 struct_lint_level(
dfeec247
XL
417 self.sess,
418 lint,
6a06907d 419 renamed_lint_level,
dfeec247 420 src,
cdc7bbd5 421 Some(sp.into()),
74b04a01
XL
422 |lint| {
423 let mut err = lint.build(&msg);
6a06907d 424 if let Some(new_name) = &renamed {
74b04a01 425 err.span_suggestion(
cdc7bbd5 426 sp,
74b04a01 427 "use the new name",
6a06907d 428 new_name.to_string(),
74b04a01
XL
429 Applicability::MachineApplicable,
430 );
431 }
432 err.emit();
433 },
dfeec247 434 );
3b2f2976 435 }
0731742a 436 CheckLintNameResult::NoLint(suggestion) => {
3b2f2976 437 let lint = builtin::UNKNOWN_LINTS;
dfeec247
XL
438 let (level, src) =
439 self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
cdc7bbd5 440 struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
136023e0
XL
441 let name = if let Some(tool_ident) = tool_ident {
442 format!("{}::{}", tool_ident.name, name)
cdc7bbd5
XL
443 } else {
444 name.to_string()
445 };
446 let mut db = lint.build(&format!("unknown lint: `{}`", name));
447 if let Some(suggestion) = suggestion {
448 db.span_suggestion(
449 sp,
450 "did you mean",
451 suggestion.to_string(),
452 Applicability::MachineApplicable,
453 );
454 }
455 db.emit();
456 });
3b2f2976
XL
457 }
458 }
6a06907d
XL
459 // If this lint was renamed, apply the new lint instead of ignoring the attribute.
460 // This happens outside of the match because the new lint should be applied even if
461 // we don't warn about the name change.
462 if let CheckLintNameResult::Warning(_, Some(new_name)) = lint_result {
463 // Ignore any errors or warnings that happen because the new name is inaccurate
cdc7bbd5 464 // NOTE: `new_name` already includes the tool name, so we don't have to add it again.
136023e0 465 if let CheckLintNameResult::Ok(ids) =
5099ac24 466 self.store.check_lint_name(&new_name, None, self.registered_tools)
136023e0 467 {
cdc7bbd5 468 let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
6a06907d
XL
469 for &id in ids {
470 self.check_gated_lint(id, attr.span);
471 self.insert_spec(&mut specs, id, (level, src));
472 }
cdc7bbd5
XL
473 } else {
474 panic!("renamed lint does not exist: {}", new_name);
6a06907d
XL
475 }
476 }
3b2f2976
XL
477 }
478 }
479
f035d41b
XL
480 if !is_crate_node {
481 for (id, &(level, ref src)) in specs.iter() {
482 if !id.lint.crate_level_only {
483 continue;
484 }
485
a2a8927a
XL
486 let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else {
487 continue
f035d41b
XL
488 };
489
490 let lint = builtin::UNUSED_ATTRIBUTES;
491 let (lint_level, lint_src) =
492 self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
493 struct_lint_level(
494 self.sess,
495 lint,
496 lint_level,
497 lint_src,
498 Some(lint_attr_span.into()),
499 |lint| {
500 let mut db = lint.build(&format!(
501 "{}({}) is ignored unless specified at crate level",
502 level.as_str(),
503 lint_attr_name
504 ));
505 db.emit();
506 },
507 );
508 // don't set a separate error for every lint in the group
509 break;
510 }
511 }
512
3b2f2976 513 let prev = self.cur;
74b04a01 514 if !specs.is_empty() {
136023e0 515 self.cur = self.sets.list.push(LintSet { specs, parent: prev });
3b2f2976
XL
516 }
517
74b04a01 518 BuilderPush { prev, changed: prev != self.cur }
3b2f2976
XL
519 }
520
f035d41b
XL
521 /// Checks if the lint is gated on a feature that is not enabled.
522 fn check_gated_lint(&self, lint_id: LintId, span: Span) {
523 if let Some(feature) = lint_id.lint.feature_gate {
524 if !self.sess.features_untracked().enabled(feature) {
525 feature_err(
526 &self.sess.parse_sess,
527 feature,
528 span,
529 &format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
530 )
531 .emit();
532 }
f9f354fc
XL
533 }
534 }
535
3b2f2976
XL
536 /// Called after `push` when the scope of a set of attributes are exited.
537 pub fn pop(&mut self, push: BuilderPush) {
538 self.cur = push.prev;
539 }
540
f9f354fc 541 /// Find the lint level for a lint.
fc512014 542 pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintLevelSource) {
f9f354fc
XL
543 self.sets.get_lint_level(lint, self.cur, None, self.sess)
544 }
545
3b2f2976
XL
546 /// Used to emit a lint-related diagnostic based on the current state of
547 /// this lint context.
dfeec247
XL
548 pub fn struct_lint(
549 &self,
550 lint: &'static Lint,
551 span: Option<MultiSpan>,
74b04a01
XL
552 decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>),
553 ) {
f9f354fc 554 let (level, src) = self.lint_level(lint);
74b04a01 555 struct_lint_level(self.sess, lint, level, src, span, decorate)
3b2f2976
XL
556 }
557
558 /// Registers the ID provided with the current set of lints stored in
559 /// this context.
560 pub fn register_id(&mut self, id: HirId) {
561 self.id_to_set.insert(id, self.cur);
562 }
563
3b2f2976 564 pub fn build_map(self) -> LintLevelMap {
dfeec247 565 LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
3b2f2976
XL
566 }
567}
568
5099ac24 569struct LintLevelMapBuilder<'tcx> {
dfeec247
XL
570 levels: LintLevelsBuilder<'tcx>,
571 tcx: TyCtxt<'tcx>,
3b2f2976
XL
572}
573
5099ac24 574impl LintLevelMapBuilder<'_> {
6a06907d 575 fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
dfeec247
XL
576 where
577 F: FnOnce(&mut Self),
3b2f2976 578 {
f035d41b 579 let is_crate_hir = id == hir::CRATE_HIR_ID;
6a06907d 580 let attrs = self.tcx.hir().attrs(id);
5099ac24 581 let push = self.levels.push(attrs, is_crate_hir);
dfeec247
XL
582 if push.changed {
583 self.levels.register_id(id);
584 }
585 f(self);
586 self.levels.pop(push);
3b2f2976 587 }
ea8adc8c
XL
588}
589
5099ac24
FG
590impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
591 type NestedFilter = nested_filter::All;
ea8adc8c 592
5099ac24
FG
593 fn nested_visit_map(&mut self) -> Self::Map {
594 self.tcx.hir()
dfeec247 595 }
ea8adc8c 596
dfeec247 597 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
6a06907d 598 self.with_lint_attrs(param.hir_id, |builder| {
dfeec247
XL
599 intravisit::walk_param(builder, param);
600 });
601 }
ea8adc8c 602
dfeec247 603 fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
6a06907d 604 self.with_lint_attrs(it.hir_id(), |builder| {
dfeec247
XL
605 intravisit::walk_item(builder, it);
606 });
607 }
ea8adc8c 608
dfeec247 609 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
6a06907d 610 self.with_lint_attrs(it.hir_id(), |builder| {
dfeec247
XL
611 intravisit::walk_foreign_item(builder, it);
612 })
613 }
614
29967ef6
XL
615 fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) {
616 // We will call `with_lint_attrs` when we walk
617 // the `StmtKind`. The outer statement itself doesn't
618 // define the lint levels.
619 intravisit::walk_stmt(self, e);
620 }
621
dfeec247 622 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
6a06907d 623 self.with_lint_attrs(e.hir_id, |builder| {
dfeec247
XL
624 intravisit::walk_expr(builder, e);
625 })
626 }
ea8adc8c 627
6a06907d
XL
628 fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
629 self.with_lint_attrs(s.hir_id, |builder| {
630 intravisit::walk_field_def(builder, s);
dfeec247
XL
631 })
632 }
ea8adc8c 633
dfeec247
XL
634 fn visit_variant(
635 &mut self,
636 v: &'tcx hir::Variant<'tcx>,
637 g: &'tcx hir::Generics<'tcx>,
638 item_id: hir::HirId,
639 ) {
6a06907d 640 self.with_lint_attrs(v.id, |builder| {
dfeec247 641 intravisit::walk_variant(builder, v, g, item_id);
ea8adc8c
XL
642 })
643 }
dfeec247
XL
644
645 fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
6a06907d 646 self.with_lint_attrs(l.hir_id, |builder| {
dfeec247
XL
647 intravisit::walk_local(builder, l);
648 })
649 }
650
651 fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
6a06907d 652 self.with_lint_attrs(a.hir_id, |builder| {
dfeec247
XL
653 intravisit::walk_arm(builder, a);
654 })
655 }
656
657 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
6a06907d 658 self.with_lint_attrs(trait_item.hir_id(), |builder| {
dfeec247
XL
659 intravisit::walk_trait_item(builder, trait_item);
660 });
661 }
662
663 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
6a06907d 664 self.with_lint_attrs(impl_item.hir_id(), |builder| {
dfeec247
XL
665 intravisit::walk_impl_item(builder, impl_item);
666 });
667 }
668}
669
f035d41b 670pub fn provide(providers: &mut Providers) {
dfeec247 671 providers.lint_levels = lint_levels;
ea8adc8c 672}