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