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