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