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