rustc_lint/
passes.rs

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