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