]> git.proxmox.com Git - rustc.git/blame - src/librustc/lint/context.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc / lint / context.rs
CommitLineData
1a4d82fc
JJ
1//! Implementation of lint checking.
2//!
94b46f34
XL
3//! The lint checking is mostly consolidated into one pass which runs
4//! after all other analyses. Throughout compilation, lint warnings
1a4d82fc 5//! can be added via the `add_lint` method on the Session structure. This
9fa01778 6//! requires a span and an ID of the node that the lint is being added to. The
1a4d82fc
JJ
7//! lint isn't actually emitted at that time because it is unknown what the
8//! actual lint level at that location is.
9//!
94b46f34
XL
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.
1a4d82fc
JJ
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
9fa01778 14//! upon. As the ast is traversed, this keeps track of the current lint level
1a4d82fc 15//! for all lint attributes.
3b2f2976 16
1a4d82fc
JJ
17use self::TargetLint::*;
18
e1599b0c
XL
19use crate::hir;
20use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
21use crate::hir::intravisit as hir_visit;
22use crate::hir::intravisit::Visitor;
23use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
532ac7d7 24use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject};
e74abb32 25use crate::lint::{Level, Lint, LintId, LintPass, LintBuffer, FutureIncompatibleInfo};
9fa01778
XL
26use crate::lint::builtin::BuiltinLintDiagnostics;
27use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
28use crate::middle::privacy::AccessLevels;
e74abb32
XL
29use crate::session::Session;
30use crate::ty::{self, print::Printer, subst::GenericArg, TyCtxt, Ty};
9fa01778
XL
31use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
32use crate::util::nodemap::FxHashMap;
33use crate::util::common::time;
1a4d82fc 34
e1599b0c
XL
35use errors::DiagnosticBuilder;
36use std::slice;
e74abb32 37use rustc_data_structures::sync::{self, ParallelIterator, join, par_iter};
e9174d1e 38use syntax::ast;
0731742a 39use syntax::util::lev_distance::find_best_match_for_name;
b039eaaf 40use syntax::visit as ast_visit;
e1599b0c 41use syntax_pos::{MultiSpan, Span, symbol::Symbol};
1a4d82fc 42
60c5eb7d
XL
43use rustc_error_codes::*;
44
1a4d82fc
JJ
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.
49pub struct LintStore {
60c5eb7d 50 /// Registered lints.
e74abb32 51 lints: Vec<&'static Lint>,
1a4d82fc 52
e74abb32
XL
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>>,
1a4d82fc
JJ
64
65 /// Lints indexed by name.
476ff2be 66 by_name: FxHashMap<String, TargetLint>,
1a4d82fc 67
0bf4aa26
XL
68 /// Map of registered lint groups to what lints they expand to.
69 lint_groups: FxHashMap<&'static str, LintGroup>,
7cac9316
XL
70}
71
3b2f2976
XL
72/// Lints that are buffered up early on in the `Session` before the
73/// `LintLevels` is calculated
60c5eb7d 74#[derive(PartialEq, Debug)]
3b2f2976
XL
75pub struct BufferedEarlyLint {
76 pub lint_id: LintId,
77 pub ast_id: ast::NodeId,
78 pub span: MultiSpan,
79 pub msg: String,
0531ce1d 80 pub diagnostic: BuiltinLintDiagnostics,
c30ab7b3
SL
81}
82
3b2f2976 83/// The target of the `by_name` map, which accounts for renaming/deprecation.
1a4d82fc
JJ
84enum TargetLint {
85 /// A direct lint target
86 Id(LintId),
87
88 /// Temporary renaming, used for easing migration pain; see #16545
89 Renamed(String, LintId),
c1a9b12d
SL
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
3b2f2976 96pub enum FindLintError {
c1a9b12d 97 NotFound,
cc61c64b 98 Removed,
1a4d82fc
JJ
99}
100
0bf4aa26
XL
101struct LintAlias {
102 name: &'static str,
103 /// Whether deprecation warnings should be suppressed for this alias.
104 silent: bool,
105}
106
107struct LintGroup {
108 lint_ids: Vec<LintId>,
109 from_plugin: bool,
110 depr: Option<LintAlias>,
111}
112
3b2f2976
XL
113pub enum CheckLintNameResult<'a> {
114 Ok(&'a [LintId]),
0731742a
XL
115 /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
116 NoLint(Option<Symbol>),
3b2f2976 117 /// The lint is either renamed or removed. This is the warning
8faf50e0
XL
118 /// message, and an optional new name (`None` if removed).
119 Warning(String, Option<String>),
b7449926
XL
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)>),
3b2f2976
XL
126}
127
1a4d82fc 128impl LintStore {
1a4d82fc
JJ
129 pub fn new() -> LintStore {
130 LintStore {
c30ab7b3 131 lints: vec![],
e74abb32
XL
132 pre_expansion_passes: vec![],
133 early_passes: vec![],
134 late_passes: vec![],
532ac7d7 135 late_module_passes: vec![],
0bf4aa26 136 by_name: Default::default(),
0bf4aa26 137 lint_groups: Default::default(),
1a4d82fc
JJ
138 }
139 }
140
e74abb32 141 pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
c34b1796 142 &self.lints
1a4d82fc
JJ
143 }
144
145 pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
0bf4aa26
XL
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()
1a4d82fc
JJ
155 }
156
e74abb32
XL
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));
b039eaaf
SL
162 }
163
8faf50e0
XL
164 pub fn register_pre_expansion_pass(
165 &mut self,
e74abb32 166 pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
8faf50e0 167 ) {
e74abb32 168 self.pre_expansion_passes.push(Box::new(pass));
8faf50e0
XL
169 }
170
e74abb32
XL
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));
b039eaaf
SL
183 }
184
185 // Helper method for register_early/late_pass
e74abb32
XL
186 pub fn register_lints(&mut self, lints: &[&'static Lint]) {
187 for lint in lints {
188 self.lints.push(lint);
1a4d82fc 189
8faf50e0 190 let id = LintId::of(lint);
1a4d82fc 191 if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
e74abb32 192 bug!("duplicate specification of lint {}", lint.name_lower())
1a4d82fc 193 }
1a4d82fc 194
e74abb32
XL
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 }
0531ce1d 205
e74abb32
XL
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);
0531ce1d 213 }
9cc50fc6 214 }
9cc50fc6
SL
215 }
216
0bf4aa26
XL
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
b7449926
XL
229 pub fn register_group(
230 &mut self,
b7449926
XL
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
0bf4aa26
XL
238 .insert(name, LintGroup {
239 lint_ids: to,
240 from_plugin,
241 depr: None,
242 })
b7449926
XL
243 .is_none();
244 if let Some(deprecated) = deprecated_name {
0bf4aa26
XL
245 self.lint_groups.insert(deprecated, LintGroup {
246 lint_ids: vec![],
247 from_plugin,
248 depr: Some(LintAlias { name, silent: false }),
249 });
b7449926 250 }
1a4d82fc
JJ
251
252 if !new {
e74abb32 253 bug!("duplicate specification of lint group {}", name);
1a4d82fc
JJ
254 }
255 }
256
c34b1796 257 pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
1a4d82fc
JJ
258 let target = match self.by_name.get(new_name) {
259 Some(&Id(lint_id)) => lint_id.clone(),
54a0048b 260 _ => bug!("invalid lint renaming of {} to {}", old_name, new_name)
1a4d82fc
JJ
261 };
262 self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
263 }
264
c1a9b12d
SL
265 pub fn register_removed(&mut self, name: &str, reason: &str) {
266 self.by_name.insert(name.into(), Removed(reason.into()));
267 }
268
0bf4aa26 269 pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
1a4d82fc 270 match self.by_name.get(lint_name) {
3b2f2976 271 Some(&Id(lint_id)) => Ok(vec![lint_id]),
92a42be0 272 Some(&Renamed(_, lint_id)) => {
3b2f2976 273 Ok(vec![lint_id])
c1a9b12d 274 },
041b39d2 275 Some(&Removed(_)) => {
c1a9b12d
SL
276 Err(FindLintError::Removed)
277 },
3b2f2976 278 None => {
0bf4aa26
XL
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 };
1a4d82fc
JJ
290 }
291 }
292 }
7cac9316 293 }
7cac9316 294
3b2f2976
XL
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) {
b7449926 300 let db = match self.check_lint_name(lint_name, None) {
3b2f2976 301 CheckLintNameResult::Ok(_) => None,
8faf50e0 302 CheckLintNameResult::Warning(ref msg, _) => {
3b2f2976
XL
303 Some(sess.struct_warn(msg))
304 },
0731742a
XL
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)
3b2f2976 313 }
b7449926
XL
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 },
3b2f2976 323 };
7cac9316 324
3b2f2976
XL
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();
7cac9316
XL
336 }
337 }
338
3b2f2976
XL
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.
b7449926
XL
346 pub fn check_lint_name(
347 &self,
348 lint_name: &str,
e1599b0c 349 tool_name: Option<Symbol>,
0bf4aa26 350 ) -> CheckLintNameResult<'_> {
b7449926
XL
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()))),
0bf4aa26
XL
361 Some(LintGroup { lint_ids, .. }) => {
362 return CheckLintNameResult::Tool(Ok(&lint_ids));
363 }
b7449926
XL
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"),
0bf4aa26 387 Some(LintGroup { lint_ids, depr, .. }) => {
b7449926 388 // Check if the lint group name is deprecated
0bf4aa26
XL
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 };
b7449926 399 }
0bf4aa26 400 CheckLintNameResult::Ok(&lint_ids)
b7449926 401 }
3b2f2976 402 },
b7449926
XL
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,
0bf4aa26 411 ) -> CheckLintNameResult<'_> {
b7449926
XL
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
0731742a
XL
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 }
0bf4aa26
XL
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 };
b7449926 438 }
0bf4aa26 439 CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
3b2f2976 440 }
b7449926
XL
441 },
442 Some(&Id(ref id)) => {
443 CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
c1a9b12d 444 }
0731742a 445 _ => CheckLintNameResult::NoLint(None),
c1a9b12d 446 }
1a4d82fc 447 }
1a4d82fc
JJ
448}
449
b039eaaf 450/// Context for lint checking after type checking.
dc9dc135 451pub struct LateContext<'a, 'tcx> {
1a4d82fc 452 /// Type context we're checking in.
dc9dc135 453 pub tcx: TyCtxt<'tcx>,
1a4d82fc 454
32a655c1 455 /// Side-tables for the body we are in.
532ac7d7 456 // FIXME: Make this lazy to avoid running the TypeckTables query?
32a655c1
SL
457 pub tables: &'a ty::TypeckTables<'tcx>,
458
041b39d2
XL
459 /// Parameter environment for the item we are in.
460 pub param_env: ty::ParamEnv<'tcx>,
1a4d82fc 461
92a42be0
SL
462 /// Items accessible from the crate being checked.
463 pub access_levels: &'a AccessLevels,
1a4d82fc 464
7cac9316 465 /// The store of registered lints and the lint levels.
e74abb32 466 lint_store: &'tcx LintStore,
3b2f2976 467
9fa01778 468 last_node_with_lint_attrs: hir::HirId,
abe05a73
XL
469
470 /// Generic type parameters in scope for the item we are in.
471 pub generics: Option<&'tcx hir::Generics>,
532ac7d7
XL
472
473 /// We are only looking at one module
474 only_module: bool,
475}
476
dc9dc135 477pub struct LateContextAndPass<'a, 'tcx, T: LateLintPass<'a, 'tcx>> {
532ac7d7
XL
478 context: LateContext<'a, 'tcx>,
479 pass: T,
1a4d82fc
JJ
480}
481
b039eaaf
SL
482/// Context for lint checking of the AST, after expansion, before lowering to
483/// HIR.
484pub 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
3b2f2976
XL
491 builder: LintLevelsBuilder<'a>,
492
7cac9316 493 /// The store of registered lints and the lint levels.
e74abb32 494 lint_store: &'a LintStore,
3b2f2976
XL
495
496 buffered: LintBuffer,
b039eaaf
SL
497}
498
9fa01778
XL
499pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
500 context: EarlyContext<'a>,
501 pass: T,
502}
503
8faf50e0 504pub trait LintPassObject: Sized {}
7cac9316 505
8faf50e0 506impl LintPassObject for EarlyLintPassObject {}
7cac9316 507
8faf50e0 508impl LintPassObject for LateLintPassObject {}
7cac9316 509
dc9dc135 510pub trait LintContext: Sized {
7cac9316
XL
511 type PassObject: LintPassObject;
512
b039eaaf
SL
513 fn sess(&self) -> &Session;
514 fn lints(&self) -> &LintStore;
1a4d82fc 515
476ff2be
SL
516 fn lookup_and_emit<S: Into<MultiSpan>>(&self,
517 lint: &'static Lint,
518 span: Option<S>,
519 msg: &str) {
3b2f2976 520 self.lookup(lint, span, msg).emit();
1a4d82fc
JJ
521 }
522
0531ce1d
XL
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
c30ab7b3
SL
533 fn lookup<S: Into<MultiSpan>>(&self,
534 lint: &'static Lint,
535 span: Option<S>,
536 msg: &str)
0bf4aa26 537 -> DiagnosticBuilder<'_>;
9cc50fc6 538
1a4d82fc 539 /// Emit a lint at the appropriate level, for a particular span.
476ff2be 540 fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
1a4d82fc
JJ
541 self.lookup_and_emit(lint, Some(span), msg);
542 }
543
c30ab7b3
SL
544 fn struct_span_lint<S: Into<MultiSpan>>(&self,
545 lint: &'static Lint,
546 span: S,
547 msg: &str)
0bf4aa26 548 -> DiagnosticBuilder<'_> {
9cc50fc6
SL
549 self.lookup(lint, Some(span), msg)
550 }
551
b039eaaf
SL
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) {
9cc50fc6 555 let mut err = self.lookup(lint, Some(span), msg);
3b2f2976
XL
556 if note_span == span {
557 err.note(note);
558 } else {
559 err.span_note(note_span, note);
b039eaaf 560 }
9cc50fc6 561 err.emit();
b039eaaf
SL
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) {
9cc50fc6 567 let mut err = self.lookup(lint, Some(span), msg);
b039eaaf 568 self.span_lint(lint, span, msg);
3b2f2976 569 err.span_help(span, help);
9cc50fc6 570 err.emit();
b039eaaf
SL
571 }
572
573 /// Emit a lint at the appropriate level, with no associated span.
574 fn lint(&self, lint: &'static Lint, msg: &str) {
476ff2be 575 self.lookup_and_emit(lint, None as Option<Span>, msg);
b039eaaf 576 }
b039eaaf
SL
577}
578
579
580impl<'a> EarlyContext<'a> {
8faf50e0
XL
581 fn new(
582 sess: &'a Session,
e74abb32 583 lint_store: &'a LintStore,
8faf50e0 584 krate: &'a ast::Crate,
8faf50e0 585 buffered: LintBuffer,
e74abb32 586 warn_about_weird_lints: bool,
8faf50e0 587 ) -> EarlyContext<'a> {
b039eaaf 588 EarlyContext {
041b39d2
XL
589 sess,
590 krate,
e74abb32
XL
591 lint_store,
592 builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store),
8faf50e0 593 buffered,
3b2f2976
XL
594 }
595 }
9fa01778 596}
3b2f2976 597
532ac7d7
XL
598macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
599 $cx.pass.$f(&$cx.context, $($args),*);
600}) }
601
9fa01778
XL
602macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
603 $cx.pass.$f(&$cx.context, $($args),*);
604}) }
605
606impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
3b2f2976 607 fn check_id(&mut self, id: ast::NodeId) {
9fa01778
XL
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 );
b039eaaf
SL
615 }
616 }
9fa01778
XL
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 {
e74abb32 627 let push = self.context.builder.push(attrs, &self.context.lint_store);
9fa01778
XL
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 }
b039eaaf
SL
644}
645
dc9dc135 646impl LintContext for LateContext<'_, '_> {
7cac9316
XL
647 type PassObject = LateLintPassObject;
648
9fa01778 649 /// Gets the overall compiler `Session` object.
b039eaaf
SL
650 fn sess(&self) -> &Session {
651 &self.tcx.sess
652 }
653
654 fn lints(&self) -> &LintStore {
532ac7d7 655 &*self.lint_store
b039eaaf
SL
656 }
657
3b2f2976
XL
658 fn lookup<S: Into<MultiSpan>>(&self,
659 lint: &'static Lint,
660 span: Option<S>,
661 msg: &str)
0bf4aa26 662 -> DiagnosticBuilder<'_> {
9fa01778
XL
663 let hir_id = self.last_node_with_lint_attrs;
664
3b2f2976 665 match span {
9fa01778
XL
666 Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg),
667 None => {
532ac7d7 668 self.tcx.struct_lint_node(lint, hir_id, msg)
9fa01778 669 },
3b2f2976
XL
670 }
671 }
b039eaaf
SL
672}
673
dc9dc135 674impl LintContext for EarlyContext<'_> {
7cac9316
XL
675 type PassObject = EarlyLintPassObject;
676
9fa01778 677 /// Gets the overall compiler `Session` object.
b039eaaf
SL
678 fn sess(&self) -> &Session {
679 &self.sess
680 }
681
682 fn lints(&self) -> &LintStore {
532ac7d7 683 &*self.lint_store
b039eaaf
SL
684 }
685
3b2f2976
XL
686 fn lookup<S: Into<MultiSpan>>(&self,
687 lint: &'static Lint,
688 span: Option<S>,
689 msg: &str)
0bf4aa26 690 -> DiagnosticBuilder<'_> {
3b2f2976
XL
691 self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
692 }
9fa01778 693}
3b2f2976 694
9fa01778 695impl<'a, 'tcx> LateContext<'a, 'tcx> {
532ac7d7
XL
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.
48663c56 701 ///
60c5eb7d
XL
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 ///
48663c56
XL
705 /// # Examples
706 ///
707 /// ```rust,ignore (no context or def id available)
dc9dc135 708 /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) {
48663c56
XL
709 /// // The given `def_id` is that of an `Option` type
710 /// }
711 /// ```
dc9dc135 712 pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool {
48663c56
XL
713 let names = self.get_def_path(def_id);
714
dc9dc135 715 names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b)
48663c56
XL
716 }
717
dc9dc135 718 /// Gets the absolute path of `def_id` as a vector of `Symbol`.
48663c56
XL
719 ///
720 /// # Examples
721 ///
722 /// ```rust,ignore (no context or def id available)
723 /// let def_path = cx.get_def_path(def_id);
dc9dc135 724 /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] {
48663c56
XL
725 /// // The given `def_id` is that of an `Option` type
726 /// }
727 /// ```
dc9dc135
XL
728 pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
729 pub struct AbsolutePathPrinter<'tcx> {
730 pub tcx: TyCtxt<'tcx>,
532ac7d7
XL
731 }
732
dc9dc135 733 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
532ac7d7
XL
734 type Error = !;
735
dc9dc135 736 type Path = Vec<Symbol>;
532ac7d7
XL
737 type Region = ();
738 type Type = ();
739 type DynExistential = ();
dc9dc135 740 type Const = ();
532ac7d7 741
dc9dc135 742 fn tcx(&self) -> TyCtxt<'tcx> {
532ac7d7
XL
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>>,
dc9dc135
XL
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> {
532ac7d7
XL
765 Ok(())
766 }
767
768 fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
dc9dc135 769 Ok(vec![self.tcx.original_crate_name(cnum)])
532ac7d7
XL
770 }
771
772 fn path_qualified(
773 self,
774 self_ty: Ty<'tcx>,
775 trait_ref: Option<ty::TraitRef<'tcx>>,
dc9dc135 776 ) -> Result<Self::Path, Self::Error> {
532ac7d7 777 if trait_ref.is_none() {
e74abb32 778 if let ty::Adt(def, substs) = self_ty.kind {
532ac7d7
XL
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 {
dc9dc135
XL
785 Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)),
786 None => Symbol::intern(&format!("<{}>", self_ty)),
532ac7d7
XL
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>>,
dc9dc135 796 ) -> Result<Self::Path, Self::Error> {
532ac7d7
XL
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) => {
60c5eb7d
XL
802 Symbol::intern(
803 &format!(
804 "<impl {} for {}>",
805 trait_ref.print_only_trait_path(),
806 self_ty
807 )
808 )
532ac7d7 809 },
dc9dc135 810 None => Symbol::intern(&format!("<impl {}>", self_ty)),
532ac7d7
XL
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,
dc9dc135 820 ) -> Result<Self::Path, Self::Error> {
532ac7d7
XL
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
e74abb32 829 path.push(disambiguated_data.data.as_symbol());
532ac7d7
XL
830 Ok(path)
831 }
832
833 fn path_generic_args(
834 self,
835 print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
e74abb32 836 _args: &[GenericArg<'tcx>],
dc9dc135 837 ) -> Result<Self::Path, Self::Error> {
532ac7d7
XL
838 print_prefix(self)
839 }
840 }
841
48663c56
XL
842 AbsolutePathPrinter { tcx: self.tcx }
843 .print_def_path(def_id, &[])
844 .unwrap()
532ac7d7
XL
845 }
846}
847
848impl<'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
857impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> {
9fa01778
XL
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.
3b2f2976 861 fn with_lint_attrs<F>(&mut self,
9fa01778
XL
862 id: hir::HirId,
863 attrs: &'tcx [ast::Attribute],
3b2f2976
XL
864 f: F)
865 where F: FnOnce(&mut Self)
866 {
532ac7d7
XL
867 let prev = self.context.last_node_with_lint_attrs;
868 self.context.last_node_with_lint_attrs = id;
3b2f2976
XL
869 self.enter_attrs(attrs);
870 f(self);
871 self.exit_attrs(attrs);
532ac7d7 872 self.context.last_node_with_lint_attrs = prev;
9fa01778
XL
873 }
874
532ac7d7 875 fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
041b39d2
XL
876 where F: FnOnce(&mut Self),
877 {
532ac7d7
XL
878 let old_param_env = self.context.param_env;
879 self.context.param_env = self.context.tcx.param_env(
416331ca 880 self.context.tcx.hir().local_def_id(id)
532ac7d7 881 );
041b39d2 882 f(self);
532ac7d7 883 self.context.param_env = old_param_env;
041b39d2 884 }
532ac7d7
XL
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);
94b46f34 890 }
041b39d2 891
532ac7d7
XL
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 }
ff7c6d11 896
532ac7d7
XL
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);
ff7c6d11
XL
900 }
901}
902
532ac7d7
XL
903impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx>
904for LateContextAndPass<'a, 'tcx, T> {
92a42be0
SL
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.
476ff2be 908 fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
532ac7d7 909 hir_visit::NestedVisitorMap::All(&self.context.tcx.hir())
32a655c1
SL
910 }
911
32a655c1 912 fn visit_nested_body(&mut self, body: hir::BodyId) {
532ac7d7
XL
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);
32a655c1 916 self.visit_body(body);
532ac7d7 917 self.context.tables = old_tables;
92a42be0
SL
918 }
919
e1599b0c
XL
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);
416331ca
XL
924 });
925 }
926
8bb4bdeb 927 fn visit_body(&mut self, body: &'tcx hir::Body) {
532ac7d7 928 lint_callback!(self, check_body, body);
8bb4bdeb 929 hir_visit::walk_body(self, body);
532ac7d7 930 lint_callback!(self, check_body_post, body);
8bb4bdeb
XL
931 }
932
476ff2be 933 fn visit_item(&mut self, it: &'tcx hir::Item) {
532ac7d7 934 let generics = self.context.generics.take();
e74abb32 935 self.context.generics = it.kind.generics();
9fa01778 936 self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
532ac7d7
XL
937 cx.with_param_env(it.hir_id, |cx| {
938 lint_callback!(cx, check_item, it);
041b39d2 939 hir_visit::walk_item(cx, it);
532ac7d7 940 lint_callback!(cx, check_item_post, it);
041b39d2 941 });
abe05a73 942 });
532ac7d7 943 self.context.generics = generics;
1a4d82fc
JJ
944 }
945
476ff2be 946 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
9fa01778 947 self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
532ac7d7
XL
948 cx.with_param_env(it.hir_id, |cx| {
949 lint_callback!(cx, check_foreign_item, it);
041b39d2 950 hir_visit::walk_foreign_item(cx, it);
532ac7d7 951 lint_callback!(cx, check_foreign_item_post, it);
041b39d2 952 });
1a4d82fc
JJ
953 })
954 }
955
476ff2be 956 fn visit_pat(&mut self, p: &'tcx hir::Pat) {
532ac7d7 957 lint_callback!(self, check_pat, p);
b039eaaf 958 hir_visit::walk_pat(self, p);
1a4d82fc
JJ
959 }
960
476ff2be 961 fn visit_expr(&mut self, e: &'tcx hir::Expr) {
9fa01778 962 self.with_lint_attrs(e.hir_id, &e.attrs, |cx| {
532ac7d7 963 lint_callback!(cx, check_expr, e);
92a42be0 964 hir_visit::walk_expr(cx, e);
532ac7d7 965 lint_callback!(cx, check_expr_post, e);
92a42be0 966 })
1a4d82fc
JJ
967 }
968
476ff2be 969 fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
92a42be0
SL
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
532ac7d7 975 lint_callback!(self, check_stmt, s);
b039eaaf 976 hir_visit::walk_stmt(self, s);
1a4d82fc
JJ
977 }
978
476ff2be 979 fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
9fa01778 980 body_id: hir::BodyId, span: Span, id: hir::HirId) {
32a655c1
SL
981 // Wrap in tables here, not just in visit_nested_body,
982 // in order for `check_fn` to be able to use them.
532ac7d7
XL
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);
476ff2be 987 hir_visit::walk_fn(self, fk, decl, body_id, span, id);
532ac7d7
XL
988 lint_callback!(self, check_fn_post, fk, decl, body, span, id);
989 self.context.tables = old_tables;
1a4d82fc
JJ
990 }
991
b039eaaf 992 fn visit_variant_data(&mut self,
476ff2be 993 s: &'tcx hir::VariantData,
e1599b0c
XL
994 _: ast::Name,
995 _: &'tcx hir::Generics,
996 _: hir::HirId,
b039eaaf 997 _: Span) {
e1599b0c 998 lint_callback!(self, check_struct_def, s);
b039eaaf 999 hir_visit::walk_struct_def(self, s);
e1599b0c 1000 lint_callback!(self, check_struct_def_post, s);
1a4d82fc
JJ
1001 }
1002
476ff2be 1003 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
9fa01778 1004 self.with_lint_attrs(s.hir_id, &s.attrs, |cx| {
532ac7d7 1005 lint_callback!(cx, check_struct_field, s);
b039eaaf 1006 hir_visit::walk_struct_field(cx, s);
1a4d82fc
JJ
1007 })
1008 }
1009
476ff2be
SL
1010 fn visit_variant(&mut self,
1011 v: &'tcx hir::Variant,
1012 g: &'tcx hir::Generics,
9fa01778 1013 item_id: hir::HirId) {
e1599b0c
XL
1014 self.with_lint_attrs(v.id, &v.attrs, |cx| {
1015 lint_callback!(cx, check_variant, v);
b039eaaf 1016 hir_visit::walk_variant(cx, v, g, item_id);
e1599b0c 1017 lint_callback!(cx, check_variant_post, v);
1a4d82fc
JJ
1018 })
1019 }
1020
476ff2be 1021 fn visit_ty(&mut self, t: &'tcx hir::Ty) {
532ac7d7 1022 lint_callback!(self, check_ty, t);
b039eaaf 1023 hir_visit::walk_ty(self, t);
1a4d82fc
JJ
1024 }
1025
b039eaaf 1026 fn visit_name(&mut self, sp: Span, name: ast::Name) {
532ac7d7 1027 lint_callback!(self, check_name, sp, name);
1a4d82fc
JJ
1028 }
1029
9fa01778 1030 fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) {
532ac7d7
XL
1031 if !self.context.only_module {
1032 self.process_mod(m, s, n);
1033 }
1a4d82fc
JJ
1034 }
1035
476ff2be 1036 fn visit_local(&mut self, l: &'tcx hir::Local) {
9fa01778 1037 self.with_lint_attrs(l.hir_id, &l.attrs, |cx| {
532ac7d7 1038 lint_callback!(cx, check_local, l);
92a42be0
SL
1039 hir_visit::walk_local(cx, l);
1040 })
1a4d82fc
JJ
1041 }
1042
476ff2be 1043 fn visit_block(&mut self, b: &'tcx hir::Block) {
532ac7d7 1044 lint_callback!(self, check_block, b);
b039eaaf 1045 hir_visit::walk_block(self, b);
532ac7d7 1046 lint_callback!(self, check_block_post, b);
1a4d82fc
JJ
1047 }
1048
476ff2be 1049 fn visit_arm(&mut self, a: &'tcx hir::Arm) {
532ac7d7 1050 lint_callback!(self, check_arm, a);
b039eaaf 1051 hir_visit::walk_arm(self, a);
1a4d82fc
JJ
1052 }
1053
ff7c6d11 1054 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
532ac7d7 1055 lint_callback!(self, check_generic_param, p);
ff7c6d11
XL
1056 hir_visit::walk_generic_param(self, p);
1057 }
1058
476ff2be 1059 fn visit_generics(&mut self, g: &'tcx hir::Generics) {
532ac7d7 1060 lint_callback!(self, check_generics, g);
b039eaaf 1061 hir_visit::walk_generics(self, g);
1a4d82fc
JJ
1062 }
1063
0531ce1d 1064 fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) {
532ac7d7 1065 lint_callback!(self, check_where_predicate, p);
0531ce1d
XL
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) {
532ac7d7 1071 lint_callback!(self, check_poly_trait_ref, t, m);
0531ce1d
XL
1072 hir_visit::walk_poly_trait_ref(self, t, m);
1073 }
1074
476ff2be 1075 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
532ac7d7
XL
1076 let generics = self.context.generics.take();
1077 self.context.generics = Some(&trait_item.generics);
9fa01778 1078 self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| {
532ac7d7
XL
1079 cx.with_param_env(trait_item.hir_id, |cx| {
1080 lint_callback!(cx, check_trait_item, trait_item);
041b39d2 1081 hir_visit::walk_trait_item(cx, trait_item);
532ac7d7 1082 lint_callback!(cx, check_trait_item_post, trait_item);
041b39d2 1083 });
c34b1796 1084 });
532ac7d7 1085 self.context.generics = generics;
c34b1796
AL
1086 }
1087
476ff2be 1088 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
532ac7d7
XL
1089 let generics = self.context.generics.take();
1090 self.context.generics = Some(&impl_item.generics);
9fa01778 1091 self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| {
532ac7d7
XL
1092 cx.with_param_env(impl_item.hir_id, |cx| {
1093 lint_callback!(cx, check_impl_item, impl_item);
041b39d2 1094 hir_visit::walk_impl_item(cx, impl_item);
532ac7d7 1095 lint_callback!(cx, check_impl_item_post, impl_item);
041b39d2 1096 });
c34b1796 1097 });
532ac7d7 1098 self.context.generics = generics;
1a4d82fc
JJ
1099 }
1100
476ff2be 1101 fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
532ac7d7 1102 lint_callback!(self, check_lifetime, lt);
32a655c1 1103 hir_visit::walk_lifetime(self, lt);
1a4d82fc
JJ
1104 }
1105
b7449926 1106 fn visit_path(&mut self, p: &'tcx hir::Path, id: hir::HirId) {
532ac7d7 1107 lint_callback!(self, check_path, p, id);
b039eaaf
SL
1108 hir_visit::walk_path(self, p);
1109 }
1110
476ff2be 1111 fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
532ac7d7 1112 lint_callback!(self, check_attribute, attr);
b039eaaf
SL
1113 }
1114}
1115
9fa01778 1116impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> {
e1599b0c
XL
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);
416331ca
XL
1121 });
1122 }
1123
476ff2be 1124 fn visit_item(&mut self, it: &'a ast::Item) {
3b2f2976 1125 self.with_lint_attrs(it.id, &it.attrs, |cx| {
9fa01778 1126 run_early_pass!(cx, check_item, it);
b039eaaf 1127 ast_visit::walk_item(cx, it);
9fa01778 1128 run_early_pass!(cx, check_item_post, it);
b039eaaf
SL
1129 })
1130 }
1131
476ff2be 1132 fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
3b2f2976 1133 self.with_lint_attrs(it.id, &it.attrs, |cx| {
9fa01778 1134 run_early_pass!(cx, check_foreign_item, it);
b039eaaf 1135 ast_visit::walk_foreign_item(cx, it);
9fa01778 1136 run_early_pass!(cx, check_foreign_item_post, it);
b039eaaf
SL
1137 })
1138 }
1139
476ff2be 1140 fn visit_pat(&mut self, p: &'a ast::Pat) {
48663c56 1141 run_early_pass!(self, check_pat, p);
3b2f2976 1142 self.check_id(p.id);
48663c56
XL
1143 ast_visit::walk_pat(self, p);
1144 run_early_pass!(self, check_pat_post, p);
b039eaaf
SL
1145 }
1146
476ff2be 1147 fn visit_expr(&mut self, e: &'a ast::Expr) {
3b2f2976 1148 self.with_lint_attrs(e.id, &e.attrs, |cx| {
9fa01778 1149 run_early_pass!(cx, check_expr, e);
7453a54e
SL
1150 ast_visit::walk_expr(cx, e);
1151 })
b039eaaf
SL
1152 }
1153
476ff2be 1154 fn visit_stmt(&mut self, s: &'a ast::Stmt) {
9fa01778 1155 run_early_pass!(self, check_stmt, s);
3b2f2976 1156 self.check_id(s.id);
b039eaaf
SL
1157 ast_visit::walk_stmt(self, s);
1158 }
1159
476ff2be
SL
1160 fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl,
1161 span: Span, id: ast::NodeId) {
9fa01778 1162 run_early_pass!(self, check_fn, fk, decl, span, id);
3b2f2976 1163 self.check_id(id);
476ff2be 1164 ast_visit::walk_fn(self, fk, decl, span);
9fa01778 1165 run_early_pass!(self, check_fn_post, fk, decl, span, id);
b039eaaf
SL
1166 }
1167
e1599b0c
XL
1168 fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
1169 run_early_pass!(self, check_struct_def, s);
532ac7d7
XL
1170 if let Some(ctor_hir_id) = s.ctor_id() {
1171 self.check_id(ctor_hir_id);
1172 }
b039eaaf 1173 ast_visit::walk_struct_def(self, s);
e1599b0c 1174 run_early_pass!(self, check_struct_def_post, s);
b039eaaf
SL
1175 }
1176
476ff2be 1177 fn visit_struct_field(&mut self, s: &'a ast::StructField) {
3b2f2976 1178 self.with_lint_attrs(s.id, &s.attrs, |cx| {
9fa01778 1179 run_early_pass!(cx, check_struct_field, s);
b039eaaf
SL
1180 ast_visit::walk_struct_field(cx, s);
1181 })
1182 }
1183
e1599b0c
XL
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);
b039eaaf
SL
1189 })
1190 }
1191
476ff2be 1192 fn visit_ty(&mut self, t: &'a ast::Ty) {
9fa01778 1193 run_early_pass!(self, check_ty, t);
3b2f2976 1194 self.check_id(t.id);
b039eaaf
SL
1195 ast_visit::walk_ty(self, t);
1196 }
1197
83c7162d 1198 fn visit_ident(&mut self, ident: ast::Ident) {
9fa01778 1199 run_early_pass!(self, check_ident, ident);
b039eaaf
SL
1200 }
1201
7cac9316 1202 fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
9fa01778 1203 run_early_pass!(self, check_mod, m, s, n);
3b2f2976 1204 self.check_id(n);
b039eaaf 1205 ast_visit::walk_mod(self, m);
9fa01778 1206 run_early_pass!(self, check_mod_post, m, s, n);
b039eaaf
SL
1207 }
1208
476ff2be 1209 fn visit_local(&mut self, l: &'a ast::Local) {
3b2f2976 1210 self.with_lint_attrs(l.id, &l.attrs, |cx| {
9fa01778 1211 run_early_pass!(cx, check_local, l);
7453a54e
SL
1212 ast_visit::walk_local(cx, l);
1213 })
b039eaaf
SL
1214 }
1215
476ff2be 1216 fn visit_block(&mut self, b: &'a ast::Block) {
9fa01778 1217 run_early_pass!(self, check_block, b);
3b2f2976 1218 self.check_id(b.id);
b039eaaf 1219 ast_visit::walk_block(self, b);
9fa01778 1220 run_early_pass!(self, check_block_post, b);
b039eaaf
SL
1221 }
1222
476ff2be 1223 fn visit_arm(&mut self, a: &'a ast::Arm) {
9fa01778 1224 run_early_pass!(self, check_arm, a);
b039eaaf
SL
1225 ast_visit::walk_arm(self, a);
1226 }
1227
476ff2be 1228 fn visit_expr_post(&mut self, e: &'a ast::Expr) {
9fa01778 1229 run_early_pass!(self, check_expr_post, e);
b039eaaf
SL
1230 }
1231
ff7c6d11 1232 fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
9fa01778 1233 run_early_pass!(self, check_generic_param, param);
ff7c6d11
XL
1234 ast_visit::walk_generic_param(self, param);
1235 }
1236
476ff2be 1237 fn visit_generics(&mut self, g: &'a ast::Generics) {
9fa01778 1238 run_early_pass!(self, check_generics, g);
b039eaaf
SL
1239 ast_visit::walk_generics(self, g);
1240 }
1241
0531ce1d 1242 fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
9fa01778 1243 run_early_pass!(self, check_where_predicate, p);
0531ce1d
XL
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) {
9fa01778 1248 run_early_pass!(self, check_poly_trait_ref, t, m);
0531ce1d
XL
1249 ast_visit::walk_poly_trait_ref(self, t, m);
1250 }
1251
476ff2be 1252 fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
3b2f2976 1253 self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
9fa01778 1254 run_early_pass!(cx, check_trait_item, trait_item);
b039eaaf 1255 ast_visit::walk_trait_item(cx, trait_item);
9fa01778 1256 run_early_pass!(cx, check_trait_item_post, trait_item);
b039eaaf
SL
1257 });
1258 }
1259
476ff2be 1260 fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
3b2f2976 1261 self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
9fa01778 1262 run_early_pass!(cx, check_impl_item, impl_item);
b039eaaf 1263 ast_visit::walk_impl_item(cx, impl_item);
9fa01778 1264 run_early_pass!(cx, check_impl_item_post, impl_item);
b039eaaf
SL
1265 });
1266 }
1267
476ff2be 1268 fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
9fa01778 1269 run_early_pass!(self, check_lifetime, lt);
3b2f2976 1270 self.check_id(lt.id);
b039eaaf
SL
1271 }
1272
476ff2be 1273 fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
9fa01778 1274 run_early_pass!(self, check_path, p, id);
3b2f2976 1275 self.check_id(id);
b039eaaf
SL
1276 ast_visit::walk_path(self, p);
1277 }
1278
476ff2be 1279 fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
9fa01778 1280 run_early_pass!(self, check_attribute, attr);
1a4d82fc 1281 }
7cac9316 1282
8faf50e0 1283 fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) {
9fa01778 1284 run_early_pass!(self, check_mac_def, mac, id);
3b2f2976 1285 self.check_id(id);
92a42be0 1286 }
8faf50e0 1287
b7449926
XL
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
e1599b0c 1294 ast_visit::walk_path(self, &mac.path);
b7449926 1295
9fa01778 1296 run_early_pass!(self, check_mac, mac);
8faf50e0 1297 }
92a42be0
SL
1298}
1299
532ac7d7
XL
1300struct LateLintPassObjects<'a> {
1301 lints: &'a mut [LateLintPassObject],
1302}
92a42be0 1303
e1599b0c 1304#[allow(rustc::lint_pass_impl_without_macro)]
532ac7d7
XL
1305impl LintPass for LateLintPassObjects<'_> {
1306 fn name(&self) -> &'static str {
1307 panic!()
1308 }
532ac7d7
XL
1309}
1310
1311macro_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
1321macro_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
1329late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
1330
1331fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
dc9dc135 1332 tcx: TyCtxt<'tcx>,
532ac7d7
XL
1333 module_def_id: DefId,
1334 pass: T,
1335) {
7cac9316 1336 let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
cc61c64b 1337
532ac7d7
XL
1338 let context = LateContext {
1339 tcx,
1340 tables: &ty::TypeckTables::empty(None),
1341 param_env: ty::ParamEnv::empty(),
1342 access_levels,
e74abb32 1343 lint_store: &tcx.lint_store,
532ac7d7
XL
1344 last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
1345 generics: None,
1346 only_module: true,
1347 };
32a655c1 1348
532ac7d7
XL
1349 let mut cx = LateContextAndPass {
1350 context,
1351 pass
1352 };
1a4d82fc 1353
532ac7d7
XL
1354 let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
1355 cx.process_mod(module, span, hir_id);
7453a54e 1356
532ac7d7
XL
1357 // Visit the crate attributes
1358 if hir_id == hir::CRATE_HIR_ID {
dc9dc135 1359 walk_list!(cx, visit_attribute, tcx.hir().attrs(hir::CRATE_HIR_ID));
532ac7d7
XL
1360 }
1361}
1362
1363pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
dc9dc135 1364 tcx: TyCtxt<'tcx>,
532ac7d7
XL
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
e74abb32
XL
1375 let mut passes: Vec<_> = tcx.lint_store.late_module_passes
1376 .iter().map(|pass| (pass)()).collect();
532ac7d7
XL
1377
1378 if !passes.is_empty() {
1379 late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
1380 }
1381}
1382
dc9dc135 1383fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
532ac7d7
XL
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,
e74abb32 1393 lint_store: &tcx.lint_store,
532ac7d7
XL
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
8faf50e0 1402 };
1a4d82fc 1403
532ac7d7
XL
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
dc9dc135 1416fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
e74abb32
XL
1417 let mut passes = tcx.lint_store
1418 .late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
532ac7d7
XL
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
e74abb32
XL
1433 let mut passes: Vec<_> = tcx.lint_store.late_module_passes
1434 .iter().map(|pass| (pass)()).collect();
532ac7d7
XL
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 }
532ac7d7
XL
1442}
1443
1444/// Performs lint checking on a crate.
1445pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
dc9dc135 1446 tcx: TyCtxt<'tcx>,
532ac7d7
XL
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, _)| {
e74abb32 1458 tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
532ac7d7
XL
1459 });
1460 });
1461 });
1a4d82fc 1462}
b039eaaf 1463
9fa01778
XL
1464struct EarlyLintPassObjects<'a> {
1465 lints: &'a mut [EarlyLintPassObject],
1466}
1467
e1599b0c 1468#[allow(rustc::lint_pass_impl_without_macro)]
9fa01778
XL
1469impl LintPass for EarlyLintPassObjects<'_> {
1470 fn name(&self) -> &'static str {
1471 panic!()
1472 }
9fa01778
XL
1473}
1474
1475macro_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
1485macro_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
1493early_lint_methods!(early_lint_pass_impl, []);
1494
9fa01778
XL
1495fn early_lint_crate<T: EarlyLintPass>(
1496 sess: &Session,
e74abb32 1497 lint_store: &LintStore,
9fa01778
XL
1498 krate: &ast::Crate,
1499 pass: T,
1500 buffered: LintBuffer,
e74abb32 1501 warn_about_weird_lints: bool,
9fa01778
XL
1502) -> LintBuffer {
1503 let mut cx = EarlyContextAndPass {
e74abb32 1504 context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints),
9fa01778
XL
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
1521pub fn check_ast_crate<T: EarlyLintPass>(
8faf50e0 1522 sess: &Session,
e74abb32 1523 lint_store: &LintStore,
8faf50e0
XL
1524 krate: &ast::Crate,
1525 pre_expansion: bool,
e74abb32 1526 lint_buffer: Option<LintBuffer>,
9fa01778 1527 builtin_lints: T,
8faf50e0 1528) {
e74abb32
XL
1529 let mut passes: Vec<_> = if pre_expansion {
1530 lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect()
8faf50e0 1531 } else {
e74abb32 1532 lint_store.early_passes.iter().map(|p| (p)()).collect()
8faf50e0 1533 };
e74abb32 1534 let mut buffered = lint_buffer.unwrap_or_default();
b039eaaf 1535
9fa01778 1536 if !sess.opts.debugging_opts.no_interleave_lints {
e74abb32
XL
1537 buffered = early_lint_crate(sess, lint_store, krate, builtin_lints, buffered,
1538 pre_expansion);
7453a54e 1539
9fa01778
XL
1540 if !passes.is_empty() {
1541 buffered = early_lint_crate(
1542 sess,
e74abb32 1543 lint_store,
9fa01778
XL
1544 krate,
1545 EarlyLintPassObjects { lints: &mut passes[..] },
1546 buffered,
e74abb32 1547 pre_expansion,
9fa01778
XL
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,
e74abb32 1555 lint_store,
9fa01778
XL
1556 krate,
1557 EarlyLintPassObjects { lints: slice::from_mut(pass) },
1558 buffered,
e74abb32 1559 pre_expansion,
9fa01778
XL
1560 )
1561 });
1562 }
1563 }
b039eaaf 1564
ff7c6d11
XL
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
0731742a 1571 // node ids to not exist (e.g., macros defined within functions for the
ff7c6d11
XL
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 {
8faf50e0 1575 for (_id, lints) in buffered.map {
ff7c6d11 1576 for early_lint in lints {
0531ce1d 1577 sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
ff7c6d11 1578 }
b039eaaf
SL
1579 }
1580 }
1581}