2014-01-25 20:37:51 +13:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 16:48:01 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
//! Lints, aka compiler warnings.
|
|
|
|
//!
|
2013-10-02 11:29:29 -07:00
|
|
|
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
|
|
|
|
//! want to enforce, but might reasonably want to permit as well, on a
|
|
|
|
//! module-by-module basis. They contrast with static constraints enforced by
|
|
|
|
//! other phases of the compiler, which are generally required to hold in order
|
|
|
|
//! to compile the program at all.
|
|
|
|
//!
|
2014-06-06 15:49:48 -07:00
|
|
|
//! Most lints can be written as `LintPass` instances. These run just before
|
|
|
|
//! translation to LLVM bytecode. The `LintPass`es built into rustc are defined
|
|
|
|
//! within `builtin.rs`, which has further comments on how to add such a lint.
|
2014-06-18 17:26:14 -07:00
|
|
|
//! rustc can also load user-defined lint plugins via the plugin mechanism.
|
2014-06-02 15:27:15 -07:00
|
|
|
//!
|
2014-06-06 15:49:48 -07:00
|
|
|
//! Some of rustc's lints are defined elsewhere in the compiler and work by
|
|
|
|
//! calling `add_lint()` on the overall `Session` object. This works when
|
|
|
|
//! it happens before the main lint pass, which emits the lints stored by
|
|
|
|
//! `add_lint()`. To emit lints after the main lint pass (from trans, for
|
|
|
|
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
|
|
|
//! in `context.rs`.
|
2013-05-17 15:28:44 -07:00
|
|
|
|
2014-11-06 00:05:53 -08:00
|
|
|
pub use self::Level::*;
|
|
|
|
pub use self::LintSource::*;
|
|
|
|
|
2014-06-04 14:35:58 -07:00
|
|
|
use std::hash;
|
2014-07-18 14:53:29 +01:00
|
|
|
use std::ascii::AsciiExt;
|
2013-08-31 18:13:04 +02:00
|
|
|
use syntax::codemap::Span;
|
2014-06-06 15:49:48 -07:00
|
|
|
use syntax::visit::FnKind;
|
|
|
|
use syntax::ast;
|
|
|
|
|
2014-06-13 15:03:26 -07:00
|
|
|
pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs};
|
2012-12-23 17:41:37 -05:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Specification of a single lint.
|
2015-01-28 08:34:18 -05:00
|
|
|
#[derive(Copy, Debug)]
|
2014-06-06 15:49:48 -07:00
|
|
|
pub struct Lint {
|
|
|
|
/// A string identifier for the lint.
|
|
|
|
///
|
2014-06-13 13:04:52 -07:00
|
|
|
/// This identifies the lint in attributes and in command-line arguments.
|
|
|
|
/// In those contexts it is always lowercase, but this field is compared
|
|
|
|
/// in a way which is case-insensitive for ASCII characters. This allows
|
|
|
|
/// `declare_lint!()` invocations to follow the convention of upper-case
|
|
|
|
/// statics without repeating the name.
|
|
|
|
///
|
|
|
|
/// The name is written with underscores, e.g. "unused_imports".
|
|
|
|
/// On the command line, underscores become dashes.
|
2014-06-06 15:49:48 -07:00
|
|
|
pub name: &'static str,
|
|
|
|
|
|
|
|
/// Default level for the lint.
|
|
|
|
pub default_level: Level,
|
|
|
|
|
|
|
|
/// Description of the lint or the issue it detects.
|
|
|
|
///
|
|
|
|
/// e.g. "imports that are never used"
|
|
|
|
pub desc: &'static str,
|
|
|
|
}
|
|
|
|
|
2014-06-13 13:04:52 -07:00
|
|
|
impl Lint {
|
|
|
|
/// Get the lint's name, with ASCII letters converted to lowercase.
|
|
|
|
pub fn name_lower(&self) -> String {
|
2014-12-05 09:57:42 -08:00
|
|
|
self.name.to_ascii_lowercase()
|
2014-06-13 13:04:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Build a `Lint` initializer.
|
2014-06-04 14:35:58 -07:00
|
|
|
#[macro_export]
|
2014-11-14 09:18:10 -08:00
|
|
|
macro_rules! lint_initializer {
|
2014-06-04 14:35:58 -07:00
|
|
|
($name:ident, $level:ident, $desc:expr) => (
|
|
|
|
::rustc::lint::Lint {
|
|
|
|
name: stringify!($name),
|
|
|
|
default_level: ::rustc::lint::$level,
|
|
|
|
desc: $desc,
|
|
|
|
}
|
|
|
|
)
|
2014-11-14 09:18:10 -08:00
|
|
|
}
|
2014-06-04 14:35:58 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Declare a static item of type `&'static Lint`.
|
2014-06-04 14:35:58 -07:00
|
|
|
#[macro_export]
|
2014-11-14 09:18:10 -08:00
|
|
|
macro_rules! declare_lint {
|
2014-06-04 14:35:58 -07:00
|
|
|
// FIXME(#14660): deduplicate
|
|
|
|
(pub $name:ident, $level:ident, $desc:expr) => (
|
|
|
|
pub static $name: &'static ::rustc::lint::Lint
|
|
|
|
= &lint_initializer!($name, $level, $desc);
|
|
|
|
);
|
|
|
|
($name:ident, $level:ident, $desc:expr) => (
|
|
|
|
static $name: &'static ::rustc::lint::Lint
|
|
|
|
= &lint_initializer!($name, $level, $desc);
|
|
|
|
);
|
2014-11-14 09:18:10 -08:00
|
|
|
}
|
2014-06-04 14:35:58 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Declare a static `LintArray` and return it as an expression.
|
2014-06-04 14:35:58 -07:00
|
|
|
#[macro_export]
|
2014-11-14 09:18:10 -08:00
|
|
|
macro_rules! lint_array { ($( $lint:expr ),*) => (
|
2014-06-04 14:35:58 -07:00
|
|
|
{
|
2014-10-27 15:37:07 -07:00
|
|
|
#[allow(non_upper_case_globals)]
|
2014-10-06 17:30:54 -07:00
|
|
|
static array: LintArray = &[ $( &$lint ),* ];
|
2014-06-04 14:35:58 -07:00
|
|
|
array
|
|
|
|
}
|
2014-11-14 09:18:10 -08:00
|
|
|
) }
|
2014-06-01 16:16:00 -07:00
|
|
|
|
2014-10-06 17:30:54 -07:00
|
|
|
pub type LintArray = &'static [&'static &'static Lint];
|
2014-06-04 14:35:58 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Trait for types providing lint checks.
|
|
|
|
///
|
|
|
|
/// Each `check` method checks a single syntax node, and should not
|
|
|
|
/// invoke methods recursively (unlike `Visitor`). By default they
|
|
|
|
/// do nothing.
|
2014-06-02 15:27:15 -07:00
|
|
|
//
|
2014-06-04 14:35:58 -07:00
|
|
|
// FIXME: eliminate the duplication with `Visitor`. But this also
|
|
|
|
// contains a few lint-specific methods with no equivalent in `Visitor`.
|
2014-06-10 14:03:19 -07:00
|
|
|
pub trait LintPass {
|
2014-06-04 14:35:58 -07:00
|
|
|
/// Get descriptions of the lints this `LintPass` object can emit.
|
|
|
|
///
|
|
|
|
/// NB: there is no enforcement that the object only emits lints it registered.
|
|
|
|
/// And some `rustc` internal `LintPass`es register lints to be emitted by other
|
|
|
|
/// parts of the compiler. If you want enforced access restrictions for your
|
|
|
|
/// `Lint`, make it a private `static` item in its own module.
|
|
|
|
fn get_lints(&self) -> LintArray;
|
|
|
|
|
2014-06-17 17:06:04 -07:00
|
|
|
fn check_crate(&mut self, _: &Context, _: &ast::Crate) { }
|
2014-06-02 15:27:15 -07:00
|
|
|
fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
|
|
|
|
fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
|
|
|
|
fn check_foreign_item(&mut self, _: &Context, _: &ast::ForeignItem) { }
|
|
|
|
fn check_item(&mut self, _: &Context, _: &ast::Item) { }
|
|
|
|
fn check_local(&mut self, _: &Context, _: &ast::Local) { }
|
|
|
|
fn check_block(&mut self, _: &Context, _: &ast::Block) { }
|
|
|
|
fn check_stmt(&mut self, _: &Context, _: &ast::Stmt) { }
|
|
|
|
fn check_arm(&mut self, _: &Context, _: &ast::Arm) { }
|
|
|
|
fn check_pat(&mut self, _: &Context, _: &ast::Pat) { }
|
|
|
|
fn check_decl(&mut self, _: &Context, _: &ast::Decl) { }
|
|
|
|
fn check_expr(&mut self, _: &Context, _: &ast::Expr) { }
|
|
|
|
fn check_expr_post(&mut self, _: &Context, _: &ast::Expr) { }
|
|
|
|
fn check_ty(&mut self, _: &Context, _: &ast::Ty) { }
|
|
|
|
fn check_generics(&mut self, _: &Context, _: &ast::Generics) { }
|
|
|
|
fn check_fn(&mut self, _: &Context,
|
2014-09-10 01:54:36 +03:00
|
|
|
_: FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
|
2014-06-02 15:27:15 -07:00
|
|
|
fn check_ty_method(&mut self, _: &Context, _: &ast::TypeMethod) { }
|
2014-08-04 13:56:56 -07:00
|
|
|
fn check_trait_method(&mut self, _: &Context, _: &ast::TraitItem) { }
|
2014-06-02 15:27:15 -07:00
|
|
|
fn check_struct_def(&mut self, _: &Context,
|
|
|
|
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
|
|
|
|
fn check_struct_def_post(&mut self, _: &Context,
|
|
|
|
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
|
|
|
|
fn check_struct_field(&mut self, _: &Context, _: &ast::StructField) { }
|
|
|
|
fn check_variant(&mut self, _: &Context, _: &ast::Variant, _: &ast::Generics) { }
|
2014-11-15 17:57:54 -08:00
|
|
|
fn check_variant_post(&mut self, _: &Context, _: &ast::Variant, _: &ast::Generics) { }
|
2014-06-02 15:27:15 -07:00
|
|
|
fn check_opt_lifetime_ref(&mut self, _: &Context, _: Span, _: &Option<ast::Lifetime>) { }
|
|
|
|
fn check_lifetime_ref(&mut self, _: &Context, _: &ast::Lifetime) { }
|
2014-11-18 17:39:16 +01:00
|
|
|
fn check_lifetime_def(&mut self, _: &Context, _: &ast::LifetimeDef) { }
|
2014-06-02 15:27:15 -07:00
|
|
|
fn check_explicit_self(&mut self, _: &Context, _: &ast::ExplicitSelf) { }
|
|
|
|
fn check_mac(&mut self, _: &Context, _: &ast::Mac) { }
|
|
|
|
fn check_path(&mut self, _: &Context, _: &ast::Path, _: ast::NodeId) { }
|
|
|
|
fn check_attribute(&mut self, _: &Context, _: &ast::Attribute) { }
|
|
|
|
|
|
|
|
/// Called when entering a syntax node that can have lint attributes such
|
|
|
|
/// as `#[allow(...)]`. Called with *all* the attributes of that node.
|
|
|
|
fn enter_lint_attrs(&mut self, _: &Context, _: &[ast::Attribute]) { }
|
|
|
|
|
|
|
|
/// Counterpart to `enter_lint_attrs`.
|
|
|
|
fn exit_lint_attrs(&mut self, _: &Context, _: &[ast::Attribute]) { }
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// A lint pass boxed up as a trait object.
|
|
|
|
pub type LintPassObject = Box<LintPass + 'static>;
|
2014-06-02 15:27:15 -07:00
|
|
|
|
2014-06-04 14:35:58 -07:00
|
|
|
/// Identifies a lint known to the compiler.
|
2015-01-03 22:54:18 -05:00
|
|
|
#[derive(Clone, Copy)]
|
2014-06-04 14:35:58 -07:00
|
|
|
pub struct LintId {
|
|
|
|
// Identity is based on pointer equality of this field.
|
|
|
|
lint: &'static Lint,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for LintId {
|
|
|
|
fn eq(&self, other: &LintId) -> bool {
|
2014-06-25 12:47:34 -07:00
|
|
|
(self.lint as *const Lint) == (other.lint as *const Lint)
|
2014-06-04 14:35:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for LintId { }
|
|
|
|
|
std: Stabilize the std::hash module
This commit aims to prepare the `std::hash` module for alpha by formalizing its
current interface whileholding off on adding `#[stable]` to the new APIs. The
current usage with the `HashMap` and `HashSet` types is also reconciled by
separating out composable parts of the design. The primary goal of this slight
redesign is to separate the concepts of a hasher's state from a hashing
algorithm itself.
The primary change of this commit is to separate the `Hasher` trait into a
`Hasher` and a `HashState` trait. Conceptually the old `Hasher` trait was
actually just a factory for various states, but hashing had very little control
over how these states were used. Additionally the old `Hasher` trait was
actually fairly unrelated to hashing.
This commit redesigns the existing `Hasher` trait to match what the notion of a
`Hasher` normally implies with the following definition:
trait Hasher {
type Output;
fn reset(&mut self);
fn finish(&self) -> Output;
}
This `Hasher` trait emphasizes that hashing algorithms may produce outputs other
than a `u64`, so the output type is made generic. Other than that, however, very
little is assumed about a particular hasher. It is left up to implementors to
provide specific methods or trait implementations to feed data into a hasher.
The corresponding `Hash` trait becomes:
trait Hash<H: Hasher> {
fn hash(&self, &mut H);
}
The old default of `SipState` was removed from this trait as it's not something
that we're willing to stabilize until the end of time, but the type parameter is
always required to implement `Hasher`. Note that the type parameter `H` remains
on the trait to enable multidispatch for specialization of hashing for
particular hashers.
Note that `Writer` is not mentioned in either of `Hash` or `Hasher`, it is
simply used as part `derive` and the implementations for all primitive types.
With these definitions, the old `Hasher` trait is realized as a new `HashState`
trait in the `collections::hash_state` module as an unstable addition for
now. The current definition looks like:
trait HashState {
type Hasher: Hasher;
fn hasher(&self) -> Hasher;
}
The purpose of this trait is to emphasize that the one piece of functionality
for implementors is that new instances of `Hasher` can be created. This
conceptually represents the two keys from which more instances of a
`SipHasher` can be created, and a `HashState` is what's stored in a
`HashMap`, not a `Hasher`.
Implementors of custom hash algorithms should implement the `Hasher` trait, and
only hash algorithms intended for use in hash maps need to implement or worry
about the `HashState` trait.
The entire module and `HashState` infrastructure remains `#[unstable]` due to it
being recently redesigned, but some other stability decision made for the
`std::hash` module are:
* The `Writer` trait remains `#[experimental]` as it's intended to be replaced
with an `io::Writer` (more details soon).
* The top-level `hash` function is `#[unstable]` as it is intended to be generic
over the hashing algorithm instead of hardwired to `SipHasher`
* The inner `sip` module is now private as its one export, `SipHasher` is
reexported in the `hash` module.
And finally, a few changes were made to the default parameters on `HashMap`.
* The `RandomSipHasher` default type parameter was renamed to `RandomState`.
This renaming emphasizes that it is not a hasher, but rather just state to
generate hashers. It also moves away from the name "sip" as it may not always
be implemented as `SipHasher`. This type lives in the
`std::collections::hash_map` module as `#[unstable]`
* The associated `Hasher` type of `RandomState` is creatively called...
`Hasher`! This concrete structure lives next to `RandomState` as an
implemenation of the "default hashing algorithm" used for a `HashMap`. Under
the hood this is currently implemented as `SipHasher`, but it draws an
explicit interface for now and allows us to modify the implementation over
time if necessary.
There are many breaking changes outlined above, and as a result this commit is
a:
[breaking-change]
2014-12-09 12:37:23 -08:00
|
|
|
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for LintId {
|
2014-06-04 14:35:58 -07:00
|
|
|
fn hash(&self, state: &mut S) {
|
2014-06-25 12:47:34 -07:00
|
|
|
let ptr = self.lint as *const Lint;
|
2014-06-04 14:35:58 -07:00
|
|
|
ptr.hash(state);
|
|
|
|
}
|
2012-01-19 16:50:51 +08:00
|
|
|
}
|
|
|
|
|
2014-06-04 14:35:58 -07:00
|
|
|
impl LintId {
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Get the `LintId` for a `Lint`.
|
2014-06-04 14:35:58 -07:00
|
|
|
pub fn of(lint: &'static Lint) -> LintId {
|
|
|
|
LintId {
|
|
|
|
lint: lint,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Get the name of the lint.
|
2014-06-13 13:04:52 -07:00
|
|
|
pub fn as_str(&self) -> String {
|
|
|
|
self.lint.name_lower()
|
Nomenclature fixes in the lint checker. Fewer double-negatives.
New style is allow(foo), warn(foo), deny(foo) and forbid(foo),
mirrored by -A foo, -W foo, -D foo and -F foo on command line.
These replace -W no-foo, -W foo, -W err-foo, respectively.
Forbid is new, and means "deny, and you can't override it".
2012-07-26 17:08:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Setting for how to handle a lint.
|
2015-01-28 08:34:18 -05:00
|
|
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug)]
|
2014-05-21 21:50:37 +10:00
|
|
|
pub enum Level {
|
|
|
|
Allow, Warn, Deny, Forbid
|
2012-01-22 01:20:22 +08:00
|
|
|
}
|
|
|
|
|
2014-06-04 14:35:58 -07:00
|
|
|
impl Level {
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Convert a level to a lower-case string.
|
2014-06-04 14:35:58 -07:00
|
|
|
pub fn as_str(self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
Allow => "allow",
|
|
|
|
Warn => "warn",
|
|
|
|
Deny => "deny",
|
|
|
|
Forbid => "forbid",
|
|
|
|
}
|
|
|
|
}
|
2013-07-16 21:12:16 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Convert a lower-case string to a level.
|
2014-06-04 14:35:58 -07:00
|
|
|
pub fn from_str(x: &str) -> Option<Level> {
|
|
|
|
match x {
|
|
|
|
"allow" => Some(Allow),
|
|
|
|
"warn" => Some(Warn),
|
|
|
|
"deny" => Some(Deny),
|
|
|
|
"forbid" => Some(Forbid),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-30 01:15:17 -04:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// How a lint level was set.
|
2015-01-03 22:54:18 -05:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
2014-05-19 14:57:24 -07:00
|
|
|
pub enum LintSource {
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Lint is at the default level as declared
|
|
|
|
/// in rustc or a plugin.
|
2013-05-09 13:22:26 -04:00
|
|
|
Default,
|
2012-06-04 16:07:54 -07:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Lint level was set by an attribute.
|
|
|
|
Node(Span),
|
2013-05-28 15:44:53 -05:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Lint level was set by a command-line flag.
|
|
|
|
CommandLine,
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
|
|
|
|
/// Lint level was set by the release channel.
|
|
|
|
ReleaseChannel
|
2013-05-24 10:27:31 +02:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
pub type LevelSource = (Level, LintSource);
|
2013-04-30 01:15:17 -04:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
pub mod builtin;
|
2013-05-07 02:07:00 -04:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
mod context;
|