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