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