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