Skip to main content

rustc_lint/
passes.rs

1use rustc_session::lint::LintPass;
2
3use crate::context::{EarlyContext, LateContext};
4
5#[macro_export]
6macro_rules! late_lint_methods {
7    ($macro:path, $args:tt) => (
8        // `_post` methods are called *after* recursing into the node.
9        $macro!($args, [
10            fn check_body(a: &rustc_hir::Body<'tcx>);
11            fn check_body_post(a: &rustc_hir::Body<'tcx>);
12            fn check_crate();
13            fn check_crate_post();
14            fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_hir::HirId);
15            fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>);
16            fn check_item(a: &'tcx rustc_hir::Item<'tcx>);
17            fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>);
18            fn check_local(a: &'tcx rustc_hir::LetStmt<'tcx>);
19            fn check_block(a: &'tcx rustc_hir::Block<'tcx>);
20            fn check_block_post(a: &'tcx rustc_hir::Block<'tcx>);
21            fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>);
22            fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>);
23            fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>);
24            fn check_lit(hir_id: rustc_hir::HirId, a: rustc_hir::Lit, negated: bool);
25            fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>);
26            fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>);
27            fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>);
28            fn check_generic_param(a: &'tcx rustc_hir::GenericParam<'tcx>);
29            fn check_generics(a: &'tcx rustc_hir::Generics<'tcx>);
30            fn check_poly_trait_ref(a: &'tcx rustc_hir::PolyTraitRef<'tcx>);
31            fn check_fn(
32                a: rustc_hir::intravisit::FnKind<'tcx>,
33                b: &'tcx rustc_hir::FnDecl<'tcx>,
34                c: &'tcx rustc_hir::Body<'tcx>,
35                d: rustc_span::Span,
36                e: rustc_span::def_id::LocalDefId);
37            fn check_trait_item(a: &'tcx rustc_hir::TraitItem<'tcx>);
38            fn check_impl_item(a: &'tcx rustc_hir::ImplItem<'tcx>);
39            fn check_impl_item_post(a: &'tcx rustc_hir::ImplItem<'tcx>);
40            fn check_struct_def(a: &'tcx rustc_hir::VariantData<'tcx>);
41            fn check_field_def(a: &'tcx rustc_hir::FieldDef<'tcx>);
42            fn check_variant(a: &'tcx rustc_hir::Variant<'tcx>);
43            fn check_path(a: &rustc_hir::Path<'tcx>, b: rustc_hir::HirId);
44            fn check_attribute(a: &'tcx rustc_hir::Attribute);
45            fn check_attributes(a: &'tcx [rustc_hir::Attribute]);
46            fn check_attributes_post(a: &'tcx [rustc_hir::Attribute]);
47        ]);
48    )
49}
50
51/// Trait for types providing lint checks.
52///
53/// Each `check` method checks a single syntax node, and should not
54/// invoke methods recursively (unlike `Visitor`). By default they
55/// do nothing.
56///
57// FIXME: eliminate the duplication with `Visitor`. But this also
58// contains a few lint-specific methods with no equivalent in `Visitor`.
59//
60macro_rules! declare_late_lint_pass {
61    ([], [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
62        pub trait LateLintPass<'tcx>: LintPass {
63            $(#[inline(always)] fn $name(&mut self, _: &LateContext<'tcx>, $(_: $arg),*) {})*
64        }
65    )
66}
67
68// Declare the `LateLintPass` trait, which contains empty default definitions
69// for all the `check_*` methods.
70pub trait LateLintPass<'tcx>: LintPass {
    #[inline(always)]
    fn check_body(&mut self, _: &LateContext<'tcx>,
        _: &rustc_hir::Body<'tcx>) {}
    #[inline(always)]
    fn check_body_post(&mut self, _: &LateContext<'tcx>,
        _: &rustc_hir::Body<'tcx>) {}
    #[inline(always)]
    fn check_crate(&mut self, _: &LateContext<'tcx>) {}
    #[inline(always)]
    fn check_crate_post(&mut self, _: &LateContext<'tcx>) {}
    #[inline(always)]
    fn check_mod(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Mod<'tcx>, _: rustc_hir::HirId) {}
    #[inline(always)]
    fn check_foreign_item(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::ForeignItem<'tcx>) {}
    #[inline(always)]
    fn check_item(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Item<'tcx>) {}
    #[inline(always)]
    fn check_item_post(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Item<'tcx>) {}
    #[inline(always)]
    fn check_local(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::LetStmt<'tcx>) {}
    #[inline(always)]
    fn check_block(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Block<'tcx>) {}
    #[inline(always)]
    fn check_block_post(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Block<'tcx>) {}
    #[inline(always)]
    fn check_stmt(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Stmt<'tcx>) {}
    #[inline(always)]
    fn check_arm(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Arm<'tcx>) {}
    #[inline(always)]
    fn check_pat(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Pat<'tcx>) {}
    #[inline(always)]
    fn check_lit(&mut self, _: &LateContext<'tcx>, _: rustc_hir::HirId,
        _: rustc_hir::Lit, _: bool) {}
    #[inline(always)]
    fn check_expr(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Expr<'tcx>) {}
    #[inline(always)]
    fn check_expr_post(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Expr<'tcx>) {}
    #[inline(always)]
    fn check_ty(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>) {}
    #[inline(always)]
    fn check_generic_param(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::GenericParam<'tcx>) {}
    #[inline(always)]
    fn check_generics(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Generics<'tcx>) {}
    #[inline(always)]
    fn check_poly_trait_ref(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::PolyTraitRef<'tcx>) {}
    #[inline(always)]
    fn check_fn(&mut self, _: &LateContext<'tcx>,
        _: rustc_hir::intravisit::FnKind<'tcx>,
        _: &'tcx rustc_hir::FnDecl<'tcx>, _: &'tcx rustc_hir::Body<'tcx>,
        _: rustc_span::Span, _: rustc_span::def_id::LocalDefId) {}
    #[inline(always)]
    fn check_trait_item(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::TraitItem<'tcx>) {}
    #[inline(always)]
    fn check_impl_item(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::ImplItem<'tcx>) {}
    #[inline(always)]
    fn check_impl_item_post(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::ImplItem<'tcx>) {}
    #[inline(always)]
    fn check_struct_def(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::VariantData<'tcx>) {}
    #[inline(always)]
    fn check_field_def(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::FieldDef<'tcx>) {}
    #[inline(always)]
    fn check_variant(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Variant<'tcx>) {}
    #[inline(always)]
    fn check_path(&mut self, _: &LateContext<'tcx>, _: &rustc_hir::Path<'tcx>,
        _: rustc_hir::HirId) {}
    #[inline(always)]
    fn check_attribute(&mut self, _: &LateContext<'tcx>,
        _: &'tcx rustc_hir::Attribute) {}
    #[inline(always)]
    fn check_attributes(&mut self, _: &LateContext<'tcx>,
        _: &'tcx [rustc_hir::Attribute]) {}
    #[inline(always)]
    fn check_attributes_post(&mut self, _: &LateContext<'tcx>,
        _: &'tcx [rustc_hir::Attribute]) {}
}late_lint_methods!(declare_late_lint_pass, []);
71
72#[macro_export]
73macro_rules! expand_combined_late_lint_pass_method {
74    ([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({
75        $($self.$pass.$name $params;)*
76    })
77}
78
79#[macro_export]
80macro_rules! expand_combined_late_lint_pass_methods {
81    ($passes:tt, [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
82        $(fn $name(&mut self, context: &$crate::LateContext<'tcx>, $($param: $arg),*) {
83            $crate::expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*));
84        })*
85    )
86}
87
88/// Combines multiple lints passes into a single lint pass, at compile time,
89/// for maximum speed. Each `check_foo` method in `$methods` within this pass
90/// simply calls `check_foo` once per `$pass`. Compare with
91/// `RuntimeCombinedLateLintPass`, which is similar, but combines lint passes at
92/// runtime.
93#[macro_export]
94macro_rules! declare_combined_late_lint_pass {
95    ([$v:vis $name:ident, [$($pass:ident: $constructor:expr,)*]], $methods:tt) => (
96        #[allow(non_snake_case)]
97        $v struct $name {
98            $($pass: $pass,)*
99        }
100
101        impl $name {
102            $v fn new() -> Self {
103                Self {
104                    $($pass: $constructor,)*
105                }
106            }
107
108            $v fn lint_vec() -> $crate::LintVec {
109                let mut lints = Vec::new();
110                $(lints.extend_from_slice(&$pass::lint_vec());)*
111                lints
112            }
113        }
114
115        impl<'tcx> $crate::LateLintPass<'tcx> for $name {
116            $crate::expand_combined_late_lint_pass_methods!([$($pass),*], $methods);
117        }
118
119        #[allow(rustc::lint_pass_impl_without_macro)]
120        impl $crate::LintPass for $name {
121            fn name(&self) -> &'static str {
122                stringify!($name)
123            }
124            fn get_lints(&self) -> LintVec {
125                $name::lint_vec()
126            }
127        }
128    )
129}
130
131#[macro_export]
132macro_rules! early_lint_methods {
133    ($macro:path, $args:tt) => (
134        // `_post` methods are called *after* recursing into the node.
135        $macro!($args, [
136            fn check_param(a: &rustc_ast::Param);
137            fn check_ident(a: &rustc_span::Ident);
138            fn check_crate(a: &rustc_ast::Crate);
139            fn check_crate_post(a: &rustc_ast::Crate);
140            fn check_item(a: &rustc_ast::Item);
141            fn check_item_post(a: &rustc_ast::Item);
142            fn check_local(a: &rustc_ast::Local);
143            fn check_block(a: &rustc_ast::Block);
144            fn check_stmt(a: &rustc_ast::Stmt);
145            fn check_arm(a: &rustc_ast::Arm);
146            fn check_pat(a: &rustc_ast::Pat);
147            fn check_pat_post(a: &rustc_ast::Pat);
148            fn check_expr(a: &rustc_ast::Expr);
149            fn check_expr_post(a: &rustc_ast::Expr);
150            fn check_ty(a: &rustc_ast::Ty);
151            fn check_generic_arg(a: &rustc_ast::GenericArg);
152            fn check_generic_param(a: &rustc_ast::GenericParam);
153            fn check_generics(a: &rustc_ast::Generics);
154            fn check_poly_trait_ref(a: &rustc_ast::PolyTraitRef);
155            fn check_fn(
156                a: rustc_ast::visit::FnKind<'_>,
157                c: rustc_span::Span,
158                d_: rustc_ast::NodeId);
159            fn check_trait_item(a: &rustc_ast::AssocItem);
160            fn check_trait_item_post(a: &rustc_ast::AssocItem);
161            fn check_impl_item(a: &rustc_ast::AssocItem);
162            fn check_impl_item_post(a: &rustc_ast::AssocItem);
163            fn check_variant(a: &rustc_ast::Variant);
164            fn check_attribute(a: &rustc_ast::Attribute);
165            fn check_attributes(a: &[rustc_ast::Attribute]);
166            fn check_attributes_post(a: &[rustc_ast::Attribute]);
167            fn check_mac_def(a: &rustc_ast::MacroDef);
168            fn check_mac(a: &rustc_ast::MacCall);
169            fn check_where_predicate(a: &rustc_ast::WherePredicate);
170            fn check_where_predicate_post(a: &rustc_ast::WherePredicate);
171        ]);
172    )
173}
174
175macro_rules! declare_early_lint_pass {
176    ([], [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
177        pub trait EarlyLintPass: LintPass {
178            $(#[inline(always)] fn $name(&mut self, _: &EarlyContext<'_>, $(_: $arg),*) {})*
179        }
180    )
181}
182
183// Declare the `EarlyLintPass` trait, which contains empty default definitions
184// for all the `check_*` methods.
185pub trait EarlyLintPass: LintPass {
    #[inline(always)]
    fn check_param(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Param) {}
    #[inline(always)]
    fn check_ident(&mut self, _: &EarlyContext<'_>, _: &rustc_span::Ident) {}
    #[inline(always)]
    fn check_crate(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Crate) {}
    #[inline(always)]
    fn check_crate_post(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::Crate) {}
    #[inline(always)]
    fn check_item(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {}
    #[inline(always)]
    fn check_item_post(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::Item) {}
    #[inline(always)]
    fn check_local(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Local) {}
    #[inline(always)]
    fn check_block(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Block) {}
    #[inline(always)]
    fn check_stmt(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Stmt) {}
    #[inline(always)]
    fn check_arm(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Arm) {}
    #[inline(always)]
    fn check_pat(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Pat) {}
    #[inline(always)]
    fn check_pat_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Pat) {}
    #[inline(always)]
    fn check_expr(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Expr) {}
    #[inline(always)]
    fn check_expr_post(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::Expr) {}
    #[inline(always)]
    fn check_ty(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Ty) {}
    #[inline(always)]
    fn check_generic_arg(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::GenericArg) {}
    #[inline(always)]
    fn check_generic_param(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::GenericParam) {}
    #[inline(always)]
    fn check_generics(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::Generics) {}
    #[inline(always)]
    fn check_poly_trait_ref(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::PolyTraitRef) {}
    #[inline(always)]
    fn check_fn(&mut self, _: &EarlyContext<'_>,
        _: rustc_ast::visit::FnKind<'_>, _: rustc_span::Span,
        _: rustc_ast::NodeId) {}
    #[inline(always)]
    fn check_trait_item(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::AssocItem) {}
    #[inline(always)]
    fn check_trait_item_post(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::AssocItem) {}
    #[inline(always)]
    fn check_impl_item(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::AssocItem) {}
    #[inline(always)]
    fn check_impl_item_post(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::AssocItem) {}
    #[inline(always)]
    fn check_variant(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::Variant) {}
    #[inline(always)]
    fn check_attribute(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::Attribute) {}
    #[inline(always)]
    fn check_attributes(&mut self, _: &EarlyContext<'_>,
        _: &[rustc_ast::Attribute]) {}
    #[inline(always)]
    fn check_attributes_post(&mut self, _: &EarlyContext<'_>,
        _: &[rustc_ast::Attribute]) {}
    #[inline(always)]
    fn check_mac_def(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::MacroDef) {}
    #[inline(always)]
    fn check_mac(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::MacCall) {}
    #[inline(always)]
    fn check_where_predicate(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::WherePredicate) {}
    #[inline(always)]
    fn check_where_predicate_post(&mut self, _: &EarlyContext<'_>,
        _: &rustc_ast::WherePredicate) {}
}early_lint_methods!(declare_early_lint_pass, []);
186
187#[macro_export]
188macro_rules! expand_combined_early_lint_pass_method {
189    ([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({
190        $($self.$pass.$name $params;)*
191    })
192}
193
194#[macro_export]
195macro_rules! expand_combined_early_lint_pass_methods {
196    ($passes:tt, [$(fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
197        $(fn $name(&mut self, context: &$crate::EarlyContext<'_>, $($param: $arg),*) {
198            $crate::expand_combined_early_lint_pass_method!($passes, self, $name, (context, $($param),*));
199        })*
200    )
201}
202
203/// Combines multiple lints passes into a single lint pass, at compile time,
204/// for maximum speed. Each `check_foo` method in `$methods` within this pass
205/// simply calls `check_foo` once per `$pass`. Compare with
206/// `EarlyLintPassObjects`, which is similar, but combines lint passes at
207/// runtime.
208#[macro_export]
209macro_rules! declare_combined_early_lint_pass {
210    ([$v:vis $name:ident, [$($pass:ident: $constructor:expr,)*]], $methods:tt) => (
211        #[allow(non_snake_case)]
212        $v struct $name {
213            $($pass: $pass,)*
214        }
215
216        impl $name {
217            $v fn new() -> Self {
218                Self {
219                    $($pass: $constructor,)*
220                }
221            }
222
223            $v fn lint_vec() -> $crate::LintVec {
224                let mut lints = Vec::new();
225                $(lints.extend_from_slice(&$pass::lint_vec());)*
226                lints
227            }
228        }
229
230        impl $crate::EarlyLintPass for $name {
231            $crate::expand_combined_early_lint_pass_methods!([$($pass),*], $methods);
232        }
233
234        #[allow(rustc::lint_pass_impl_without_macro)]
235        impl $crate::LintPass for $name {
236            fn name(&self) -> &'static str {
237                panic!()
238            }
239            fn get_lints(&self) -> LintVec {
240                panic!()
241            }
242        }
243    )
244}
245
246/// A lint pass boxed up as a trait object.
247pub(crate) type EarlyLintPassObject = Box<dyn EarlyLintPass>;
248pub(crate) type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + 'tcx>;