]> git.lizzy.rs Git - rust.git/blob - src/librustc/lint/mod.rs
ea7023b3bc82c944955552c7882bab1946109420
[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 //!
23 //! Some of rustc's lints are defined elsewhere in the compiler and work by
24 //! calling `add_lint()` on the overall `Session` object. This works when
25 //! it happens before the main lint pass, which emits the lints stored by
26 //! `add_lint()`. To emit lints after the main lint pass (from trans, for
27 //! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
28 //! in `context.rs`.
29
30 #![macro_escape]
31
32 use middle::privacy::ExportedItems;
33 use std::hash;
34 use syntax::codemap::Span;
35 use syntax::visit::FnKind;
36 use syntax::ast;
37
38 pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate};
39
40 /// Specification of a single lint.
41 pub struct Lint {
42     /// A string identifier for the lint.
43     ///
44     /// Written with underscores, e.g. "unused_imports".
45     /// This identifies the lint in attributes and in
46     /// command-line arguments. On the command line,
47     /// underscores become dashes.
48     pub name: &'static str,
49
50     /// Default level for the lint.
51     pub default_level: Level,
52
53     /// Description of the lint or the issue it detects.
54     ///
55     /// e.g. "imports that are never used"
56     pub desc: &'static str,
57 }
58
59 /// Build a `Lint` initializer.
60 #[macro_export]
61 macro_rules! lint_initializer (
62     ($name:ident, $level:ident, $desc:expr) => (
63         ::rustc::lint::Lint {
64             name: stringify!($name),
65             default_level: ::rustc::lint::$level,
66             desc: $desc,
67         }
68     )
69 )
70
71 /// Declare a static item of type `&'static Lint`.
72 #[macro_export]
73 macro_rules! declare_lint (
74     // FIXME(#14660): deduplicate
75     (pub $name:ident, $level:ident, $desc:expr) => (
76         pub static $name: &'static ::rustc::lint::Lint
77             = &lint_initializer!($name, $level, $desc);
78     );
79     ($name:ident, $level:ident, $desc:expr) => (
80         static $name: &'static ::rustc::lint::Lint
81             = &lint_initializer!($name, $level, $desc);
82     );
83 )
84
85 /// Declare a static `LintArray` and return it as an expression.
86 #[macro_export]
87 macro_rules! lint_array ( ($( $lint:expr ),*) => (
88     {
89         static array: LintArray = &[ $( $lint ),* ];
90         array
91     }
92 ))
93
94 pub type LintArray = &'static [&'static Lint];
95
96 /// Trait for types providing lint checks.
97 ///
98 /// Each `check` method checks a single syntax node, and should not
99 /// invoke methods recursively (unlike `Visitor`). By default they
100 /// do nothing.
101 //
102 // FIXME: eliminate the duplication with `Visitor`. But this also
103 // contains a few lint-specific methods with no equivalent in `Visitor`.
104 pub trait LintPass {
105     /// Get descriptions of the lints this `LintPass` object can emit.
106     ///
107     /// NB: there is no enforcement that the object only emits lints it registered.
108     /// And some `rustc` internal `LintPass`es register lints to be emitted by other
109     /// parts of the compiler. If you want enforced access restrictions for your
110     /// `Lint`, make it a private `static` item in its own module.
111     fn get_lints(&self) -> LintArray;
112
113     fn check_crate(&mut self, _: &Context, _: &ExportedItems, _: &ast::Crate) { }
114     fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
115     fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
116     fn check_view_item(&mut self, _: &Context, _: &ast::ViewItem) { }
117     fn check_foreign_item(&mut self, _: &Context, _: &ast::ForeignItem) { }
118     fn check_item(&mut self, _: &Context, _: &ast::Item) { }
119     fn check_local(&mut self, _: &Context, _: &ast::Local) { }
120     fn check_block(&mut self, _: &Context, _: &ast::Block) { }
121     fn check_stmt(&mut self, _: &Context, _: &ast::Stmt) { }
122     fn check_arm(&mut self, _: &Context, _: &ast::Arm) { }
123     fn check_pat(&mut self, _: &Context, _: &ast::Pat) { }
124     fn check_decl(&mut self, _: &Context, _: &ast::Decl) { }
125     fn check_expr(&mut self, _: &Context, _: &ast::Expr) { }
126     fn check_expr_post(&mut self, _: &Context, _: &ast::Expr) { }
127     fn check_ty(&mut self, _: &Context, _: &ast::Ty) { }
128     fn check_generics(&mut self, _: &Context, _: &ast::Generics) { }
129     fn check_fn(&mut self, _: &Context,
130         _: &FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
131     fn check_ty_method(&mut self, _: &Context, _: &ast::TypeMethod) { }
132     fn check_trait_method(&mut self, _: &Context, _: &ast::TraitMethod) { }
133     fn check_struct_def(&mut self, _: &Context,
134         _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
135     fn check_struct_def_post(&mut self, _: &Context,
136         _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
137     fn check_struct_field(&mut self, _: &Context, _: &ast::StructField) { }
138     fn check_variant(&mut self, _: &Context, _: &ast::Variant, _: &ast::Generics) { }
139     fn check_opt_lifetime_ref(&mut self, _: &Context, _: Span, _: &Option<ast::Lifetime>) { }
140     fn check_lifetime_ref(&mut self, _: &Context, _: &ast::Lifetime) { }
141     fn check_lifetime_decl(&mut self, _: &Context, _: &ast::Lifetime) { }
142     fn check_explicit_self(&mut self, _: &Context, _: &ast::ExplicitSelf) { }
143     fn check_mac(&mut self, _: &Context, _: &ast::Mac) { }
144     fn check_path(&mut self, _: &Context, _: &ast::Path, _: ast::NodeId) { }
145     fn check_attribute(&mut self, _: &Context, _: &ast::Attribute) { }
146
147     /// Called when entering a syntax node that can have lint attributes such
148     /// as `#[allow(...)]`. Called with *all* the attributes of that node.
149     fn enter_lint_attrs(&mut self, _: &Context, _: &[ast::Attribute]) { }
150
151     /// Counterpart to `enter_lint_attrs`.
152     fn exit_lint_attrs(&mut self, _: &Context, _: &[ast::Attribute]) { }
153 }
154
155 /// A lint pass boxed up as a trait object.
156 pub type LintPassObject = Box<LintPass + 'static>;
157
158 /// Identifies a lint known to the compiler.
159 #[deriving(Clone)]
160 pub struct LintId {
161     // Identity is based on pointer equality of this field.
162     lint: &'static Lint,
163 }
164
165 impl PartialEq for LintId {
166     fn eq(&self, other: &LintId) -> bool {
167         (self.lint as *Lint) == (other.lint as *Lint)
168     }
169 }
170
171 impl Eq for LintId { }
172
173 impl<S: hash::Writer> hash::Hash<S> for LintId {
174     fn hash(&self, state: &mut S) {
175         let ptr = self.lint as *Lint;
176         ptr.hash(state);
177     }
178 }
179
180 impl LintId {
181     /// Get the `LintId` for a `Lint`.
182     pub fn of(lint: &'static Lint) -> LintId {
183         LintId {
184             lint: lint,
185         }
186     }
187
188     /// Get the name of the lint.
189     pub fn as_str(&self) -> &'static str {
190         self.lint.name
191     }
192 }
193
194 /// Setting for how to handle a lint.
195 #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
196 pub enum Level {
197     Allow, Warn, Deny, Forbid
198 }
199
200 impl Level {
201     /// Convert a level to a lower-case string.
202     pub fn as_str(self) -> &'static str {
203         match self {
204             Allow => "allow",
205             Warn => "warn",
206             Deny => "deny",
207             Forbid => "forbid",
208         }
209     }
210
211     /// Convert a lower-case string to a level.
212     pub fn from_str(x: &str) -> Option<Level> {
213         match x {
214             "allow" => Some(Allow),
215             "warn" => Some(Warn),
216             "deny" => Some(Deny),
217             "forbid" => Some(Forbid),
218             _ => None,
219         }
220     }
221 }
222
223 /// How a lint level was set.
224 #[deriving(Clone, PartialEq, Eq)]
225 pub enum LintSource {
226     /// Lint is at the default level as declared
227     /// in rustc or a plugin.
228     Default,
229
230     /// Lint level was set by an attribute.
231     Node(Span),
232
233     /// Lint level was set by a command-line flag.
234     CommandLine,
235 }
236
237 pub type LevelSource = (Level, LintSource);
238
239 pub mod builtin;
240
241 mod context;