1 //! Implementation of lint checking.
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.
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.
17 use self::TargetLint
::*;
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
;
35 use errors
::DiagnosticBuilder
;
37 use rustc_data_structures
::sync
::{self, ParallelIterator, join, par_iter}
;
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}
;
43 use rustc_error_codes
::*;
45 /// Information about the registered lints.
47 /// This is basically the subset of `Context` that we can
48 /// build early in the compile pipeline.
49 pub struct LintStore
{
51 lints
: Vec
<&'
static Lint
>,
53 /// Constructor functions for each variety of lint pass.
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
>>,
65 /// Lints indexed by name.
66 by_name
: FxHashMap
<String
, TargetLint
>,
68 /// Map of registered lint groups to what lints they expand to.
69 lint_groups
: FxHashMap
<&'
static str, LintGroup
>,
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
{
77 pub ast_id
: ast
::NodeId
,
80 pub diagnostic
: BuiltinLintDiagnostics
,
83 /// The target of the `by_name` map, which accounts for renaming/deprecation.
85 /// A direct lint target
88 /// Temporary renaming, used for easing migration pain; see #16545
89 Renamed(String
, LintId
),
91 /// Lint with this name existed previously, but has been removed/deprecated.
92 /// The string argument is the reason for removal.
96 pub enum FindLintError
{
103 /// Whether deprecation warnings should be suppressed for this alias.
108 lint_ids
: Vec
<LintId
>,
110 depr
: Option
<LintAlias
>,
113 pub enum CheckLintNameResult
<'a
> {
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
)>),
129 pub fn new() -> LintStore
{
132 pre_expansion_passes
: vec
![],
133 early_passes
: vec
![],
135 late_module_passes
: vec
![],
136 by_name
: Default
::default(),
137 lint_groups
: Default
::default(),
141 pub fn get_lints
<'t
>(&'t
self) -> &'t
[&'
static Lint
] {
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.
151 .map(|(k
, LintGroup { lint_ids, from_plugin, .. }
)| {
152 (*k
, lint_ids
.clone(), *from_plugin
)
157 pub fn register_early_pass(
159 pass
: impl Fn() -> EarlyLintPassObject
+ '
static + sync
::Send
+ sync
::Sync
161 self.early_passes
.push(Box
::new(pass
));
164 pub fn register_pre_expansion_pass(
166 pass
: impl Fn() -> EarlyLintPassObject
+ '
static + sync
::Send
+ sync
::Sync
,
168 self.pre_expansion_passes
.push(Box
::new(pass
));
171 pub fn register_late_pass(
173 pass
: impl Fn() -> LateLintPassObject
+ '
static + sync
::Send
+ sync
::Sync
,
175 self.late_passes
.push(Box
::new(pass
));
178 pub fn register_late_mod_pass(
180 pass
: impl Fn() -> LateLintPassObject
+ '
static + sync
::Send
+ sync
::Sync
,
182 self.late_module_passes
.push(Box
::new(pass
));
185 // Helper method for register_early/late_pass
186 pub fn register_lints(&mut self, lints
: &[&'
static Lint
]) {
188 self.lints
.push(lint
);
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())
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
{
200 from_plugin
: lint
.is_plugin
,
206 self.lint_groups
.entry("future_incompatible")
207 .or_insert(LintGroup
{
209 from_plugin
: lint
.is_plugin
,
217 pub fn register_group_alias(
219 lint_name
: &'
static str,
222 self.lint_groups
.insert(alias
, LintGroup
{
225 depr
: Some(LintAlias { name: lint_name, silent: true }
),
229 pub fn register_group(
233 deprecated_name
: Option
<&'
static str>,
238 .insert(name
, LintGroup
{
244 if let Some(deprecated
) = deprecated_name
{
245 self.lint_groups
.insert(deprecated
, LintGroup
{
248 depr
: Some(LintAlias { name, silent: false }
),
253 bug
!("duplicate specification of lint group {}", name
);
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
)
262 self.by_name
.insert(old_name
.to_string(), Renamed(new_name
.to_string(), target
));
265 pub fn register_removed(&mut self, name
: &str, reason
: &str) {
266 self.by_name
.insert(name
.into(), Removed(reason
.into()));
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
)) => {
275 Some(&Removed(_
)) => {
276 Err(FindLintError
::Removed
)
280 return match self.lint_groups
.get(lint_name
) {
281 Some(LintGroup {lint_ids, depr, .. }
) => {
282 if let Some(LintAlias { name, .. }
) = depr
{
288 None
=> Err(FindLintError
::Removed
)
295 /// Checks the validity of lint names derived from the command line
296 pub fn check_lint_name_cmdline(&self,
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
))
305 CheckLintNameResult
::NoLint(suggestion
) => {
306 let mut err
= struct_err
!(sess
, E0602
, "unknown lint: `{}`", lint_name
);
308 if let Some(suggestion
) = suggestion
{
309 err
.help(&format
!("did you mean: `{}`", suggestion
));
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. \
325 if let Some(mut db
) = db
{
326 let msg
= format
!("requested on the command line with `{} {}`",
328 Level
::Allow
=> "-A",
331 Level
::Forbid
=> "-F",
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(
349 tool_name
: Option
<Symbol
>,
350 ) -> CheckLintNameResult
<'_
> {
351 let complete_name
= if let Some(tool_name
) = tool_name
{
352 format
!("{}::{}", tool_name
, lint_name
)
354 lint_name
.to_string()
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
));
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.
371 match self.by_name
.get(&complete_name
) {
372 Some(&Renamed(ref new_name
, _
)) => CheckLintNameResult
::Warning(
374 "lint `{}` has been renamed to `{}`",
375 complete_name
, new_name
377 Some(new_name
.to_owned()),
379 Some(&Removed(ref reason
)) => CheckLintNameResult
::Warning(
380 format
!("lint `{}` has been removed: `{}`", complete_name
, reason
),
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();
392 CheckLintNameResult
::Ok(&lint_ids
)
394 CheckLintNameResult
::Tool(Err((
400 CheckLintNameResult
::Ok(&lint_ids
)
403 Some(&Id(ref id
)) => CheckLintNameResult
::Ok(slice
::from_ref(id
)),
407 fn check_tool_name_for_backwards_compat(
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
417 let symbols
= self.by_name
.keys()
418 .map(|name
| Symbol
::intern(&name
))
419 .collect
::<Vec
<_
>>();
422 find_best_match_for_name(symbols
.iter(), &lint_name
.to_lowercase(), None
);
424 CheckLintNameResult
::NoLint(suggestion
)
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();
431 CheckLintNameResult
::Tool(Err((Some(&lint_ids
), complete_name
)))
433 CheckLintNameResult
::Tool(Err((
439 CheckLintNameResult
::Tool(Err((Some(&lint_ids
), complete_name
)))
442 Some(&Id(ref id
)) => {
443 CheckLintNameResult
::Tool(Err((Some(slice
::from_ref(id
)), complete_name
)))
445 _
=> CheckLintNameResult
::NoLint(None
),
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
>,
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
>,
459 /// Parameter environment for the item we are in.
460 pub param_env
: ty
::ParamEnv
<'tcx
>,
462 /// Items accessible from the crate being checked.
463 pub access_levels
: &'a AccessLevels
,
465 /// The store of registered lints and the lint levels.
466 lint_store
: &'tcx LintStore
,
468 last_node_with_lint_attrs
: hir
::HirId
,
470 /// Generic type parameters in scope for the item we are in.
471 pub generics
: Option
<&'tcx hir
::Generics
>,
473 /// We are only looking at one module
477 pub struct LateContextAndPass
<'a
, 'tcx
, T
: LateLintPass
<'a
, 'tcx
>> {
478 context
: LateContext
<'a
, 'tcx
>,
482 /// Context for lint checking of the AST, after expansion, before lowering to
484 pub struct EarlyContext
<'a
> {
485 /// Type context we're checking in.
486 pub sess
: &'a Session
,
488 /// The crate being checked.
489 pub krate
: &'a ast
::Crate
,
491 builder
: LintLevelsBuilder
<'a
>,
493 /// The store of registered lints and the lint levels.
494 lint_store
: &'a LintStore
,
496 buffered
: LintBuffer
,
499 pub struct EarlyContextAndPass
<'a
, T
: EarlyLintPass
> {
500 context
: EarlyContext
<'a
>,
504 pub trait LintPassObject
: Sized {}
506 impl LintPassObject
for EarlyLintPassObject {}
508 impl LintPassObject
for LateLintPassObject {}
510 pub trait LintContext
: Sized
{
511 type PassObject
: LintPassObject
;
513 fn sess(&self) -> &Session
;
514 fn lints(&self) -> &LintStore
;
516 fn lookup_and_emit
<S
: Into
<MultiSpan
>>(&self,
520 self.lookup(lint
, span
, msg
).emit();
523 fn lookup_and_emit_with_diagnostics
<S
: Into
<MultiSpan
>>(&self,
527 diagnostic
: BuiltinLintDiagnostics
) {
528 let mut db
= self.lookup(lint
, span
, msg
);
529 diagnostic
.run(self.sess(), &mut db
);
533 fn lookup
<S
: Into
<MultiSpan
>>(&self,
537 -> DiagnosticBuilder
<'_
>;
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
);
544 fn struct_span_lint
<S
: Into
<MultiSpan
>>(&self,
548 -> DiagnosticBuilder
<'_
> {
549 self.lookup(lint
, Some(span
), msg
)
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
{
559 err
.span_note(note_span
, note
);
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
);
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
);
580 impl<'a
> EarlyContext
<'a
> {
583 lint_store
: &'a LintStore
,
584 krate
: &'a ast
::Crate
,
585 buffered
: LintBuffer
,
586 warn_about_weird_lints
: bool
,
587 ) -> EarlyContext
<'a
> {
592 builder
: LintLevelSets
::builder(sess
, warn_about_weird_lints
, lint_store
),
598 macro_rules
! lint_callback
{ ($cx
:expr
, $f
:ident
, $
($args
:expr
),*) => ({
599 $cx
.pass
.$
f(&$cx
.context
, $
($args
),*);
602 macro_rules
! run_early_pass
{ ($cx
:expr
, $f
:ident
, $
($args
:expr
),*) => ({
603 $cx
.pass
.$
f(&$cx
.context
, $
($args
),*);
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()),
613 early_lint
.diagnostic
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,
623 attrs
: &'a
[ast
::Attribute
],
625 where F
: FnOnce(&mut Self)
627 let push
= self.context
.builder
.push(attrs
, &self.context
.lint_store
);
629 self.enter_attrs(attrs
);
631 self.exit_attrs(attrs
);
632 self.context
.builder
.pop(push
);
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
);
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
);
646 impl LintContext
for LateContext
<'_
, '_
> {
647 type PassObject
= LateLintPassObject
;
649 /// Gets the overall compiler `Session` object.
650 fn sess(&self) -> &Session
{
654 fn lints(&self) -> &LintStore
{
658 fn lookup
<S
: Into
<MultiSpan
>>(&self,
662 -> DiagnosticBuilder
<'_
> {
663 let hir_id
= self.last_node_with_lint_attrs
;
666 Some(s
) => self.tcx
.struct_span_lint_hir(lint
, hir_id
, s
, msg
),
668 self.tcx
.struct_lint_node(lint
, hir_id
, msg
)
674 impl LintContext
for EarlyContext
<'_
> {
675 type PassObject
= EarlyLintPassObject
;
677 /// Gets the overall compiler `Session` object.
678 fn sess(&self) -> &Session
{
682 fn lints(&self) -> &LintStore
{
686 fn lookup
<S
: Into
<MultiSpan
>>(&self,
690 -> DiagnosticBuilder
<'_
> {
691 self.builder
.struct_lint(lint
, span
.map(|s
| s
.into()), msg
)
695 impl<'a
, 'tcx
> LateContext
<'a
, 'tcx
> {
696 pub fn current_lint_root(&self) -> hir
::HirId
{
697 self.last_node_with_lint_attrs
700 /// Check if a `DefId`'s path matches the given absolute type path usage.
702 /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
703 /// inherent `impl` blocks are matched with the name of the type.
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
712 pub fn match_def_path(&self, def_id
: DefId
, path
: &[Symbol
]) -> bool
{
713 let names
= self.get_def_path(def_id
);
715 names
.len() == path
.len() && names
.into_iter().zip(path
.iter()).all(|(a
, &b
)| a
== b
)
718 /// Gets the absolute path of `def_id` as a vector of `Symbol`.
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
728 pub fn get_def_path(&self, def_id
: DefId
) -> Vec
<Symbol
> {
729 pub struct AbsolutePathPrinter
<'tcx
> {
730 pub tcx
: TyCtxt
<'tcx
>,
733 impl<'tcx
> Printer
<'tcx
> for AbsolutePathPrinter
<'tcx
> {
736 type Path
= Vec
<Symbol
>;
739 type DynExistential
= ();
742 fn tcx(&self) -> TyCtxt
<'tcx
> {
746 fn print_region(self, _region
: ty
::Region
<'_
>) -> Result
<Self::Region
, Self::Error
> {
750 fn print_type(self, _ty
: Ty
<'tcx
>) -> Result
<Self::Type
, Self::Error
> {
754 fn print_dyn_existential(
756 _predicates
: &'tcx ty
::List
<ty
::ExistentialPredicate
<'tcx
>>,
757 ) -> Result
<Self::DynExistential
, Self::Error
> {
763 _ct
: &'tcx ty
::Const
<'tcx
>,
764 ) -> Result
<Self::Const
, Self::Error
> {
768 fn path_crate(self, cnum
: CrateNum
) -> Result
<Self::Path
, Self::Error
> {
769 Ok(vec
![self.tcx
.original_crate_name(cnum
)])
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
);
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
)),
792 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
793 _disambiguated_data
: &DisambiguatedDefPathData
,
795 trait_ref
: Option
<ty
::TraitRef
<'tcx
>>,
796 ) -> Result
<Self::Path
, Self::Error
> {
797 let mut path
= print_prefix(self)?
;
799 // This shouldn't ever be needed, but just in case:
800 path
.push(match trait_ref
{
805 trait_ref
.print_only_trait_path(),
810 None
=> Symbol
::intern(&format
!("<impl {}>", self_ty
)),
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)?
;
823 // Skip `::{{constructor}}` on tuple/unit structs.
824 match disambiguated_data
.data
{
825 DefPathData
::Ctor
=> return Ok(path
),
829 path
.push(disambiguated_data
.data
.as_symbol());
833 fn path_generic_args(
835 print_prefix
: impl FnOnce(Self) -> Result
<Self::Path
, Self::Error
>,
836 _args
: &[GenericArg
<'tcx
>],
837 ) -> Result
<Self::Path
, Self::Error
> {
842 AbsolutePathPrinter { tcx: self.tcx }
843 .print_def_path(def_id
, &[])
848 impl<'a
, 'tcx
> LayoutOf
for LateContext
<'a
, 'tcx
> {
850 type TyLayout
= Result
<TyLayout
<'tcx
>, LayoutError
<'tcx
>>;
852 fn layout_of(&self, ty
: Ty
<'tcx
>) -> Self::TyLayout
{
853 self.tcx
.layout_of(self.param_env
.and(ty
))
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,
863 attrs
: &'tcx
[ast
::Attribute
],
865 where F
: FnOnce(&mut Self)
867 let prev
= self.context
.last_node_with_lint_attrs
;
868 self.context
.last_node_with_lint_attrs
= id
;
869 self.enter_attrs(attrs
);
871 self.exit_attrs(attrs
);
872 self.context
.last_node_with_lint_attrs
= prev
;
875 fn with_param_env
<F
>(&mut self, id
: hir
::HirId
, f
: F
)
876 where F
: FnOnce(&mut Self),
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
)
883 self.context
.param_env
= old_param_env
;
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
);
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
);
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
);
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
908 fn nested_visit_map
<'this
>(&'this
mut self) -> hir_visit
::NestedVisitorMap
<'this
, 'tcx
> {
909 hir_visit
::NestedVisitorMap
::All(&self.context
.tcx
.hir())
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
;
920 fn visit_param(&mut self, param
: &'tcx hir
::Param
) {
921 self.with_lint_attrs(param
.hir_id
, ¶m
.attrs
, |cx
| {
922 lint_callback
!(cx
, check_param
, param
);
923 hir_visit
::walk_param(cx
, param
);
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
);
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
);
943 self.context
.generics
= generics
;
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
);
956 fn visit_pat(&mut self, p
: &'tcx hir
::Pat
) {
957 lint_callback
!(self, check_pat
, p
);
958 hir_visit
::walk_pat(self, p
);
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
);
969 fn visit_stmt(&mut self, s
: &'tcx hir
::Stmt
) {
970 // statement attributes are actually just attributes on one of
974 // so we keep track of lint levels there
975 lint_callback
!(self, check_stmt
, s
);
976 hir_visit
::walk_stmt(self, s
);
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
;
992 fn visit_variant_data(&mut self,
993 s
: &'tcx hir
::VariantData
,
995 _
: &'tcx hir
::Generics
,
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
);
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
);
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
);
1021 fn visit_ty(&mut self, t
: &'tcx hir
::Ty
) {
1022 lint_callback
!(self, check_ty
, t
);
1023 hir_visit
::walk_ty(self, t
);
1026 fn visit_name(&mut self, sp
: Span
, name
: ast
::Name
) {
1027 lint_callback
!(self, check_name
, sp
, name
);
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
);
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
);
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
);
1049 fn visit_arm(&mut self, a
: &'tcx hir
::Arm
) {
1050 lint_callback
!(self, check_arm
, a
);
1051 hir_visit
::walk_arm(self, a
);
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
);
1059 fn visit_generics(&mut self, g
: &'tcx hir
::Generics
) {
1060 lint_callback
!(self, check_generics
, g
);
1061 hir_visit
::walk_generics(self, g
);
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
);
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
);
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
);
1085 self.context
.generics
= generics
;
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
);
1098 self.context
.generics
= generics
;
1101 fn visit_lifetime(&mut self, lt
: &'tcx hir
::Lifetime
) {
1102 lint_callback
!(self, check_lifetime
, lt
);
1103 hir_visit
::walk_lifetime(self, lt
);
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
);
1111 fn visit_attribute(&mut self, attr
: &'tcx ast
::Attribute
) {
1112 lint_callback
!(self, check_attribute
, attr
);
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
, ¶m
.attrs
, |cx
| {
1119 run_early_pass
!(cx
, check_param
, param
);
1120 ast_visit
::walk_param(cx
, param
);
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
);
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
);
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
);
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
);
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
);
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
);
1164 ast_visit
::walk_fn(self, fk
, decl
, span
);
1165 run_early_pass
!(self, check_fn_post
, fk
, decl
, span
, id
);
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
);
1173 ast_visit
::walk_struct_def(self, s
);
1174 run_early_pass
!(self, check_struct_def_post
, s
);
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
);
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
);
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
);
1198 fn visit_ident(&mut self, ident
: ast
::Ident
) {
1199 run_early_pass
!(self, check_ident
, ident
);
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
);
1205 ast_visit
::walk_mod(self, m
);
1206 run_early_pass
!(self, check_mod_post
, m
, s
, n
);
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
);
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
);
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
);
1228 fn visit_expr_post(&mut self, e
: &'a ast
::Expr
) {
1229 run_early_pass
!(self, check_expr_post
, e
);
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
);
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
);
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
);
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
);
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
);
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
);
1268 fn visit_lifetime(&mut self, lt
: &'a ast
::Lifetime
) {
1269 run_early_pass
!(self, check_lifetime
, lt
);
1270 self.check_id(lt
.id
);
1273 fn visit_path(&mut self, p
: &'a ast
::Path
, id
: ast
::NodeId
) {
1274 run_early_pass
!(self, check_path
, p
, id
);
1276 ast_visit
::walk_path(self, p
);
1279 fn visit_attribute(&mut self, attr
: &'a ast
::Attribute
) {
1280 run_early_pass
!(self, check_attribute
, attr
);
1283 fn visit_mac_def(&mut self, mac
: &'a ast
::MacroDef
, id
: ast
::NodeId
) {
1284 run_early_pass
!(self, check_mac_def
, mac
, id
);
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
);
1296 run_early_pass
!(self, check_mac
, mac
);
1300 struct LateLintPassObjects
<'a
> {
1301 lints
: &'a
mut [LateLintPassObject
],
1304 #[allow(rustc::lint_pass_impl_without_macro)]
1305 impl LintPass
for LateLintPassObjects
<'_
> {
1306 fn name(&self) -> &'
static str {
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
),*);
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
);
1329 late_lint_methods
!(late_lint_pass_impl
, [], ['tcx
]);
1331 fn late_lint_mod_pass
<'tcx
, T
: for<'a
> LateLintPass
<'a
, 'tcx
>>(
1333 module_def_id
: DefId
,
1336 let access_levels
= &tcx
.privacy_access_levels(LOCAL_CRATE
);
1338 let context
= LateContext
{
1340 tables
: &ty
::TypeckTables
::empty(None
),
1341 param_env
: ty
::ParamEnv
::empty(),
1343 lint_store
: &tcx
.lint_store
,
1344 last_node_with_lint_attrs
: tcx
.hir().as_local_hir_id(module_def_id
).unwrap(),
1349 let mut cx
= LateContextAndPass
{
1354 let (module
, span
, hir_id
) = tcx
.hir().get_module(module_def_id
);
1355 cx
.process_mod(module
, span
, hir_id
);
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
));
1363 pub fn late_lint_mod
<'tcx
, T
: for<'a
> LateLintPass
<'a
, 'tcx
>>(
1365 module_def_id
: DefId
,
1368 if tcx
.sess
.opts
.debugging_opts
.no_interleave_lints
{
1369 // These passes runs in late_lint_crate with -Z no_interleave_lints
1373 late_lint_mod_pass(tcx
, module_def_id
, builtin_lints
);
1375 let mut passes
: Vec
<_
> = tcx
.lint_store
.late_module_passes
1376 .iter().map(|pass
| (pass
)()).collect();
1378 if !passes
.is_empty() {
1379 late_lint_mod_pass(tcx
, module_def_id
, LateLintPassObjects { lints: &mut passes[..] }
);
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
);
1386 let krate
= tcx
.hir().krate();
1388 let context
= LateContext
{
1390 tables
: &ty
::TypeckTables
::empty(None
),
1391 param_env
: ty
::ParamEnv
::empty(),
1393 lint_store
: &tcx
.lint_store
,
1394 last_node_with_lint_attrs
: hir
::CRATE_HIR_ID
,
1399 let mut cx
= LateContextAndPass
{
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
);
1410 hir_visit
::walk_crate(cx
, krate
);
1412 lint_callback
!(cx
, check_crate_post
, krate
);
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
<_
>>();
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[..] }
);
1425 late_lint_pass_crate(tcx
, builtin_lints
);
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) }
);
1433 let mut passes
: Vec
<_
> = tcx
.lint_store
.late_module_passes
1434 .iter().map(|pass
| (pass
)()).collect();
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) }
);
1444 /// Performs lint checking on a crate.
1445 pub fn check_crate
<'tcx
, T
: for<'a
> LateLintPass
<'a
, 'tcx
>>(
1447 builtin_lints
: impl FnOnce() -> T
+ Send
,
1450 time(tcx
.sess
, "crate lints", || {
1451 // Run whole crate non-incremental lints
1452 late_lint_crate(tcx
, builtin_lints());
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
));
1464 struct EarlyLintPassObjects
<'a
> {
1465 lints
: &'a
mut [EarlyLintPassObject
],
1468 #[allow(rustc::lint_pass_impl_without_macro)]
1469 impl LintPass
for EarlyLintPassObjects
<'_
> {
1470 fn name(&self) -> &'
static str {
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
),*);
1485 macro_rules
! early_lint_pass_impl
{
1486 ([], [$
($methods
:tt
)*]) => (
1487 impl EarlyLintPass
for EarlyLintPassObjects
<'_
> {
1488 expand_early_lint_pass_impl_methods
!([$
($methods
)*]);
1493 early_lint_methods
!(early_lint_pass_impl
, []);
1495 fn early_lint_crate
<T
: EarlyLintPass
>(
1497 lint_store
: &LintStore
,
1500 buffered
: LintBuffer
,
1501 warn_about_weird_lints
: bool
,
1503 let mut cx
= EarlyContextAndPass
{
1504 context
: EarlyContext
::new(sess
, lint_store
, krate
, buffered
, warn_about_weird_lints
),
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
);
1514 ast_visit
::walk_crate(cx
, krate
);
1516 run_early_pass
!(cx
, check_crate_post
, krate
);
1521 pub fn check_ast_crate
<T
: EarlyLintPass
>(
1523 lint_store
: &LintStore
,
1525 pre_expansion
: bool
,
1526 lint_buffer
: Option
<LintBuffer
>,
1529 let mut passes
: Vec
<_
> = if pre_expansion
{
1530 lint_store
.pre_expansion_passes
.iter().map(|p
| (p
)()).collect()
1532 lint_store
.early_passes
.iter().map(|p
| (p
)()).collect()
1534 let mut buffered
= lint_buffer
.unwrap_or_default();
1536 if !sess
.opts
.debugging_opts
.no_interleave_lints
{
1537 buffered
= early_lint_crate(sess
, lint_store
, krate
, builtin_lints
, buffered
,
1540 if !passes
.is_empty() {
1541 buffered
= early_lint_crate(
1545 EarlyLintPassObjects { lints: &mut passes[..] }
,
1551 for pass
in &mut passes
{
1552 buffered
= time(sess
, &format
!("running lint: {}", pass
.name()), || {
1557 EarlyLintPassObjects { lints: slice::from_mut(pass) }
,
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.
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");