]> git.proxmox.com Git - rustc.git/blame - src/librustc/lint/mod.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librustc / lint / mod.rs
CommitLineData
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
31pub use self::Level::*;
32pub use self::LintSource::*;
33
34use std::hash;
35use std::ascii::AsciiExt;
3157f602 36use syntax_pos::Span;
54a0048b 37use hir::intravisit::FnKind;
b039eaaf 38use syntax::visit as ast_visit;
1a4d82fc 39use syntax::ast;
54a0048b 40use hir;
1a4d82fc 41
b039eaaf
SL
42pub 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
48pub 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
70impl 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]
79macro_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]
91macro_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]
104macro_rules! lint_array { ($( $lint:expr ),*) => (
105 {
62682a34
SL
106 static ARRAY: LintArray = &[ $( &$lint ),* ];
107 ARRAY
1a4d82fc
JJ
108 }
109) }
110
111pub type LintArray = &'static [&'static &'static Lint];
112
1a4d82fc
JJ
113pub 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`.
132pub 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
182pub 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
232pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>;
233pub type LateLintPassObject = Box<LateLintPass + 'static>;
1a4d82fc
JJ
234
235/// Identifies a lint known to the compiler.
92a42be0 236#[derive(Clone, Copy, Debug)]
1a4d82fc
JJ
237pub struct LintId {
238 // Identity is based on pointer equality of this field.
239 lint: &'static Lint,
240}
241
242impl PartialEq for LintId {
243 fn eq(&self, other: &LintId) -> bool {
244 (self.lint as *const Lint) == (other.lint as *const Lint)
245 }
246}
247
248impl Eq for LintId { }
249
85aaf69f
SL
250impl 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
257impl 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
273pub enum Level {
274 Allow, Warn, Deny, Forbid
275}
276
277impl 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)]
302pub 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
314pub type LevelSource = (Level, LintSource);
315
316pub mod builtin;
1a4d82fc 317mod context;