]> git.proxmox.com Git - rustc.git/blob - src/librustc/lint/context.rs
New upstream version 1.41.1+dfsg1
[rustc.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::TraitItem) {
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::ImplItem) {
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 }