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