]> git.lizzy.rs Git - rust.git/blob - src/librustc/lint/context.rs
Rollup merge of #67130 - wesleywiser:const_prop_into_locals, r=oli-obk
[rust.git] / src / librustc / lint / context.rs
1 //! Implementation of lint checking.
2 //!
3 //! The lint checking is mostly consolidated into one pass which runs
4 //! after all other analyses. Throughout compilation, lint warnings
5 //! can be added via the `add_lint` method on the Session structure. This
6 //! requires a span and an ID of the node that the lint is being added to. The
7 //! lint isn't actually emitted at that time because it is unknown what the
8 //! actual lint level at that location is.
9 //!
10 //! To actually emit lint warnings/errors, a separate pass is used.
11 //! A context keeps track of the current state of all lint levels.
12 //! Upon entering a node of the ast which can modify the lint settings, the
13 //! previous lint state is pushed onto a stack and the ast is then recursed
14 //! upon. As the ast is traversed, this keeps track of the current lint level
15 //! for all lint attributes.
16
17 use self::TargetLint::*;
18
19 use crate::hir;
20 use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
21 use crate::hir::intravisit as hir_visit;
22 use crate::hir::intravisit::Visitor;
23 use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
24 use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject};
25 use crate::lint::{Level, Lint, LintId, LintPass, LintBuffer, FutureIncompatibleInfo};
26 use crate::lint::builtin::BuiltinLintDiagnostics;
27 use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
28 use crate::middle::privacy::AccessLevels;
29 use crate::session::Session;
30 use crate::ty::{self, print::Printer, subst::GenericArg, TyCtxt, Ty};
31 use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
32 use crate::util::nodemap::FxHashMap;
33 use crate::util::common::time;
34
35 use errors::DiagnosticBuilder;
36 use std::slice;
37 use rustc_data_structures::sync::{self, ParallelIterator, join, par_iter};
38 use syntax::ast;
39 use syntax::util::lev_distance::find_best_match_for_name;
40 use syntax::visit as ast_visit;
41 use syntax_pos::{MultiSpan, Span, symbol::Symbol};
42
43 use rustc_error_codes::*;
44
45 /// Information about the registered lints.
46 ///
47 /// This is basically the subset of `Context` that we can
48 /// build early in the compile pipeline.
49 pub struct LintStore {
50     /// Registered lints.
51     lints: Vec<&'static Lint>,
52
53     /// Constructor functions for each variety of lint pass.
54     ///
55     /// These should only be called once, but since we want to avoid locks or
56     /// interior mutability, we don't enforce this (and lints should, in theory,
57     /// be compatible with being constructed more than once, though not
58     /// necessarily in a sane manner. This is safe though.)
59     pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
60     early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
61     late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
62     /// This is unique in that we construct them per-module, so not once.
63     late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
64
65     /// Lints indexed by name.
66     by_name: FxHashMap<String, TargetLint>,
67
68     /// Map of registered lint groups to what lints they expand to.
69     lint_groups: FxHashMap<&'static str, LintGroup>,
70 }
71
72 /// Lints that are buffered up early on in the `Session` before the
73 /// `LintLevels` is calculated
74 #[derive(PartialEq, Debug)]
75 pub struct BufferedEarlyLint {
76     pub lint_id: LintId,
77     pub ast_id: ast::NodeId,
78     pub span: MultiSpan,
79     pub msg: String,
80     pub diagnostic: BuiltinLintDiagnostics,
81 }
82
83 /// The target of the `by_name` map, which accounts for renaming/deprecation.
84 enum TargetLint {
85     /// A direct lint target
86     Id(LintId),
87
88     /// Temporary renaming, used for easing migration pain; see #16545
89     Renamed(String, LintId),
90
91     /// Lint with this name existed previously, but has been removed/deprecated.
92     /// The string argument is the reason for removal.
93     Removed(String),
94 }
95
96 pub enum FindLintError {
97     NotFound,
98     Removed,
99 }
100
101 struct LintAlias {
102     name: &'static str,
103     /// Whether deprecation warnings should be suppressed for this alias.
104     silent: bool,
105 }
106
107 struct LintGroup {
108     lint_ids: Vec<LintId>,
109     from_plugin: bool,
110     depr: Option<LintAlias>,
111 }
112
113 pub enum CheckLintNameResult<'a> {
114     Ok(&'a [LintId]),
115     /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
116     NoLint(Option<Symbol>),
117     /// The lint is either renamed or removed. This is the warning
118     /// message, and an optional new name (`None` if removed).
119     Warning(String, Option<String>),
120     /// The lint is from a tool. If the Option is None, then either
121     /// the lint does not exist in the tool or the code was not
122     /// compiled with the tool and therefore the lint was never
123     /// added to the `LintStore`. Otherwise the `LintId` will be
124     /// returned as if it where a rustc lint.
125     Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>),
126 }
127
128 impl LintStore {
129     pub fn new() -> LintStore {
130         LintStore {
131             lints: vec![],
132             pre_expansion_passes: vec![],
133             early_passes: vec![],
134             late_passes: vec![],
135             late_module_passes: vec![],
136             by_name: Default::default(),
137             lint_groups: Default::default(),
138         }
139     }
140
141     pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
142         &self.lints
143     }
144
145     pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
146         self.lint_groups.iter()
147             .filter(|(_, LintGroup { depr, .. })| {
148                 // Don't display deprecated lint groups.
149                 depr.is_none()
150             })
151             .map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
152                 (*k, lint_ids.clone(), *from_plugin)
153             })
154             .collect()
155     }
156
157     pub fn register_early_pass(
158         &mut self,
159         pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync
160     ) {
161         self.early_passes.push(Box::new(pass));
162     }
163
164     pub fn register_pre_expansion_pass(
165         &mut self,
166         pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
167     ) {
168         self.pre_expansion_passes.push(Box::new(pass));
169     }
170
171     pub fn register_late_pass(
172         &mut self,
173         pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
174     ) {
175         self.late_passes.push(Box::new(pass));
176     }
177
178     pub fn register_late_mod_pass(
179         &mut self,
180         pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
181     ) {
182         self.late_module_passes.push(Box::new(pass));
183     }
184
185     // Helper method for register_early/late_pass
186     pub fn register_lints(&mut self, lints: &[&'static Lint]) {
187         for lint in lints {
188             self.lints.push(lint);
189
190             let id = LintId::of(lint);
191             if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
192                 bug!("duplicate specification of lint {}", lint.name_lower())
193             }
194
195             if let Some(FutureIncompatibleInfo { edition, .. }) = lint.future_incompatible {
196                 if let Some(edition) = edition {
197                     self.lint_groups.entry(edition.lint_name())
198                         .or_insert(LintGroup {
199                             lint_ids: vec![],
200                             from_plugin: lint.is_plugin,
201                             depr: None,
202                         })
203                         .lint_ids.push(id);
204                 }
205
206                 self.lint_groups.entry("future_incompatible")
207                     .or_insert(LintGroup {
208                         lint_ids: vec![],
209                         from_plugin: lint.is_plugin,
210                         depr: None,
211                     })
212                     .lint_ids.push(id);
213             }
214         }
215     }
216
217     pub fn register_group_alias(
218         &mut self,
219         lint_name: &'static str,
220         alias: &'static str,
221     ) {
222         self.lint_groups.insert(alias, LintGroup {
223             lint_ids: vec![],
224             from_plugin: false,
225             depr: Some(LintAlias { name: lint_name, silent: true }),
226         });
227     }
228
229     pub fn register_group(
230         &mut self,
231         from_plugin: bool,
232         name: &'static str,
233         deprecated_name: Option<&'static str>,
234         to: Vec<LintId>,
235     ) {
236         let new = self
237             .lint_groups
238             .insert(name, LintGroup {
239                 lint_ids: to,
240                 from_plugin,
241                 depr: None,
242             })
243             .is_none();
244         if let Some(deprecated) = deprecated_name {
245             self.lint_groups.insert(deprecated, LintGroup {
246                 lint_ids: vec![],
247                 from_plugin,
248                 depr: Some(LintAlias { name, silent: false }),
249             });
250         }
251
252         if !new {
253             bug!("duplicate specification of lint group {}", name);
254         }
255     }
256
257     pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
258         let target = match self.by_name.get(new_name) {
259             Some(&Id(lint_id)) => lint_id.clone(),
260             _ => bug!("invalid lint renaming of {} to {}", old_name, new_name)
261         };
262         self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
263     }
264
265     pub fn register_removed(&mut self, name: &str, reason: &str) {
266         self.by_name.insert(name.into(), Removed(reason.into()));
267     }
268
269     pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
270         match self.by_name.get(lint_name) {
271             Some(&Id(lint_id)) => Ok(vec![lint_id]),
272             Some(&Renamed(_, lint_id)) => {
273                 Ok(vec![lint_id])
274             },
275             Some(&Removed(_)) => {
276                 Err(FindLintError::Removed)
277             },
278             None => {
279                 loop {
280                     return match self.lint_groups.get(lint_name) {
281                         Some(LintGroup {lint_ids, depr, .. }) => {
282                             if let Some(LintAlias { name, .. }) = depr {
283                                 lint_name = name;
284                                 continue;
285                             }
286                             Ok(lint_ids.clone())
287                         }
288                         None => Err(FindLintError::Removed)
289                     };
290                 }
291             }
292         }
293     }
294
295     /// Checks the validity of lint names derived from the command line
296     pub fn check_lint_name_cmdline(&self,
297                                    sess: &Session,
298                                    lint_name: &str,
299                                    level: Level) {
300         let db = match self.check_lint_name(lint_name, None) {
301             CheckLintNameResult::Ok(_) => None,
302             CheckLintNameResult::Warning(ref msg, _) => {
303                 Some(sess.struct_warn(msg))
304             },
305             CheckLintNameResult::NoLint(suggestion) => {
306                 let mut err = struct_err!(sess, E0602, "unknown lint: `{}`", lint_name);
307
308                 if let Some(suggestion) = suggestion {
309                     err.help(&format!("did you mean: `{}`", suggestion));
310                 }
311
312                 Some(err)
313             }
314             CheckLintNameResult::Tool(result) => match result {
315                 Err((Some(_), new_name)) => Some(sess.struct_warn(&format!(
316                     "lint name `{}` is deprecated \
317                      and does not have an effect anymore. \
318                      Use: {}",
319                     lint_name, new_name
320                 ))),
321                 _ => None,
322             },
323         };
324
325         if let Some(mut db) = db {
326             let msg = format!("requested on the command line with `{} {}`",
327                               match level {
328                                   Level::Allow => "-A",
329                                   Level::Warn => "-W",
330                                   Level::Deny => "-D",
331                                   Level::Forbid => "-F",
332                               },
333                               lint_name);
334             db.note(&msg);
335             db.emit();
336         }
337     }
338
339     /// Checks the name of a lint for its existence, and whether it was
340     /// renamed or removed. Generates a DiagnosticBuilder containing a
341     /// warning for renamed and removed lints. This is over both lint
342     /// names from attributes and those passed on the command line. Since
343     /// it emits non-fatal warnings and there are *two* lint passes that
344     /// inspect attributes, this is only run from the late pass to avoid
345     /// printing duplicate warnings.
346     pub fn check_lint_name(
347         &self,
348         lint_name: &str,
349         tool_name: Option<Symbol>,
350     ) -> CheckLintNameResult<'_> {
351         let complete_name = if let Some(tool_name) = tool_name {
352             format!("{}::{}", tool_name, lint_name)
353         } else {
354             lint_name.to_string()
355         };
356         // If the lint was scoped with `tool::` check if the tool lint exists
357         if let Some(_) = tool_name {
358             match self.by_name.get(&complete_name) {
359                 None => match self.lint_groups.get(&*complete_name) {
360                     None => return CheckLintNameResult::Tool(Err((None, String::new()))),
361                     Some(LintGroup { lint_ids, .. }) => {
362                         return CheckLintNameResult::Tool(Ok(&lint_ids));
363                     }
364                 },
365                 Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
366                 // If the lint was registered as removed or renamed by the lint tool, we don't need
367                 // to treat tool_lints and rustc lints different and can use the code below.
368                 _ => {}
369             }
370         }
371         match self.by_name.get(&complete_name) {
372             Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
373                 format!(
374                     "lint `{}` has been renamed to `{}`",
375                     complete_name, new_name
376                 ),
377                 Some(new_name.to_owned()),
378             ),
379             Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
380                 format!("lint `{}` has been removed: `{}`", complete_name, reason),
381                 None,
382             ),
383             None => match self.lint_groups.get(&*complete_name) {
384                 // If neither the lint, nor the lint group exists check if there is a `clippy::`
385                 // variant of this lint
386                 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
387                 Some(LintGroup { lint_ids, depr, .. }) => {
388                     // Check if the lint group name is deprecated
389                     if let Some(LintAlias { name, silent }) = depr {
390                         let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
391                         return if *silent {
392                             CheckLintNameResult::Ok(&lint_ids)
393                         } else {
394                             CheckLintNameResult::Tool(Err((
395                                 Some(&lint_ids),
396                                 name.to_string(),
397                             )))
398                         };
399                     }
400                     CheckLintNameResult::Ok(&lint_ids)
401                 }
402             },
403             Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
404         }
405     }
406
407     fn check_tool_name_for_backwards_compat(
408         &self,
409         lint_name: &str,
410         tool_name: &str,
411     ) -> CheckLintNameResult<'_> {
412         let complete_name = format!("{}::{}", tool_name, lint_name);
413         match self.by_name.get(&complete_name) {
414             None => match self.lint_groups.get(&*complete_name) {
415                 // Now we are sure, that this lint exists nowhere
416                 None => {
417                     let symbols = self.by_name.keys()
418                         .map(|name| Symbol::intern(&name))
419                         .collect::<Vec<_>>();
420
421                     let suggestion =
422                         find_best_match_for_name(symbols.iter(), &lint_name.to_lowercase(), None);
423
424                     CheckLintNameResult::NoLint(suggestion)
425                 }
426                 Some(LintGroup { lint_ids, depr, .. }) => {
427                     // Reaching this would be weird, but let's cover this case anyway
428                     if let Some(LintAlias { name, silent }) = depr {
429                         let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
430                         return if *silent {
431                             CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
432                         } else {
433                             CheckLintNameResult::Tool(Err((
434                                 Some(&lint_ids),
435                                 name.to_string(),
436                             )))
437                         };
438                     }
439                     CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
440                 }
441             },
442             Some(&Id(ref id)) => {
443                 CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
444             }
445             _ => CheckLintNameResult::NoLint(None),
446         }
447     }
448 }
449
450 /// Context for lint checking after type checking.
451 pub struct LateContext<'a, 'tcx> {
452     /// Type context we're checking in.
453     pub tcx: TyCtxt<'tcx>,
454
455     /// Side-tables for the body we are in.
456     // FIXME: Make this lazy to avoid running the TypeckTables query?
457     pub tables: &'a ty::TypeckTables<'tcx>,
458
459     /// Parameter environment for the item we are in.
460     pub param_env: ty::ParamEnv<'tcx>,
461
462     /// Items accessible from the crate being checked.
463     pub access_levels: &'a AccessLevels,
464
465     /// The store of registered lints and the lint levels.
466     lint_store: &'tcx LintStore,
467
468     last_node_with_lint_attrs: hir::HirId,
469
470     /// Generic type parameters in scope for the item we are in.
471     pub generics: Option<&'tcx hir::Generics>,
472
473     /// We are only looking at one module
474     only_module: bool,
475 }
476
477 pub struct LateContextAndPass<'a, 'tcx, T: LateLintPass<'a, 'tcx>> {
478     context: LateContext<'a, 'tcx>,
479     pass: T,
480 }
481
482 /// Context for lint checking of the AST, after expansion, before lowering to
483 /// HIR.
484 pub struct EarlyContext<'a> {
485     /// Type context we're checking in.
486     pub sess: &'a Session,
487
488     /// The crate being checked.
489     pub krate: &'a ast::Crate,
490
491     builder: LintLevelsBuilder<'a>,
492
493     /// The store of registered lints and the lint levels.
494     lint_store: &'a LintStore,
495
496     buffered: LintBuffer,
497 }
498
499 pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
500     context: EarlyContext<'a>,
501     pass: T,
502 }
503
504 pub trait LintPassObject: Sized {}
505
506 impl LintPassObject for EarlyLintPassObject {}
507
508 impl LintPassObject for LateLintPassObject {}
509
510 pub trait LintContext: Sized {
511     type PassObject: LintPassObject;
512
513     fn sess(&self) -> &Session;
514     fn lints(&self) -> &LintStore;
515
516     fn lookup_and_emit<S: Into<MultiSpan>>(&self,
517                                            lint: &'static Lint,
518                                            span: Option<S>,
519                                            msg: &str) {
520         self.lookup(lint, span, msg).emit();
521     }
522
523     fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
524                                                             lint: &'static Lint,
525                                                             span: Option<S>,
526                                                             msg: &str,
527                                                             diagnostic: BuiltinLintDiagnostics) {
528         let mut db = self.lookup(lint, span, msg);
529         diagnostic.run(self.sess(), &mut db);
530         db.emit();
531     }
532
533     fn lookup<S: Into<MultiSpan>>(&self,
534                                   lint: &'static Lint,
535                                   span: Option<S>,
536                                   msg: &str)
537                                   -> DiagnosticBuilder<'_>;
538
539     /// Emit a lint at the appropriate level, for a particular span.
540     fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
541         self.lookup_and_emit(lint, Some(span), msg);
542     }
543
544     fn struct_span_lint<S: Into<MultiSpan>>(&self,
545                                             lint: &'static Lint,
546                                             span: S,
547                                             msg: &str)
548                                             -> DiagnosticBuilder<'_> {
549         self.lookup(lint, Some(span), msg)
550     }
551
552     /// Emit a lint and note at the appropriate level, for a particular span.
553     fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
554                       note_span: Span, note: &str) {
555         let mut err = self.lookup(lint, Some(span), msg);
556         if note_span == span {
557             err.note(note);
558         } else {
559             err.span_note(note_span, note);
560         }
561         err.emit();
562     }
563
564     /// Emit a lint and help at the appropriate level, for a particular span.
565     fn span_lint_help(&self, lint: &'static Lint, span: Span,
566                       msg: &str, help: &str) {
567         let mut err = self.lookup(lint, Some(span), msg);
568         self.span_lint(lint, span, msg);
569         err.span_help(span, help);
570         err.emit();
571     }
572
573     /// Emit a lint at the appropriate level, with no associated span.
574     fn lint(&self, lint: &'static Lint, msg: &str) {
575         self.lookup_and_emit(lint, None as Option<Span>, msg);
576     }
577 }
578
579
580 impl<'a> EarlyContext<'a> {
581     fn new(
582         sess: &'a Session,
583         lint_store: &'a LintStore,
584         krate: &'a ast::Crate,
585         buffered: LintBuffer,
586         warn_about_weird_lints: bool,
587     ) -> EarlyContext<'a> {
588         EarlyContext {
589             sess,
590             krate,
591             lint_store,
592             builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store),
593             buffered,
594         }
595     }
596 }
597
598 macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
599     $cx.pass.$f(&$cx.context, $($args),*);
600 }) }
601
602 macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
603     $cx.pass.$f(&$cx.context, $($args),*);
604 }) }
605
606 impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
607     fn check_id(&mut self, id: ast::NodeId) {
608         for early_lint in self.context.buffered.take(id) {
609             self.context.lookup_and_emit_with_diagnostics(
610                 early_lint.lint_id.lint,
611                 Some(early_lint.span.clone()),
612                 &early_lint.msg,
613                 early_lint.diagnostic
614             );
615         }
616     }
617
618     /// Merge the lints specified by any lint attributes into the
619     /// current lint context, call the provided function, then reset the
620     /// lints in effect to their previous state.
621     fn with_lint_attrs<F>(&mut self,
622                           id: ast::NodeId,
623                           attrs: &'a [ast::Attribute],
624                           f: F)
625         where F: FnOnce(&mut Self)
626     {
627         let push = self.context.builder.push(attrs, &self.context.lint_store);
628         self.check_id(id);
629         self.enter_attrs(attrs);
630         f(self);
631         self.exit_attrs(attrs);
632         self.context.builder.pop(push);
633     }
634
635     fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) {
636         debug!("early context: enter_attrs({:?})", attrs);
637         run_early_pass!(self, enter_lint_attrs, attrs);
638     }
639
640     fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) {
641         debug!("early context: exit_attrs({:?})", attrs);
642         run_early_pass!(self, exit_lint_attrs, attrs);
643     }
644 }
645
646 impl LintContext for LateContext<'_, '_> {
647     type PassObject = LateLintPassObject;
648
649     /// Gets the overall compiler `Session` object.
650     fn sess(&self) -> &Session {
651         &self.tcx.sess
652     }
653
654     fn lints(&self) -> &LintStore {
655         &*self.lint_store
656     }
657
658     fn lookup<S: Into<MultiSpan>>(&self,
659                                   lint: &'static Lint,
660                                   span: Option<S>,
661                                   msg: &str)
662                                   -> DiagnosticBuilder<'_> {
663         let hir_id = self.last_node_with_lint_attrs;
664
665         match span {
666             Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg),
667             None => {
668                 self.tcx.struct_lint_node(lint, hir_id, msg)
669             },
670         }
671     }
672 }
673
674 impl LintContext for EarlyContext<'_> {
675     type PassObject = EarlyLintPassObject;
676
677     /// Gets the overall compiler `Session` object.
678     fn sess(&self) -> &Session {
679         &self.sess
680     }
681
682     fn lints(&self) -> &LintStore {
683         &*self.lint_store
684     }
685
686     fn lookup<S: Into<MultiSpan>>(&self,
687                                   lint: &'static Lint,
688                                   span: Option<S>,
689                                   msg: &str)
690                                   -> DiagnosticBuilder<'_> {
691         self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
692     }
693 }
694
695 impl<'a, 'tcx> LateContext<'a, 'tcx> {
696     pub fn current_lint_root(&self) -> hir::HirId {
697         self.last_node_with_lint_attrs
698     }
699
700     /// Check if a `DefId`'s path matches the given absolute type path usage.
701     ///
702     /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
703     /// inherent `impl` blocks are matched with the name of the type.
704     ///
705     /// # Examples
706     ///
707     /// ```rust,ignore (no context or def id available)
708     /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) {
709     ///     // The given `def_id` is that of an `Option` type
710     /// }
711     /// ```
712     pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool {
713         let names = self.get_def_path(def_id);
714
715         names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b)
716     }
717
718     /// Gets the absolute path of `def_id` as a vector of `Symbol`.
719     ///
720     /// # Examples
721     ///
722     /// ```rust,ignore (no context or def id available)
723     /// let def_path = cx.get_def_path(def_id);
724     /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] {
725     ///     // The given `def_id` is that of an `Option` type
726     /// }
727     /// ```
728     pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
729         pub struct AbsolutePathPrinter<'tcx> {
730             pub tcx: TyCtxt<'tcx>,
731         }
732
733         impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
734             type Error = !;
735
736             type Path = Vec<Symbol>;
737             type Region = ();
738             type Type = ();
739             type DynExistential = ();
740             type Const = ();
741
742             fn tcx(&self) -> TyCtxt<'tcx> {
743                 self.tcx
744             }
745
746             fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
747                 Ok(())
748             }
749
750             fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
751                 Ok(())
752             }
753
754             fn print_dyn_existential(
755                 self,
756                 _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
757             ) -> Result<Self::DynExistential, Self::Error> {
758                 Ok(())
759             }
760
761             fn print_const(
762                 self,
763                 _ct: &'tcx ty::Const<'tcx>,
764             ) -> Result<Self::Const, Self::Error> {
765                 Ok(())
766             }
767
768             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
769                 Ok(vec![self.tcx.original_crate_name(cnum)])
770             }
771
772             fn path_qualified(
773                 self,
774                 self_ty: Ty<'tcx>,
775                 trait_ref: Option<ty::TraitRef<'tcx>>,
776             ) -> Result<Self::Path, Self::Error> {
777                 if trait_ref.is_none() {
778                     if let ty::Adt(def, substs) = self_ty.kind {
779                         return self.print_def_path(def.did, substs);
780                     }
781                 }
782
783                 // This shouldn't ever be needed, but just in case:
784                 Ok(vec![match trait_ref {
785                     Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)),
786                     None => Symbol::intern(&format!("<{}>", self_ty)),
787                 }])
788             }
789
790             fn path_append_impl(
791                 self,
792                 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
793                 _disambiguated_data: &DisambiguatedDefPathData,
794                 self_ty: Ty<'tcx>,
795                 trait_ref: Option<ty::TraitRef<'tcx>>,
796             ) -> Result<Self::Path, Self::Error> {
797                 let mut path = print_prefix(self)?;
798
799                 // This shouldn't ever be needed, but just in case:
800                 path.push(match trait_ref {
801                     Some(trait_ref) => {
802                         Symbol::intern(
803                             &format!(
804                                 "<impl {} for {}>",
805                                 trait_ref.print_only_trait_path(),
806                                 self_ty
807                             )
808                         )
809                     },
810                     None => Symbol::intern(&format!("<impl {}>", self_ty)),
811                 });
812
813                 Ok(path)
814             }
815
816             fn path_append(
817                 self,
818                 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
819                 disambiguated_data: &DisambiguatedDefPathData,
820             ) -> Result<Self::Path, Self::Error> {
821                 let mut path = print_prefix(self)?;
822
823                 // Skip `::{{constructor}}` on tuple/unit structs.
824                 match disambiguated_data.data {
825                     DefPathData::Ctor => return Ok(path),
826                     _ => {}
827                 }
828
829                 path.push(disambiguated_data.data.as_symbol());
830                 Ok(path)
831             }
832
833             fn path_generic_args(
834                 self,
835                 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
836                 _args: &[GenericArg<'tcx>],
837             ) -> Result<Self::Path, Self::Error> {
838                 print_prefix(self)
839             }
840         }
841
842         AbsolutePathPrinter { tcx: self.tcx }
843             .print_def_path(def_id, &[])
844             .unwrap()
845     }
846 }
847
848 impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
849     type Ty = Ty<'tcx>;
850     type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
851
852     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
853         self.tcx.layout_of(self.param_env.and(ty))
854     }
855 }
856
857 impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> {
858     /// Merge the lints specified by any lint attributes into the
859     /// current lint context, call the provided function, then reset the
860     /// lints in effect to their previous state.
861     fn with_lint_attrs<F>(&mut self,
862                           id: hir::HirId,
863                           attrs: &'tcx [ast::Attribute],
864                           f: F)
865         where F: FnOnce(&mut Self)
866     {
867         let prev = self.context.last_node_with_lint_attrs;
868         self.context.last_node_with_lint_attrs = id;
869         self.enter_attrs(attrs);
870         f(self);
871         self.exit_attrs(attrs);
872         self.context.last_node_with_lint_attrs = prev;
873     }
874
875     fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
876         where F: FnOnce(&mut Self),
877     {
878         let old_param_env = self.context.param_env;
879         self.context.param_env = self.context.tcx.param_env(
880             self.context.tcx.hir().local_def_id(id)
881         );
882         f(self);
883         self.context.param_env = old_param_env;
884     }
885
886     fn process_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
887         lint_callback!(self, check_mod, m, s, n);
888         hir_visit::walk_mod(self, m, n);
889         lint_callback!(self, check_mod_post, m, s, n);
890     }
891
892     fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
893         debug!("late context: enter_attrs({:?})", attrs);
894         lint_callback!(self, enter_lint_attrs, attrs);
895     }
896
897     fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
898         debug!("late context: exit_attrs({:?})", attrs);
899         lint_callback!(self, exit_lint_attrs, attrs);
900     }
901 }
902
903 impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
904 for LateContextAndPass<'a, 'tcx, T> {
905     /// Because lints are scoped lexically, we want to walk nested
906     /// items in the context of the outer item, so enable
907     /// deep-walking.
908     fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
909         hir_visit::NestedVisitorMap::All(&self.context.tcx.hir())
910     }
911
912     fn visit_nested_body(&mut self, body: hir::BodyId) {
913         let old_tables = self.context.tables;
914         self.context.tables = self.context.tcx.body_tables(body);
915         let body = self.context.tcx.hir().body(body);
916         self.visit_body(body);
917         self.context.tables = old_tables;
918     }
919
920     fn visit_param(&mut self, param: &'tcx hir::Param) {
921         self.with_lint_attrs(param.hir_id, &param.attrs, |cx| {
922             lint_callback!(cx, check_param, param);
923             hir_visit::walk_param(cx, param);
924         });
925     }
926
927     fn visit_body(&mut self, body: &'tcx hir::Body) {
928         lint_callback!(self, check_body, body);
929         hir_visit::walk_body(self, body);
930         lint_callback!(self, check_body_post, body);
931     }
932
933     fn visit_item(&mut self, it: &'tcx hir::Item) {
934         let generics = self.context.generics.take();
935         self.context.generics = it.kind.generics();
936         self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
937             cx.with_param_env(it.hir_id, |cx| {
938                 lint_callback!(cx, check_item, it);
939                 hir_visit::walk_item(cx, it);
940                 lint_callback!(cx, check_item_post, it);
941             });
942         });
943         self.context.generics = generics;
944     }
945
946     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
947         self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
948             cx.with_param_env(it.hir_id, |cx| {
949                 lint_callback!(cx, check_foreign_item, it);
950                 hir_visit::walk_foreign_item(cx, it);
951                 lint_callback!(cx, check_foreign_item_post, it);
952             });
953         })
954     }
955
956     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
957         lint_callback!(self, check_pat, p);
958         hir_visit::walk_pat(self, p);
959     }
960
961     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
962         self.with_lint_attrs(e.hir_id, &e.attrs, |cx| {
963             lint_callback!(cx, check_expr, e);
964             hir_visit::walk_expr(cx, e);
965             lint_callback!(cx, check_expr_post, e);
966         })
967     }
968
969     fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
970         // statement attributes are actually just attributes on one of
971         // - item
972         // - local
973         // - expression
974         // so we keep track of lint levels there
975         lint_callback!(self, check_stmt, s);
976         hir_visit::walk_stmt(self, s);
977     }
978
979     fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
980                 body_id: hir::BodyId, span: Span, id: hir::HirId) {
981         // Wrap in tables here, not just in visit_nested_body,
982         // in order for `check_fn` to be able to use them.
983         let old_tables = self.context.tables;
984         self.context.tables = self.context.tcx.body_tables(body_id);
985         let body = self.context.tcx.hir().body(body_id);
986         lint_callback!(self, check_fn, fk, decl, body, span, id);
987         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
988         lint_callback!(self, check_fn_post, fk, decl, body, span, id);
989         self.context.tables = old_tables;
990     }
991
992     fn visit_variant_data(&mut self,
993                         s: &'tcx hir::VariantData,
994                         _: ast::Name,
995                         _: &'tcx hir::Generics,
996                         _: hir::HirId,
997                         _: Span) {
998         lint_callback!(self, check_struct_def, s);
999         hir_visit::walk_struct_def(self, s);
1000         lint_callback!(self, check_struct_def_post, s);
1001     }
1002
1003     fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
1004         self.with_lint_attrs(s.hir_id, &s.attrs, |cx| {
1005             lint_callback!(cx, check_struct_field, s);
1006             hir_visit::walk_struct_field(cx, s);
1007         })
1008     }
1009
1010     fn visit_variant(&mut self,
1011                      v: &'tcx hir::Variant,
1012                      g: &'tcx hir::Generics,
1013                      item_id: hir::HirId) {
1014         self.with_lint_attrs(v.id, &v.attrs, |cx| {
1015             lint_callback!(cx, check_variant, v);
1016             hir_visit::walk_variant(cx, v, g, item_id);
1017             lint_callback!(cx, check_variant_post, v);
1018         })
1019     }
1020
1021     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
1022         lint_callback!(self, check_ty, t);
1023         hir_visit::walk_ty(self, t);
1024     }
1025
1026     fn visit_name(&mut self, sp: Span, name: ast::Name) {
1027         lint_callback!(self, check_name, sp, name);
1028     }
1029
1030     fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
1031         if !self.context.only_module {
1032             self.process_mod(m, s, n);
1033         }
1034     }
1035
1036     fn visit_local(&mut self, l: &'tcx hir::Local) {
1037         self.with_lint_attrs(l.hir_id, &l.attrs, |cx| {
1038             lint_callback!(cx, check_local, l);
1039             hir_visit::walk_local(cx, l);
1040         })
1041     }
1042
1043     fn visit_block(&mut self, b: &'tcx hir::Block) {
1044         lint_callback!(self, check_block, b);
1045         hir_visit::walk_block(self, b);
1046         lint_callback!(self, check_block_post, b);
1047     }
1048
1049     fn visit_arm(&mut self, a: &'tcx hir::Arm) {
1050         lint_callback!(self, check_arm, a);
1051         hir_visit::walk_arm(self, a);
1052     }
1053
1054     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
1055         lint_callback!(self, check_generic_param, p);
1056         hir_visit::walk_generic_param(self, p);
1057     }
1058
1059     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
1060         lint_callback!(self, check_generics, g);
1061         hir_visit::walk_generics(self, g);
1062     }
1063
1064     fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) {
1065         lint_callback!(self, check_where_predicate, p);
1066         hir_visit::walk_where_predicate(self, p);
1067     }
1068
1069     fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef,
1070                             m: hir::TraitBoundModifier) {
1071         lint_callback!(self, check_poly_trait_ref, t, m);
1072         hir_visit::walk_poly_trait_ref(self, t, m);
1073     }
1074
1075     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
1076         let generics = self.context.generics.take();
1077         self.context.generics = Some(&trait_item.generics);
1078         self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| {
1079             cx.with_param_env(trait_item.hir_id, |cx| {
1080                 lint_callback!(cx, check_trait_item, trait_item);
1081                 hir_visit::walk_trait_item(cx, trait_item);
1082                 lint_callback!(cx, check_trait_item_post, trait_item);
1083             });
1084         });
1085         self.context.generics = generics;
1086     }
1087
1088     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
1089         let generics = self.context.generics.take();
1090         self.context.generics = Some(&impl_item.generics);
1091         self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| {
1092             cx.with_param_env(impl_item.hir_id, |cx| {
1093                 lint_callback!(cx, check_impl_item, impl_item);
1094                 hir_visit::walk_impl_item(cx, impl_item);
1095                 lint_callback!(cx, check_impl_item_post, impl_item);
1096             });
1097         });
1098         self.context.generics = generics;
1099     }
1100
1101     fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
1102         lint_callback!(self, check_lifetime, lt);
1103         hir_visit::walk_lifetime(self, lt);
1104     }
1105
1106     fn visit_path(&mut self, p: &'tcx hir::Path, id: hir::HirId) {
1107         lint_callback!(self, check_path, p, id);
1108         hir_visit::walk_path(self, p);
1109     }
1110
1111     fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
1112         lint_callback!(self, check_attribute, attr);
1113     }
1114 }
1115
1116 impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> {
1117     fn visit_param(&mut self, param: &'a ast::Param) {
1118         self.with_lint_attrs(param.id, &param.attrs, |cx| {
1119             run_early_pass!(cx, check_param, param);
1120             ast_visit::walk_param(cx, param);
1121         });
1122     }
1123
1124     fn visit_item(&mut self, it: &'a ast::Item) {
1125         self.with_lint_attrs(it.id, &it.attrs, |cx| {
1126             run_early_pass!(cx, check_item, it);
1127             ast_visit::walk_item(cx, it);
1128             run_early_pass!(cx, check_item_post, it);
1129         })
1130     }
1131
1132     fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
1133         self.with_lint_attrs(it.id, &it.attrs, |cx| {
1134             run_early_pass!(cx, check_foreign_item, it);
1135             ast_visit::walk_foreign_item(cx, it);
1136             run_early_pass!(cx, check_foreign_item_post, it);
1137         })
1138     }
1139
1140     fn visit_pat(&mut self, p: &'a ast::Pat) {
1141         run_early_pass!(self, check_pat, p);
1142         self.check_id(p.id);
1143         ast_visit::walk_pat(self, p);
1144         run_early_pass!(self, check_pat_post, p);
1145     }
1146
1147     fn visit_expr(&mut self, e: &'a ast::Expr) {
1148         self.with_lint_attrs(e.id, &e.attrs, |cx| {
1149             run_early_pass!(cx, check_expr, e);
1150             ast_visit::walk_expr(cx, e);
1151         })
1152     }
1153
1154     fn visit_stmt(&mut self, s: &'a ast::Stmt) {
1155         run_early_pass!(self, check_stmt, s);
1156         self.check_id(s.id);
1157         ast_visit::walk_stmt(self, s);
1158     }
1159
1160     fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl,
1161                 span: Span, id: ast::NodeId) {
1162         run_early_pass!(self, check_fn, fk, decl, span, id);
1163         self.check_id(id);
1164         ast_visit::walk_fn(self, fk, decl, span);
1165         run_early_pass!(self, check_fn_post, fk, decl, span, id);
1166     }
1167
1168     fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
1169         run_early_pass!(self, check_struct_def, s);
1170         if let Some(ctor_hir_id) = s.ctor_id() {
1171             self.check_id(ctor_hir_id);
1172         }
1173         ast_visit::walk_struct_def(self, s);
1174         run_early_pass!(self, check_struct_def_post, s);
1175     }
1176
1177     fn visit_struct_field(&mut self, s: &'a ast::StructField) {
1178         self.with_lint_attrs(s.id, &s.attrs, |cx| {
1179             run_early_pass!(cx, check_struct_field, s);
1180             ast_visit::walk_struct_field(cx, s);
1181         })
1182     }
1183
1184     fn visit_variant(&mut self, v: &'a ast::Variant) {
1185         self.with_lint_attrs(v.id, &v.attrs, |cx| {
1186             run_early_pass!(cx, check_variant, v);
1187             ast_visit::walk_variant(cx, v);
1188             run_early_pass!(cx, check_variant_post, v);
1189         })
1190     }
1191
1192     fn visit_ty(&mut self, t: &'a ast::Ty) {
1193         run_early_pass!(self, check_ty, t);
1194         self.check_id(t.id);
1195         ast_visit::walk_ty(self, t);
1196     }
1197
1198     fn visit_ident(&mut self, ident: ast::Ident) {
1199         run_early_pass!(self, check_ident, ident);
1200     }
1201
1202     fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
1203         run_early_pass!(self, check_mod, m, s, n);
1204         self.check_id(n);
1205         ast_visit::walk_mod(self, m);
1206         run_early_pass!(self, check_mod_post, m, s, n);
1207     }
1208
1209     fn visit_local(&mut self, l: &'a ast::Local) {
1210         self.with_lint_attrs(l.id, &l.attrs, |cx| {
1211             run_early_pass!(cx, check_local, l);
1212             ast_visit::walk_local(cx, l);
1213         })
1214     }
1215
1216     fn visit_block(&mut self, b: &'a ast::Block) {
1217         run_early_pass!(self, check_block, b);
1218         self.check_id(b.id);
1219         ast_visit::walk_block(self, b);
1220         run_early_pass!(self, check_block_post, b);
1221     }
1222
1223     fn visit_arm(&mut self, a: &'a ast::Arm) {
1224         run_early_pass!(self, check_arm, a);
1225         ast_visit::walk_arm(self, a);
1226     }
1227
1228     fn visit_expr_post(&mut self, e: &'a ast::Expr) {
1229         run_early_pass!(self, check_expr_post, e);
1230     }
1231
1232     fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
1233         run_early_pass!(self, check_generic_param, param);
1234         ast_visit::walk_generic_param(self, param);
1235     }
1236
1237     fn visit_generics(&mut self, g: &'a ast::Generics) {
1238         run_early_pass!(self, check_generics, g);
1239         ast_visit::walk_generics(self, g);
1240     }
1241
1242     fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
1243         run_early_pass!(self, check_where_predicate, p);
1244         ast_visit::walk_where_predicate(self, p);
1245     }
1246
1247     fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
1248         run_early_pass!(self, check_poly_trait_ref, t, m);
1249         ast_visit::walk_poly_trait_ref(self, t, m);
1250     }
1251
1252     fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) {
1253         self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
1254             run_early_pass!(cx, check_trait_item, trait_item);
1255             ast_visit::walk_trait_item(cx, trait_item);
1256             run_early_pass!(cx, check_trait_item_post, trait_item);
1257         });
1258     }
1259
1260     fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) {
1261         self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
1262             run_early_pass!(cx, check_impl_item, impl_item);
1263             ast_visit::walk_impl_item(cx, impl_item);
1264             run_early_pass!(cx, check_impl_item_post, impl_item);
1265         });
1266     }
1267
1268     fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
1269         run_early_pass!(self, check_lifetime, lt);
1270         self.check_id(lt.id);
1271     }
1272
1273     fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
1274         run_early_pass!(self, check_path, p, id);
1275         self.check_id(id);
1276         ast_visit::walk_path(self, p);
1277     }
1278
1279     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
1280         run_early_pass!(self, check_attribute, attr);
1281     }
1282
1283     fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) {
1284         run_early_pass!(self, check_mac_def, mac, id);
1285         self.check_id(id);
1286     }
1287
1288     fn visit_mac(&mut self, mac: &'a ast::Mac) {
1289         // FIXME(#54110): So, this setup isn't really right. I think
1290         // that (a) the libsyntax visitor ought to be doing this as
1291         // part of `walk_mac`, and (b) we should be calling
1292         // `visit_path`, *but* that would require a `NodeId`, and I
1293         // want to get #53686 fixed quickly. -nmatsakis
1294         ast_visit::walk_path(self, &mac.path);
1295
1296         run_early_pass!(self, check_mac, mac);
1297     }
1298 }
1299
1300 struct LateLintPassObjects<'a> {
1301     lints: &'a mut [LateLintPassObject],
1302 }
1303
1304 #[allow(rustc::lint_pass_impl_without_macro)]
1305 impl LintPass for LateLintPassObjects<'_> {
1306     fn name(&self) -> &'static str {
1307         panic!()
1308     }
1309 }
1310
1311 macro_rules! expand_late_lint_pass_impl_methods {
1312     ([$a:tt, $hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
1313         $(fn $name(&mut self, context: &LateContext<$a, $hir>, $($param: $arg),*) {
1314             for obj in self.lints.iter_mut() {
1315                 obj.$name(context, $($param),*);
1316             }
1317         })*
1318     )
1319 }
1320
1321 macro_rules! late_lint_pass_impl {
1322     ([], [$hir:tt], $methods:tt) => (
1323         impl LateLintPass<'a, $hir> for LateLintPassObjects<'_> {
1324             expand_late_lint_pass_impl_methods!(['a, $hir], $methods);
1325         }
1326     )
1327 }
1328
1329 late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
1330
1331 fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
1332     tcx: TyCtxt<'tcx>,
1333     module_def_id: DefId,
1334     pass: T,
1335 ) {
1336     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1337
1338     let context = LateContext {
1339         tcx,
1340         tables: &ty::TypeckTables::empty(None),
1341         param_env: ty::ParamEnv::empty(),
1342         access_levels,
1343         lint_store: &tcx.lint_store,
1344         last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
1345         generics: None,
1346         only_module: true,
1347     };
1348
1349     let mut cx = LateContextAndPass {
1350         context,
1351         pass
1352     };
1353
1354     let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
1355     cx.process_mod(module, span, hir_id);
1356
1357     // Visit the crate attributes
1358     if hir_id == hir::CRATE_HIR_ID {
1359         walk_list!(cx, visit_attribute, tcx.hir().attrs(hir::CRATE_HIR_ID));
1360     }
1361 }
1362
1363 pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
1364     tcx: TyCtxt<'tcx>,
1365     module_def_id: DefId,
1366     builtin_lints: T,
1367 ) {
1368     if tcx.sess.opts.debugging_opts.no_interleave_lints {
1369         // These passes runs in late_lint_crate with -Z no_interleave_lints
1370         return;
1371     }
1372
1373     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
1374
1375     let mut passes: Vec<_> = tcx.lint_store.late_module_passes
1376                                 .iter().map(|pass| (pass)()).collect();
1377
1378     if !passes.is_empty() {
1379         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
1380     }
1381 }
1382
1383 fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
1384     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1385
1386     let krate = tcx.hir().krate();
1387
1388     let context = LateContext {
1389         tcx,
1390         tables: &ty::TypeckTables::empty(None),
1391         param_env: ty::ParamEnv::empty(),
1392         access_levels,
1393         lint_store: &tcx.lint_store,
1394         last_node_with_lint_attrs: hir::CRATE_HIR_ID,
1395         generics: None,
1396         only_module: false,
1397     };
1398
1399     let mut cx = LateContextAndPass {
1400         context,
1401         pass
1402     };
1403
1404     // Visit the whole crate.
1405     cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| {
1406         // since the root module isn't visited as an item (because it isn't an
1407         // item), warn for it here.
1408         lint_callback!(cx, check_crate, krate);
1409
1410         hir_visit::walk_crate(cx, krate);
1411
1412         lint_callback!(cx, check_crate_post, krate);
1413     })
1414 }
1415
1416 fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
1417     let mut passes = tcx.lint_store
1418         .late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
1419
1420     if !tcx.sess.opts.debugging_opts.no_interleave_lints {
1421         if !passes.is_empty() {
1422             late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] });
1423         }
1424
1425         late_lint_pass_crate(tcx, builtin_lints);
1426     } else {
1427         for pass in &mut passes {
1428             time(tcx.sess, &format!("running late lint: {}", pass.name()), || {
1429                 late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
1430             });
1431         }
1432
1433         let mut passes: Vec<_> = tcx.lint_store.late_module_passes
1434                                     .iter().map(|pass| (pass)()).collect();
1435
1436         for pass in &mut passes {
1437             time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
1438                 late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
1439             });
1440         }
1441     }
1442 }
1443
1444 /// Performs lint checking on a crate.
1445 pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
1446     tcx: TyCtxt<'tcx>,
1447     builtin_lints: impl FnOnce() -> T + Send,
1448 ) {
1449     join(|| {
1450         time(tcx.sess, "crate lints", || {
1451             // Run whole crate non-incremental lints
1452             late_lint_crate(tcx, builtin_lints());
1453         });
1454     }, || {
1455         time(tcx.sess, "module lints", || {
1456             // Run per-module lints
1457             par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
1458                 tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
1459             });
1460         });
1461     });
1462 }
1463
1464 struct EarlyLintPassObjects<'a> {
1465     lints: &'a mut [EarlyLintPassObject],
1466 }
1467
1468 #[allow(rustc::lint_pass_impl_without_macro)]
1469 impl LintPass for EarlyLintPassObjects<'_> {
1470     fn name(&self) -> &'static str {
1471         panic!()
1472     }
1473 }
1474
1475 macro_rules! expand_early_lint_pass_impl_methods {
1476     ([$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
1477         $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) {
1478             for obj in self.lints.iter_mut() {
1479                 obj.$name(context, $($param),*);
1480             }
1481         })*
1482     )
1483 }
1484
1485 macro_rules! early_lint_pass_impl {
1486     ([], [$($methods:tt)*]) => (
1487         impl EarlyLintPass for EarlyLintPassObjects<'_> {
1488             expand_early_lint_pass_impl_methods!([$($methods)*]);
1489         }
1490     )
1491 }
1492
1493 early_lint_methods!(early_lint_pass_impl, []);
1494
1495 fn early_lint_crate<T: EarlyLintPass>(
1496     sess: &Session,
1497     lint_store: &LintStore,
1498     krate: &ast::Crate,
1499     pass: T,
1500     buffered: LintBuffer,
1501     warn_about_weird_lints: bool,
1502 ) -> LintBuffer {
1503     let mut cx = EarlyContextAndPass {
1504         context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints),
1505         pass,
1506     };
1507
1508     // Visit the whole crate.
1509     cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
1510         // since the root module isn't visited as an item (because it isn't an
1511         // item), warn for it here.
1512         run_early_pass!(cx, check_crate, krate);
1513
1514         ast_visit::walk_crate(cx, krate);
1515
1516         run_early_pass!(cx, check_crate_post, krate);
1517     });
1518     cx.context.buffered
1519 }
1520
1521 pub fn check_ast_crate<T: EarlyLintPass>(
1522     sess: &Session,
1523     lint_store: &LintStore,
1524     krate: &ast::Crate,
1525     pre_expansion: bool,
1526     lint_buffer: Option<LintBuffer>,
1527     builtin_lints: T,
1528 ) {
1529     let mut passes: Vec<_> = if pre_expansion {
1530         lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect()
1531     } else {
1532         lint_store.early_passes.iter().map(|p| (p)()).collect()
1533     };
1534     let mut buffered = lint_buffer.unwrap_or_default();
1535
1536     if !sess.opts.debugging_opts.no_interleave_lints {
1537         buffered = early_lint_crate(sess, lint_store, krate, builtin_lints, buffered,
1538             pre_expansion);
1539
1540         if !passes.is_empty() {
1541             buffered = early_lint_crate(
1542                 sess,
1543                 lint_store,
1544                 krate,
1545                 EarlyLintPassObjects { lints: &mut passes[..] },
1546                 buffered,
1547                 pre_expansion,
1548             );
1549         }
1550     } else {
1551         for pass in &mut passes {
1552             buffered = time(sess, &format!("running lint: {}", pass.name()), || {
1553                 early_lint_crate(
1554                     sess,
1555                     lint_store,
1556                     krate,
1557                     EarlyLintPassObjects { lints: slice::from_mut(pass) },
1558                     buffered,
1559                     pre_expansion,
1560                 )
1561             });
1562         }
1563     }
1564
1565     // All of the buffered lints should have been emitted at this point.
1566     // If not, that means that we somehow buffered a lint for a node id
1567     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
1568     //
1569     // Rustdoc runs everybody-loops before the early lints and removes
1570     // function bodies, so it's totally possible for linted
1571     // node ids to not exist (e.g., macros defined within functions for the
1572     // unused_macro lint) anymore. So we only run this check
1573     // when we're not in rustdoc mode. (see issue #47639)
1574     if !sess.opts.actually_rustdoc {
1575         for (_id, lints) in buffered.map {
1576             for early_lint in lints {
1577                 sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
1578             }
1579         }
1580     }
1581 }