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