]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 std::hash; | |
35 | use std::ascii::AsciiExt; | |
3157f602 | 36 | use syntax_pos::Span; |
54a0048b | 37 | use hir::intravisit::FnKind; |
b039eaaf | 38 | use syntax::visit as ast_visit; |
1a4d82fc | 39 | use syntax::ast; |
54a0048b | 40 | use hir; |
1a4d82fc | 41 | |
b039eaaf SL |
42 | pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, |
43 | raw_emit_lint, check_crate, check_ast_crate, gather_attrs, | |
c30ab7b3 | 44 | raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint}; |
1a4d82fc JJ |
45 | |
46 | /// Specification of a single lint. | |
c34b1796 | 47 | #[derive(Copy, Clone, Debug)] |
1a4d82fc JJ |
48 | pub struct Lint { |
49 | /// A string identifier for the lint. | |
50 | /// | |
51 | /// This identifies the lint in attributes and in command-line arguments. | |
52 | /// In those contexts it is always lowercase, but this field is compared | |
53 | /// in a way which is case-insensitive for ASCII characters. This allows | |
54 | /// `declare_lint!()` invocations to follow the convention of upper-case | |
55 | /// statics without repeating the name. | |
56 | /// | |
57 | /// The name is written with underscores, e.g. "unused_imports". | |
58 | /// On the command line, underscores become dashes. | |
59 | pub name: &'static str, | |
60 | ||
61 | /// Default level for the lint. | |
62 | pub default_level: Level, | |
63 | ||
64 | /// Description of the lint or the issue it detects. | |
65 | /// | |
66 | /// e.g. "imports that are never used" | |
67 | pub desc: &'static str, | |
68 | } | |
69 | ||
70 | impl Lint { | |
71 | /// Get the lint's name, with ASCII letters converted to lowercase. | |
72 | pub fn name_lower(&self) -> String { | |
73 | self.name.to_ascii_lowercase() | |
74 | } | |
75 | } | |
76 | ||
77 | /// Build a `Lint` initializer. | |
78 | #[macro_export] | |
79 | macro_rules! lint_initializer { | |
80 | ($name:ident, $level:ident, $desc:expr) => ( | |
81 | ::rustc::lint::Lint { | |
82 | name: stringify!($name), | |
83 | default_level: ::rustc::lint::$level, | |
84 | desc: $desc, | |
85 | } | |
86 | ) | |
87 | } | |
88 | ||
89 | /// Declare a static item of type `&'static Lint`. | |
90 | #[macro_export] | |
91 | macro_rules! declare_lint { | |
1a4d82fc JJ |
92 | (pub $name:ident, $level:ident, $desc:expr) => ( |
93 | pub static $name: &'static ::rustc::lint::Lint | |
94 | = &lint_initializer!($name, $level, $desc); | |
95 | ); | |
96 | ($name:ident, $level:ident, $desc:expr) => ( | |
97 | static $name: &'static ::rustc::lint::Lint | |
98 | = &lint_initializer!($name, $level, $desc); | |
99 | ); | |
100 | } | |
101 | ||
102 | /// Declare a static `LintArray` and return it as an expression. | |
103 | #[macro_export] | |
104 | macro_rules! lint_array { ($( $lint:expr ),*) => ( | |
105 | { | |
62682a34 SL |
106 | static ARRAY: LintArray = &[ $( &$lint ),* ]; |
107 | ARRAY | |
1a4d82fc JJ |
108 | } |
109 | ) } | |
110 | ||
111 | pub type LintArray = &'static [&'static &'static Lint]; | |
112 | ||
1a4d82fc JJ |
113 | pub trait LintPass { |
114 | /// Get descriptions of the lints this `LintPass` object can emit. | |
115 | /// | |
116 | /// NB: there is no enforcement that the object only emits lints it registered. | |
117 | /// And some `rustc` internal `LintPass`es register lints to be emitted by other | |
118 | /// parts of the compiler. If you want enforced access restrictions for your | |
119 | /// `Lint`, make it a private `static` item in its own module. | |
120 | fn get_lints(&self) -> LintArray; | |
b039eaaf SL |
121 | } |
122 | ||
1a4d82fc | 123 | |
b039eaaf SL |
124 | /// Trait for types providing lint checks. |
125 | /// | |
126 | /// Each `check` method checks a single syntax node, and should not | |
127 | /// invoke methods recursively (unlike `Visitor`). By default they | |
128 | /// do nothing. | |
129 | // | |
130 | // FIXME: eliminate the duplication with `Visitor`. But this also | |
131 | // contains a few lint-specific methods with no equivalent in `Visitor`. | |
132 | pub trait LateLintPass: LintPass { | |
133 | fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } | |
134 | fn check_crate(&mut self, _: &LateContext, _: &hir::Crate) { } | |
7453a54e | 135 | fn check_crate_post(&mut self, _: &LateContext, _: &hir::Crate) { } |
b039eaaf | 136 | fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { } |
7453a54e | 137 | fn check_mod_post(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { } |
b039eaaf | 138 | fn check_foreign_item(&mut self, _: &LateContext, _: &hir::ForeignItem) { } |
7453a54e | 139 | fn check_foreign_item_post(&mut self, _: &LateContext, _: &hir::ForeignItem) { } |
b039eaaf | 140 | fn check_item(&mut self, _: &LateContext, _: &hir::Item) { } |
7453a54e | 141 | fn check_item_post(&mut self, _: &LateContext, _: &hir::Item) { } |
b039eaaf SL |
142 | fn check_local(&mut self, _: &LateContext, _: &hir::Local) { } |
143 | fn check_block(&mut self, _: &LateContext, _: &hir::Block) { } | |
7453a54e | 144 | fn check_block_post(&mut self, _: &LateContext, _: &hir::Block) { } |
b039eaaf SL |
145 | fn check_stmt(&mut self, _: &LateContext, _: &hir::Stmt) { } |
146 | fn check_arm(&mut self, _: &LateContext, _: &hir::Arm) { } | |
147 | fn check_pat(&mut self, _: &LateContext, _: &hir::Pat) { } | |
148 | fn check_decl(&mut self, _: &LateContext, _: &hir::Decl) { } | |
149 | fn check_expr(&mut self, _: &LateContext, _: &hir::Expr) { } | |
150 | fn check_expr_post(&mut self, _: &LateContext, _: &hir::Expr) { } | |
151 | fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { } | |
152 | fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { } | |
153 | fn check_fn(&mut self, _: &LateContext, | |
e9174d1e | 154 | _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } |
7453a54e SL |
155 | fn check_fn_post(&mut self, _: &LateContext, |
156 | _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } | |
b039eaaf | 157 | fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } |
7453a54e | 158 | fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { } |
b039eaaf | 159 | fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } |
7453a54e | 160 | fn check_impl_item_post(&mut self, _: &LateContext, _: &hir::ImplItem) { } |
b039eaaf SL |
161 | fn check_struct_def(&mut self, _: &LateContext, |
162 | _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } | |
163 | fn check_struct_def_post(&mut self, _: &LateContext, | |
164 | _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } | |
165 | fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { } | |
166 | fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } | |
167 | fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } | |
168 | fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { } | |
169 | fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { } | |
b039eaaf SL |
170 | fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { } |
171 | fn check_path_list_item(&mut self, _: &LateContext, _: &hir::PathListItem) { } | |
172 | fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { } | |
173 | ||
174 | /// Called when entering a syntax node that can have lint attributes such | |
175 | /// as `#[allow(...)]`. Called with *all* the attributes of that node. | |
176 | fn enter_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { } | |
177 | ||
178 | /// Counterpart to `enter_lint_attrs`. | |
179 | fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { } | |
180 | } | |
181 | ||
182 | pub trait EarlyLintPass: LintPass { | |
183 | fn check_ident(&mut self, _: &EarlyContext, _: Span, _: ast::Ident) { } | |
184 | fn check_crate(&mut self, _: &EarlyContext, _: &ast::Crate) { } | |
7453a54e | 185 | fn check_crate_post(&mut self, _: &EarlyContext, _: &ast::Crate) { } |
b039eaaf | 186 | fn check_mod(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { } |
7453a54e | 187 | fn check_mod_post(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { } |
b039eaaf | 188 | fn check_foreign_item(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { } |
7453a54e | 189 | fn check_foreign_item_post(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { } |
b039eaaf | 190 | fn check_item(&mut self, _: &EarlyContext, _: &ast::Item) { } |
7453a54e | 191 | fn check_item_post(&mut self, _: &EarlyContext, _: &ast::Item) { } |
b039eaaf SL |
192 | fn check_local(&mut self, _: &EarlyContext, _: &ast::Local) { } |
193 | fn check_block(&mut self, _: &EarlyContext, _: &ast::Block) { } | |
7453a54e | 194 | fn check_block_post(&mut self, _: &EarlyContext, _: &ast::Block) { } |
b039eaaf SL |
195 | fn check_stmt(&mut self, _: &EarlyContext, _: &ast::Stmt) { } |
196 | fn check_arm(&mut self, _: &EarlyContext, _: &ast::Arm) { } | |
197 | fn check_pat(&mut self, _: &EarlyContext, _: &ast::Pat) { } | |
b039eaaf SL |
198 | fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { } |
199 | fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { } | |
200 | fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { } | |
201 | fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { } | |
202 | fn check_fn(&mut self, _: &EarlyContext, | |
203 | _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } | |
7453a54e SL |
204 | fn check_fn_post(&mut self, _: &EarlyContext, |
205 | _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } | |
b039eaaf | 206 | fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } |
7453a54e | 207 | fn check_trait_item_post(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } |
b039eaaf | 208 | fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } |
7453a54e | 209 | fn check_impl_item_post(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } |
b039eaaf SL |
210 | fn check_struct_def(&mut self, _: &EarlyContext, |
211 | _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } | |
212 | fn check_struct_def_post(&mut self, _: &EarlyContext, | |
213 | _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } | |
214 | fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { } | |
215 | fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } | |
216 | fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } | |
217 | fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { } | |
218 | fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { } | |
b039eaaf SL |
219 | fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { } |
220 | fn check_path_list_item(&mut self, _: &EarlyContext, _: &ast::PathListItem) { } | |
221 | fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { } | |
1a4d82fc JJ |
222 | |
223 | /// Called when entering a syntax node that can have lint attributes such | |
224 | /// as `#[allow(...)]`. Called with *all* the attributes of that node. | |
b039eaaf | 225 | fn enter_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { } |
1a4d82fc JJ |
226 | |
227 | /// Counterpart to `enter_lint_attrs`. | |
b039eaaf | 228 | fn exit_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { } |
1a4d82fc JJ |
229 | } |
230 | ||
231 | /// A lint pass boxed up as a trait object. | |
b039eaaf SL |
232 | pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>; |
233 | pub type LateLintPassObject = Box<LateLintPass + 'static>; | |
1a4d82fc JJ |
234 | |
235 | /// Identifies a lint known to the compiler. | |
92a42be0 | 236 | #[derive(Clone, Copy, Debug)] |
1a4d82fc JJ |
237 | pub struct LintId { |
238 | // Identity is based on pointer equality of this field. | |
239 | lint: &'static Lint, | |
240 | } | |
241 | ||
242 | impl PartialEq for LintId { | |
243 | fn eq(&self, other: &LintId) -> bool { | |
244 | (self.lint as *const Lint) == (other.lint as *const Lint) | |
245 | } | |
246 | } | |
247 | ||
248 | impl Eq for LintId { } | |
249 | ||
85aaf69f SL |
250 | impl hash::Hash for LintId { |
251 | fn hash<H: hash::Hasher>(&self, state: &mut H) { | |
252 | let ptr = self.lint as *const Lint; | |
253 | ptr.hash(state); | |
254 | } | |
255 | } | |
1a4d82fc JJ |
256 | |
257 | impl LintId { | |
258 | /// Get the `LintId` for a `Lint`. | |
259 | pub fn of(lint: &'static Lint) -> LintId { | |
260 | LintId { | |
261 | lint: lint, | |
262 | } | |
263 | } | |
264 | ||
265 | /// Get the name of the lint. | |
9e0c209e | 266 | pub fn to_string(&self) -> String { |
1a4d82fc JJ |
267 | self.lint.name_lower() |
268 | } | |
269 | } | |
270 | ||
271 | /// Setting for how to handle a lint. | |
5bcae85e | 272 | #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] |
1a4d82fc JJ |
273 | pub enum Level { |
274 | Allow, Warn, Deny, Forbid | |
275 | } | |
276 | ||
277 | impl Level { | |
278 | /// Convert a level to a lower-case string. | |
279 | pub fn as_str(self) -> &'static str { | |
280 | match self { | |
281 | Allow => "allow", | |
282 | Warn => "warn", | |
283 | Deny => "deny", | |
284 | Forbid => "forbid", | |
285 | } | |
286 | } | |
287 | ||
288 | /// Convert a lower-case string to a level. | |
289 | pub fn from_str(x: &str) -> Option<Level> { | |
290 | match x { | |
291 | "allow" => Some(Allow), | |
292 | "warn" => Some(Warn), | |
293 | "deny" => Some(Deny), | |
294 | "forbid" => Some(Forbid), | |
295 | _ => None, | |
296 | } | |
297 | } | |
298 | } | |
299 | ||
300 | /// How a lint level was set. | |
301 | #[derive(Clone, Copy, PartialEq, Eq)] | |
302 | pub enum LintSource { | |
303 | /// Lint is at the default level as declared | |
304 | /// in rustc or a plugin. | |
305 | Default, | |
306 | ||
307 | /// Lint level was set by an attribute. | |
308 | Node(Span), | |
309 | ||
310 | /// Lint level was set by a command-line flag. | |
311 | CommandLine, | |
1a4d82fc JJ |
312 | } |
313 | ||
314 | pub type LevelSource = (Level, LintSource); | |
315 | ||
316 | pub mod builtin; | |
1a4d82fc | 317 | mod context; |