]> git.lizzy.rs Git - rust.git/blob - src/librustc/lint/mod.rs
d12065ca86e144c5d0e682e33b596ed4122d5275
[rust.git] / src / librustc / lint / mod.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Lints, aka compiler warnings.
12 //!
13 //! A 'lint' check is a kind of miscellaneous constraint that a user _might_
14 //! want to enforce, but might reasonably want to permit as well, on a
15 //! module-by-module basis. They contrast with static constraints enforced by
16 //! other phases of the compiler, which are generally required to hold in order
17 //! to compile the program at all.
18 //!
19 //! Most lints can be written as `LintPass` instances. These run just before
20 //! translation to LLVM bytecode. The `LintPass`es built into rustc are defined
21 //! within `builtin.rs`, which has further comments on how to add such a lint.
22 //! rustc can also load user-defined lint plugins via the plugin mechanism.
23 //!
24 //! Some of rustc's lints are defined elsewhere in the compiler and work by
25 //! calling `add_lint()` on the overall `Session` object. This works when
26 //! it happens before the main lint pass, which emits the lints stored by
27 //! `add_lint()`. To emit lints after the main lint pass (from trans, for
28 //! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
29 //! in `context.rs`.
30
31 pub use self::Level::*;
32 pub use self::LintSource::*;
33
34 use hir;
35 use hir::intravisit::FnKind;
36 use std::hash;
37 use std::ascii::AsciiExt;
38 use syntax_pos::Span;
39 use syntax::visit as ast_visit;
40 use syntax::ast;
41
42 pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
43                         raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
44                         raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint};
45
46 pub use lint::table::LintTable;
47
48 /// Specification of a single lint.
49 #[derive(Copy, Clone, Debug)]
50 pub struct Lint {
51     /// A string identifier for the lint.
52     ///
53     /// This identifies the lint in attributes and in command-line arguments.
54     /// In those contexts it is always lowercase, but this field is compared
55     /// in a way which is case-insensitive for ASCII characters. This allows
56     /// `declare_lint!()` invocations to follow the convention of upper-case
57     /// statics without repeating the name.
58     ///
59     /// The name is written with underscores, e.g. "unused_imports".
60     /// On the command line, underscores become dashes.
61     pub name: &'static str,
62
63     /// Default level for the lint.
64     pub default_level: Level,
65
66     /// Description of the lint or the issue it detects.
67     ///
68     /// e.g. "imports that are never used"
69     pub desc: &'static str,
70 }
71
72 impl Lint {
73     /// Get the lint's name, with ASCII letters converted to lowercase.
74     pub fn name_lower(&self) -> String {
75         self.name.to_ascii_lowercase()
76     }
77 }
78
79 /// Build a `Lint` initializer.
80 #[macro_export]
81 macro_rules! lint_initializer {
82     ($name:ident, $level:ident, $desc:expr) => (
83         ::rustc::lint::Lint {
84             name: stringify!($name),
85             default_level: ::rustc::lint::$level,
86             desc: $desc,
87         }
88     )
89 }
90
91 /// Declare a static item of type `&'static Lint`.
92 #[macro_export]
93 macro_rules! declare_lint {
94     (pub $name:ident, $level:ident, $desc:expr) => (
95         pub static $name: &'static ::rustc::lint::Lint
96             = &lint_initializer!($name, $level, $desc);
97     );
98     ($name:ident, $level:ident, $desc:expr) => (
99         static $name: &'static ::rustc::lint::Lint
100             = &lint_initializer!($name, $level, $desc);
101     );
102 }
103
104 /// Declare a static `LintArray` and return it as an expression.
105 #[macro_export]
106 macro_rules! lint_array { ($( $lint:expr ),*) => (
107     {
108         static ARRAY: LintArray = &[ $( &$lint ),* ];
109         ARRAY
110     }
111 ) }
112
113 pub type LintArray = &'static [&'static &'static Lint];
114
115 pub trait LintPass {
116     /// Get descriptions of the lints this `LintPass` object can emit.
117     ///
118     /// NB: there is no enforcement that the object only emits lints it registered.
119     /// And some `rustc` internal `LintPass`es register lints to be emitted by other
120     /// parts of the compiler. If you want enforced access restrictions for your
121     /// `Lint`, make it a private `static` item in its own module.
122     fn get_lints(&self) -> LintArray;
123 }
124
125
126 /// Trait for types providing lint checks.
127 ///
128 /// Each `check` method checks a single syntax node, and should not
129 /// invoke methods recursively (unlike `Visitor`). By default they
130 /// do nothing.
131 //
132 // FIXME: eliminate the duplication with `Visitor`. But this also
133 // contains a few lint-specific methods with no equivalent in `Visitor`.
134 pub trait LateLintPass<'a, 'tcx>: LintPass {
135     fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { }
136     fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { }
137     fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { }
138     fn check_mod(&mut self,
139                  _: &LateContext<'a, 'tcx>,
140                  _: &'tcx hir::Mod,
141                  _: Span,
142                  _: ast::NodeId) { }
143     fn check_mod_post(&mut self,
144                       _: &LateContext<'a, 'tcx>,
145                       _: &'tcx hir::Mod,
146                       _: Span,
147                       _: ast::NodeId) { }
148     fn check_foreign_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { }
149     fn check_foreign_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { }
150     fn check_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { }
151     fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { }
152     fn check_local(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Local) { }
153     fn check_block(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { }
154     fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { }
155     fn check_stmt(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Stmt) { }
156     fn check_arm(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Arm) { }
157     fn check_pat(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Pat) { }
158     fn check_decl(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Decl) { }
159     fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { }
160     fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { }
161     fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { }
162     fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { }
163     fn check_fn(&mut self,
164                 _: &LateContext<'a, 'tcx>,
165                 _: FnKind<'tcx>,
166                 _: &'tcx hir::FnDecl,
167                 _: &'tcx hir::Body,
168                 _: Span,
169                 _: ast::NodeId) { }
170     fn check_fn_post(&mut self,
171                      _: &LateContext<'a, 'tcx>,
172                      _: FnKind<'tcx>,
173                      _: &'tcx hir::FnDecl,
174                      _: &'tcx hir::Body,
175                      _: Span,
176                      _: ast::NodeId) { }
177     fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }
178     fn check_trait_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }
179     fn check_impl_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { }
180     fn check_impl_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { }
181     fn check_struct_def(&mut self,
182                         _: &LateContext<'a, 'tcx>,
183                         _: &'tcx hir::VariantData,
184                         _: ast::Name,
185                         _: &'tcx hir::Generics,
186                         _: ast::NodeId) { }
187     fn check_struct_def_post(&mut self,
188                              _: &LateContext<'a, 'tcx>,
189                              _: &'tcx hir::VariantData,
190                              _: ast::Name,
191                              _: &'tcx hir::Generics,
192                              _: ast::NodeId) { }
193     fn check_struct_field(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::StructField) { }
194     fn check_variant(&mut self,
195                      _: &LateContext<'a, 'tcx>,
196                      _: &'tcx hir::Variant,
197                      _: &'tcx hir::Generics) { }
198     fn check_variant_post(&mut self,
199                           _: &LateContext<'a, 'tcx>,
200                           _: &'tcx hir::Variant,
201                           _: &'tcx hir::Generics) { }
202     fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { }
203     fn check_lifetime_def(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::LifetimeDef) { }
204     fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { }
205     fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { }
206
207     /// Called when entering a syntax node that can have lint attributes such
208     /// as `#[allow(...)]`. Called with *all* the attributes of that node.
209     fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { }
210
211     /// Counterpart to `enter_lint_attrs`.
212     fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { }
213 }
214
215 pub trait EarlyLintPass: LintPass {
216     fn check_ident(&mut self, _: &EarlyContext, _: Span, _: ast::Ident) { }
217     fn check_crate(&mut self, _: &EarlyContext, _: &ast::Crate) { }
218     fn check_crate_post(&mut self, _: &EarlyContext, _: &ast::Crate) { }
219     fn check_mod(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { }
220     fn check_mod_post(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { }
221     fn check_foreign_item(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { }
222     fn check_foreign_item_post(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { }
223     fn check_item(&mut self, _: &EarlyContext, _: &ast::Item) { }
224     fn check_item_post(&mut self, _: &EarlyContext, _: &ast::Item) { }
225     fn check_local(&mut self, _: &EarlyContext, _: &ast::Local) { }
226     fn check_block(&mut self, _: &EarlyContext, _: &ast::Block) { }
227     fn check_block_post(&mut self, _: &EarlyContext, _: &ast::Block) { }
228     fn check_stmt(&mut self, _: &EarlyContext, _: &ast::Stmt) { }
229     fn check_arm(&mut self, _: &EarlyContext, _: &ast::Arm) { }
230     fn check_pat(&mut self, _: &EarlyContext, _: &ast::Pat) { }
231     fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { }
232     fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { }
233     fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
234     fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
235     fn check_fn(&mut self, _: &EarlyContext,
236         _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
237     fn check_fn_post(&mut self, _: &EarlyContext,
238         _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { }
239     fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
240     fn check_trait_item_post(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
241     fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
242     fn check_impl_item_post(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
243     fn check_struct_def(&mut self, _: &EarlyContext,
244         _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
245     fn check_struct_def_post(&mut self, _: &EarlyContext,
246         _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
247     fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { }
248     fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
249     fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
250     fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { }
251     fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { }
252     fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { }
253     fn check_path_list_item(&mut self, _: &EarlyContext, _: &ast::PathListItem) { }
254     fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { }
255
256     /// Called when entering a syntax node that can have lint attributes such
257     /// as `#[allow(...)]`. Called with *all* the attributes of that node.
258     fn enter_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }
259
260     /// Counterpart to `enter_lint_attrs`.
261     fn exit_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }
262 }
263
264 /// A lint pass boxed up as a trait object.
265 pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>;
266 pub type LateLintPassObject = Box<for<'a, 'tcx> LateLintPass<'a, 'tcx> + 'static>;
267
268 /// Identifies a lint known to the compiler.
269 #[derive(Clone, Copy, Debug)]
270 pub struct LintId {
271     // Identity is based on pointer equality of this field.
272     lint: &'static Lint,
273 }
274
275 impl PartialEq for LintId {
276     fn eq(&self, other: &LintId) -> bool {
277         (self.lint as *const Lint) == (other.lint as *const Lint)
278     }
279 }
280
281 impl Eq for LintId { }
282
283 impl hash::Hash for LintId {
284     fn hash<H: hash::Hasher>(&self, state: &mut H) {
285         let ptr = self.lint as *const Lint;
286         ptr.hash(state);
287     }
288 }
289
290 impl LintId {
291     /// Get the `LintId` for a `Lint`.
292     pub fn of(lint: &'static Lint) -> LintId {
293         LintId {
294             lint: lint,
295         }
296     }
297
298     /// Get the name of the lint.
299     pub fn to_string(&self) -> String {
300         self.lint.name_lower()
301     }
302 }
303
304 /// Setting for how to handle a lint.
305 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
306 pub enum Level {
307     Allow, Warn, Deny, Forbid
308 }
309
310 impl Level {
311     /// Convert a level to a lower-case string.
312     pub fn as_str(self) -> &'static str {
313         match self {
314             Allow => "allow",
315             Warn => "warn",
316             Deny => "deny",
317             Forbid => "forbid",
318         }
319     }
320
321     /// Convert a lower-case string to a level.
322     pub fn from_str(x: &str) -> Option<Level> {
323         match x {
324             "allow" => Some(Allow),
325             "warn" => Some(Warn),
326             "deny" => Some(Deny),
327             "forbid" => Some(Forbid),
328             _ => None,
329         }
330     }
331 }
332
333 /// How a lint level was set.
334 #[derive(Clone, Copy, PartialEq, Eq)]
335 pub enum LintSource {
336     /// Lint is at the default level as declared
337     /// in rustc or a plugin.
338     Default,
339
340     /// Lint level was set by an attribute.
341     Node(Span),
342
343     /// Lint level was set by a command-line flag.
344     CommandLine,
345 }
346
347 pub type LevelSource = (Level, LintSource);
348
349 pub mod builtin;
350 mod context;
351 mod table;