Replace enum LintId with an extensible alternative

This commit is contained in:
Keegan McAllister 2014-06-04 14:35:58 -07:00
parent 69b6bc5eee
commit 442fbc473e
16 changed files with 742 additions and 764 deletions

View File

@ -70,7 +70,8 @@ pub struct Options {
pub gc: bool,
pub optimize: OptLevel,
pub debuginfo: DebugInfoLevel,
pub lint_opts: Vec<(lint::LintId, lint::Level)> ,
pub lint_opts: Vec<(String, lint::Level)>,
pub describe_lints: bool,
pub output_types: Vec<back::link::OutputType> ,
// This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use
@ -104,6 +105,7 @@ pub fn basic_options() -> Options {
optimize: No,
debuginfo: NoDebugInfo,
lint_opts: Vec::new(),
describe_lints: false,
output_types: Vec::new(),
addl_lib_search_paths: RefCell::new(HashSet::new()),
maybe_sysroot: None,
@ -585,30 +587,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let no_trans = matches.opt_present("no-trans");
let no_analysis = matches.opt_present("no-analysis");
let lint_levels = [lint::Allow, lint::Warn,
lint::Deny, lint::Forbid];
let mut lint_opts = Vec::new();
let lint_dict = lint::get_lint_dict();
for level in lint_levels.iter() {
let level_name = lint::level_to_str(*level);
let mut lint_opts = vec!();
let mut describe_lints = false;
let level_short = level_name.slice_chars(0, 1);
let level_short = level_short.to_ascii().to_upper().into_str();
let flags = matches.opt_strs(level_short.as_slice())
.move_iter()
.collect::<Vec<_>>()
.append(matches.opt_strs(level_name).as_slice());
for lint_name in flags.iter() {
let lint_name = lint_name.replace("-", "_").into_string();
match lint_dict.find_equiv(&lint_name) {
None => {
early_error(format!("unknown {} flag: {}",
level_name,
lint_name).as_slice());
}
Some(lint) => {
lint_opts.push((lint.lint, *level));
}
for &level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid].iter() {
for lint_name in matches.opt_strs(level.as_str()).move_iter() {
if lint_name.as_slice() == "help" {
describe_lints = true;
} else {
lint_opts.push((lint_name.replace("-", "_").into_string(), level));
}
}
}
@ -752,6 +739,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
optimize: opt_level,
debuginfo: debuginfo,
lint_opts: lint_opts,
describe_lints: describe_lints,
output_types: output_types,
addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
maybe_sysroot: sysroot_opt,

View File

@ -767,7 +767,7 @@ pub fn collect_crate_types(session: &Session,
}
Some(ref n) if n.equiv(&("bin")) => Some(config::CrateTypeExecutable),
Some(_) => {
session.add_lint(lint::UnknownCrateType,
session.add_lint(lint::builtin::unknown_crate_type,
ast::CRATE_NODE_ID,
a.span,
"invalid `crate_type` \
@ -775,7 +775,7 @@ pub fn collect_crate_types(session: &Session,
None
}
_ => {
session.add_lint(lint::UnknownCrateType,
session.add_lint(lint::builtin::unknown_crate_type,
ast::CRATE_NODE_ID,
a.span,
"`crate_type` requires a \

View File

@ -17,7 +17,6 @@ use lint;
use metadata;
use std::any::AnyRefExt;
use std::cmp;
use std::io;
use std::os;
use std::str;
@ -50,6 +49,12 @@ fn run_compiler(args: &[String]) {
None => return
};
let sopts = config::build_session_options(&matches);
if sopts.describe_lints {
describe_lints();
return;
}
let (input, input_file_path) = match matches.free.len() {
0u => early_error("no input filename given"),
1u => {
@ -66,7 +71,6 @@ fn run_compiler(args: &[String]) {
_ => early_error("multiple input filenames provided")
};
let sopts = config::build_session_options(&matches);
let sess = build_session(sopts, input_file_path);
let cfg = config::build_configuration(&sess);
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
@ -124,7 +128,7 @@ Additional help:
config::optgroups().as_slice()));
}
fn describe_warnings() {
fn describe_lints() {
println!("
Available lint options:
-W <foo> Warn about <foo>
@ -133,30 +137,32 @@ Available lint options:
-F <foo> Forbid <foo> (deny, and deny all overrides)
");
let lint_dict = lint::get_lint_dict();
let mut lint_dict = lint_dict.move_iter()
.map(|(k, v)| (v, k))
.collect::<Vec<(lint::LintSpec, &'static str)> >();
lint_dict.as_mut_slice().sort();
let mut builtin_specs = lint::builtin_lint_specs();
builtin_specs.sort_by(|x, y| {
match x.default_level.cmp(&y.default_level) {
Equal => x.name.cmp(&y.name),
r => r,
}
});
// FIXME: What if someone uses combining characters or East Asian fullwidth
// characters in a lint name?!?!?
let max_name_len = builtin_specs.iter()
.map(|&s| s.name.char_len())
.max().unwrap_or(0);
let padded = |x: &str| {
format!("{}{}", " ".repeat(max_name_len - x.char_len()), x)
};
let mut max_key = 0;
for &(_, name) in lint_dict.iter() {
max_key = cmp::max(name.len(), max_key);
}
fn padded(max: uint, s: &str) -> String {
format!("{}{}", " ".repeat(max - s.len()), s)
}
println!("\nAvailable lint checks:\n");
println!(" {} {:7.7s} {}",
padded(max_key, "name"), "default", "meaning");
println!(" {} {:7.7s} {}\n",
padded(max_key, "----"), "-------", "-------");
for (spec, name) in lint_dict.move_iter() {
let name = name.replace("_", "-");
println!(" {} {:7.7s} {}", padded("name"), "default", "meaning");
println!(" {} {:7.7s} {}", padded("----"), "-------", "-------");
println!("");
for spec in builtin_specs.move_iter() {
let name = spec.name.replace("_", "-");
println!(" {} {:7.7s} {}",
padded(max_key, name.as_slice()),
lint::level_to_str(spec.default),
spec.desc);
padded(name.as_slice()), spec.default_level.as_str(), spec.desc);
}
println!("");
}
@ -214,12 +220,7 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
return None;
}
let lint_flags = matches.opt_strs("W").move_iter().collect::<Vec<_>>().append(
matches.opt_strs("warn").as_slice());
if lint_flags.iter().any(|x| x.as_slice() == "help") {
describe_warnings();
return None;
}
// Don't handle -W help here, because we might first load plugins.
let r = matches.opt_strs("Z");
if r.iter().any(|x| x.as_slice() == "help") {

View File

@ -106,16 +106,17 @@ impl Session {
self.diagnostic().handler().unimpl(msg)
}
pub fn add_lint(&self,
lint: lint::LintId,
lint: &'static lint::Lint,
id: ast::NodeId,
sp: Span,
msg: String) {
let lint_id = lint::LintId::of(lint);
let mut lints = self.lints.borrow_mut();
match lints.find_mut(&id) {
Some(arr) => { arr.push((lint, sp, msg)); return; }
Some(arr) => { arr.push((lint_id, sp, msg)); return; }
None => {}
}
lints.insert(id, vec!((lint, sp, msg)));
lints.insert(id, vec!((lint_id, sp, msg)));
}
pub fn next_node_id(&self) -> ast::NodeId {
self.reserve_node_ids(1)

View File

@ -409,7 +409,7 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
directive not necessary");
}
None => {
sess.add_lint(lint::UnknownFeatures,
sess.add_lint(lint::builtin::unknown_features,
ast::CRATE_NODE_ID,
mi.span,
"unknown feature".to_string());

View File

@ -127,6 +127,15 @@ pub mod lib {
pub mod llvmdeps;
}
// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
pub use lint;
}
pub fn main() {
let args = std::os::args().iter()
.map(|x| x.to_string())

View File

@ -19,7 +19,7 @@ use middle::privacy::ExportedItems;
use middle::{typeck, ty, def, pat_util};
use util::ppaux::{ty_to_str};
use util::nodemap::NodeSet;
use lint::{Context, LintPass};
use lint::{Context, LintPass, LintArray};
use lint;
use std::cmp;
@ -41,31 +41,17 @@ use syntax::codemap::Span;
use syntax::parse::token;
use syntax::{ast, ast_util, visit};
/// Doesn't actually warn; just gathers information for use by
/// checks in trans.
#[deriving(Default)]
pub struct GatherNodeLevels;
impl LintPass for GatherNodeLevels {
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
match it.node {
ast::ItemEnum(..) => {
match cx.cur.find(&(lint::VariantSizeDifference as uint)) {
Some(&(lvl, src)) if lvl != lint::Allow => {
cx.insert_node_level(it.id, lint::VariantSizeDifference, lvl, src);
},
_ => { }
}
},
_ => { }
}
}
}
declare_lint!(while_true, Warn,
"suggest using `loop { }` instead of `while true { }`")
#[deriving(Default)]
pub struct WhileTrue;
impl LintPass for WhileTrue {
fn get_lints(&self) -> LintArray {
lint_array!(while_true)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
ast::ExprWhile(cond, _) => {
@ -73,8 +59,7 @@ impl LintPass for WhileTrue {
ast::ExprLit(lit) => {
match lit.node {
ast::LitBool(true) => {
cx.span_lint(lint::WhileTrue,
e.span,
cx.span_lint(while_true, e.span,
"denote infinite loops with loop \
{ ... }");
}
@ -89,17 +74,23 @@ impl LintPass for WhileTrue {
}
}
declare_lint!(unnecessary_typecast, Allow,
"detects unnecessary type casts, that can be removed")
#[deriving(Default)]
pub struct UnusedCasts;
impl LintPass for UnusedCasts {
fn get_lints(&self) -> LintArray {
lint_array!(unnecessary_typecast)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
ast::ExprCast(expr, ty) => {
let t_t = ast_ty_to_ty(cx, &infer::new_infer_ctxt(cx.tcx), ty);
if ty::get(ty::expr_ty(cx.tcx, expr)).sty == ty::get(t_t).sty {
cx.span_lint(lint::UnnecessaryTypecast, ty.span,
"unnecessary type cast");
cx.span_lint(unnecessary_typecast, ty.span, "unnecessary type cast");
}
}
_ => ()
@ -107,6 +98,15 @@ impl LintPass for UnusedCasts {
}
}
declare_lint!(unsigned_negate, Warn,
"using an unary minus operator on unsigned type")
declare_lint!(type_limits, Warn,
"comparisons made useless by limits of the types involved")
declare_lint!(type_overflow, Warn,
"literal out of range for its type")
pub struct TypeLimits {
/// Id of the last visited negated expression
negated_expr_id: ast::NodeId,
@ -121,6 +121,10 @@ impl Default for TypeLimits {
}
impl LintPass for TypeLimits {
fn get_lints(&self) -> LintArray {
lint_array!(unsigned_negate, type_limits, type_overflow)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
ast::ExprUnary(ast::UnNeg, expr) => {
@ -128,7 +132,7 @@ impl LintPass for TypeLimits {
ast::ExprLit(lit) => {
match lit.node {
ast::LitUint(..) => {
cx.span_lint(lint::UnsignedNegate, e.span,
cx.span_lint(unsigned_negate, e.span,
"negation of unsigned int literal may \
be unintentional");
},
@ -139,7 +143,7 @@ impl LintPass for TypeLimits {
let t = ty::expr_ty(cx.tcx, expr);
match ty::get(t).sty {
ty::ty_uint(_) => {
cx.span_lint(lint::UnsignedNegate, e.span,
cx.span_lint(unsigned_negate, e.span,
"negation of unsigned int variable may \
be unintentional");
},
@ -157,7 +161,7 @@ impl LintPass for TypeLimits {
},
ast::ExprBinary(binop, l, r) => {
if is_comparison(binop) && !check_limits(cx.tcx, binop, l, r) {
cx.span_lint(lint::TypeLimits, e.span,
cx.span_lint(type_limits, e.span,
"comparison is useless due to type limits");
}
},
@ -178,7 +182,7 @@ impl LintPass for TypeLimits {
lit_val *= -1;
}
if lit_val < min || lit_val > max {
cx.span_lint(lint::TypeOverflow, e.span,
cx.span_lint(type_overflow, e.span,
"literal out of range for its type");
}
},
@ -194,7 +198,7 @@ impl LintPass for TypeLimits {
_ => fail!()
};
if lit_val < min || lit_val > max {
cx.span_lint(lint::TypeOverflow, e.span,
cx.span_lint(type_overflow, e.span,
"literal out of range for its type");
}
},
@ -300,30 +304,37 @@ impl LintPass for TypeLimits {
}
}
declare_lint!(ctypes, Warn,
"proper use of libc types in foreign modules")
#[deriving(Default)]
pub struct CTypes;
impl LintPass for CTypes {
fn get_lints(&self) -> LintArray {
lint_array!(ctypes)
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
fn check_ty(cx: &Context, ty: &ast::Ty) {
match ty.node {
ast::TyPath(_, _, id) => {
match cx.tcx.def_map.borrow().get_copy(&id) {
def::DefPrimTy(ast::TyInt(ast::TyI)) => {
cx.span_lint(lint::CTypes, ty.span,
"found rust type `int` in foreign module, while \
libc::c_int or libc::c_long should be used");
cx.span_lint(ctypes, ty.span,
"found rust type `int` in foreign module, while \
libc::c_int or libc::c_long should be used");
}
def::DefPrimTy(ast::TyUint(ast::TyU)) => {
cx.span_lint(lint::CTypes, ty.span,
"found rust type `uint` in foreign module, while \
libc::c_uint or libc::c_ulong should be used");
cx.span_lint(ctypes, ty.span,
"found rust type `uint` in foreign module, while \
libc::c_uint or libc::c_ulong should be used");
}
def::DefTy(def_id) => {
if !adt::is_ffi_safe(cx.tcx, def_id) {
cx.span_lint(lint::CTypes, ty.span,
"found enum type without foreign-function-safe \
representation annotation in foreign module");
cx.span_lint(ctypes, ty.span,
"found enum type without foreign-function-safe \
representation annotation in foreign module");
// hmm... this message could be more helpful
}
}
@ -356,54 +367,64 @@ impl LintPass for CTypes {
}
}
declare_lint!(managed_heap_memory, Allow,
"use of managed (@ type) heap memory")
declare_lint!(owned_heap_memory, Allow,
"use of owned (Box type) heap memory")
declare_lint!(heap_memory, Allow,
"use of any (Box type or @ type) heap memory")
#[deriving(Default)]
pub struct HeapMemory;
impl HeapMemory {
fn check_heap_type(&self, cx: &Context, span: Span, ty: ty::t) {
let xs = [lint::ManagedHeapMemory, lint::OwnedHeapMemory, lint::HeapMemory];
for &lint in xs.iter() {
if cx.get_level(lint) == lint::Allow { continue }
let mut n_box = 0;
let mut n_uniq = 0;
ty::fold_ty(cx.tcx, ty, |t| {
match ty::get(t).sty {
ty::ty_box(_) => {
n_box += 1;
}
ty::ty_uniq(_) |
ty::ty_trait(box ty::TyTrait {
store: ty::UniqTraitStore, ..
}) |
ty::ty_closure(box ty::ClosureTy {
store: ty::UniqTraitStore,
..
}) => {
n_uniq += 1;
}
let mut n_box = 0;
let mut n_uniq = 0;
ty::fold_ty(cx.tcx, ty, |t| {
match ty::get(t).sty {
ty::ty_box(_) => {
n_box += 1;
}
ty::ty_uniq(_) |
ty::ty_trait(box ty::TyTrait {
store: ty::UniqTraitStore, ..
}) |
ty::ty_closure(box ty::ClosureTy {
store: ty::UniqTraitStore,
..
}) => {
n_uniq += 1;
}
_ => ()
};
t
});
_ => ()
};
t
});
if n_uniq > 0 {
let s = ty_to_str(cx.tcx, ty);
let m = format!("type uses owned (Box type) pointers: {}", s);
cx.span_lint(owned_heap_memory, span, m.as_slice());
cx.span_lint(heap_memory, span, m.as_slice());
}
if n_uniq > 0 && lint != lint::ManagedHeapMemory {
let s = ty_to_str(cx.tcx, ty);
let m = format!("type uses owned (Box type) pointers: {}", s);
cx.span_lint(lint, span, m.as_slice());
}
if n_box > 0 && lint != lint::OwnedHeapMemory {
let s = ty_to_str(cx.tcx, ty);
let m = format!("type uses managed (@ type) pointers: {}", s);
cx.span_lint(lint, span, m.as_slice());
}
if n_box > 0 {
let s = ty_to_str(cx.tcx, ty);
let m = format!("type uses managed (@ type) pointers: {}", s);
cx.span_lint(managed_heap_memory, span, m.as_slice());
cx.span_lint(heap_memory, span, m.as_slice());
}
}
}
impl LintPass for HeapMemory {
fn get_lints(&self) -> LintArray {
lint_array!(managed_heap_memory, owned_heap_memory, heap_memory)
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
match it.node {
ast::ItemFn(..) |
@ -434,6 +455,9 @@ impl LintPass for HeapMemory {
}
}
declare_lint!(raw_pointer_deriving, Warn,
"uses of #[deriving] with raw pointers are rarely correct")
struct RawPtrDerivingVisitor<'a> {
cx: &'a Context<'a>
}
@ -442,7 +466,7 @@ impl<'a> visit::Visitor<()> for RawPtrDerivingVisitor<'a> {
fn visit_ty(&mut self, ty: &ast::Ty, _: ()) {
static MSG: &'static str = "use of `#[deriving]` with a raw pointer";
match ty.node {
ast::TyPtr(..) => self.cx.span_lint(lint::RawPointerDeriving, ty.span, MSG),
ast::TyPtr(..) => self.cx.span_lint(raw_pointer_deriving, ty.span, MSG),
_ => {}
}
visit::walk_ty(self, ty, ());
@ -465,6 +489,10 @@ impl Default for RawPointerDeriving {
}
impl LintPass for RawPointerDeriving {
fn get_lints(&self) -> LintArray {
lint_array!(raw_pointer_deriving)
}
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
if !attr::contains_name(item.attrs.as_slice(), "automatically_derived") {
return
@ -495,10 +523,17 @@ impl LintPass for RawPointerDeriving {
}
}
declare_lint!(unused_attribute, Warn,
"detects attributes that were not used by the compiler")
#[deriving(Default)]
pub struct UnusedAttribute;
impl LintPass for UnusedAttribute {
fn get_lints(&self) -> LintArray {
lint_array!(unused_attribute)
}
fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
static ATTRIBUTE_WHITELIST: &'static [&'static str] = &'static [
// FIXME: #14408 whitelist docs since rustdoc looks at them
@ -556,7 +591,7 @@ impl LintPass for UnusedAttribute {
}
if !attr::is_used(attr) {
cx.span_lint(lint::UnusedAttribute, attr.span, "unused attribute");
cx.span_lint(unused_attribute, attr.span, "unused attribute");
if CRATE_ATTRS.contains(&attr.name().get()) {
let msg = match attr.node.style {
ast::AttrOuter => "crate-level attribute should be an inner \
@ -564,26 +599,30 @@ impl LintPass for UnusedAttribute {
ast::AttrInner => "crate-level attribute should be in the \
root module",
};
cx.span_lint(lint::UnusedAttribute, attr.span, msg);
cx.span_lint(unused_attribute, attr.span, msg);
}
}
}
}
declare_lint!(path_statement, Warn,
"path statements with no effect")
#[deriving(Default)]
pub struct PathStatement;
impl LintPass for PathStatement {
fn get_lints(&self) -> LintArray {
lint_array!(path_statement)
}
fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
match s.node {
ast::StmtSemi(expr, _) => {
match expr.node {
ast::ExprPath(_) => {
cx.span_lint(lint::PathStatement,
s.span,
"path statement with no effect");
}
_ => {}
ast::ExprPath(_) => cx.span_lint(path_statement, s.span,
"path statement with no effect"),
_ => ()
}
}
_ => ()
@ -591,10 +630,20 @@ impl LintPass for PathStatement {
}
}
#[deriving(Default)]
pub struct UnusedMustUse;
declare_lint!(unused_must_use, Warn,
"unused result of a type flagged as #[must_use]")
declare_lint!(unused_result, Allow,
"unused result of an expression in a statement")
#[deriving(Default)]
pub struct UnusedResult;
impl LintPass for UnusedResult {
fn get_lints(&self) -> LintArray {
lint_array!(unused_must_use, unused_result)
}
impl LintPass for UnusedMustUse {
fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
let expr = match s.node {
ast::StmtSemi(expr, _) => expr,
@ -620,7 +669,7 @@ impl LintPass for UnusedMustUse {
ast_map::NodeItem(it) => {
if attr::contains_name(it.attrs.as_slice(),
"must_use") {
cx.span_lint(lint::UnusedMustUse, s.span,
cx.span_lint(unused_must_use, s.span,
"unused result which must be used");
warned = true;
}
@ -630,7 +679,7 @@ impl LintPass for UnusedMustUse {
} else {
csearch::get_item_attrs(&cx.tcx.sess.cstore, did, |attrs| {
if attr::contains_name(attrs.as_slice(), "must_use") {
cx.span_lint(lint::UnusedMustUse, s.span,
cx.span_lint(unused_must_use, s.span,
"unused result which must be used");
warned = true;
}
@ -640,21 +689,28 @@ impl LintPass for UnusedMustUse {
_ => {}
}
if !warned {
cx.span_lint(lint::UnusedResult, s.span, "unused result");
cx.span_lint(unused_result, s.span, "unused result");
}
}
}
declare_lint!(deprecated_owned_vector, Allow,
"use of a `~[T]` vector")
#[deriving(Default)]
pub struct DeprecatedOwnedVector;
impl LintPass for DeprecatedOwnedVector {
fn get_lints(&self) -> LintArray {
lint_array!(deprecated_owned_vector)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
let t = ty::expr_ty(cx.tcx, e);
match ty::get(t).sty {
ty::ty_uniq(t) => match ty::get(t).sty {
ty::ty_vec(_, None) => {
cx.span_lint(lint::DeprecatedOwnedVector, e.span,
cx.span_lint(deprecated_owned_vector, e.span,
"use of deprecated `~[]` vector; replaced by `std::vec::Vec`")
}
_ => {}
@ -664,10 +720,17 @@ impl LintPass for DeprecatedOwnedVector {
}
}
declare_lint!(non_camel_case_types, Warn,
"types, variants and traits should have camel case names")
#[deriving(Default)]
pub struct NonCamelCaseTypes;
impl LintPass for NonCamelCaseTypes {
fn get_lints(&self) -> LintArray {
lint_array!(non_camel_case_types)
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
fn is_camel_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
@ -690,8 +753,7 @@ impl LintPass for NonCamelCaseTypes {
let s = token::get_ident(ident);
if !is_camel_case(ident) {
cx.span_lint(lint::
NonCamelCaseTypes, span,
cx.span_lint(non_camel_case_types, span,
format!("{} `{}` should have a camel case name such as `{}`",
sort, s, to_camel_case(s.get())).as_slice());
}
@ -744,6 +806,9 @@ fn method_context(cx: &Context, m: &ast::Method) -> MethodContext {
}
}
declare_lint!(non_snake_case_functions, Warn,
"methods and functions should have snake case names")
#[deriving(Default)]
pub struct NonSnakeCaseFunctions;
@ -785,7 +850,7 @@ impl NonSnakeCaseFunctions {
let s = token::get_ident(ident);
if !is_snake_case(ident) {
cx.span_lint(lint::NonSnakeCaseFunctions, span,
cx.span_lint(non_snake_case_functions, span,
format!("{} `{}` should have a snake case name such as `{}`",
sort, s, to_snake_case(s.get())).as_slice());
}
@ -793,6 +858,10 @@ impl NonSnakeCaseFunctions {
}
impl LintPass for NonSnakeCaseFunctions {
fn get_lints(&self) -> LintArray {
lint_array!(non_snake_case_functions)
}
fn check_fn(&mut self, cx: &Context,
fk: &visit::FnKind, _: &ast::FnDecl,
_: &ast::Block, span: Span, _: ast::NodeId) {
@ -815,10 +884,17 @@ impl LintPass for NonSnakeCaseFunctions {
}
}
declare_lint!(non_uppercase_statics, Allow,
"static constants should have uppercase identifiers")
#[deriving(Default)]
pub struct NonUppercaseStatics;
impl LintPass for NonUppercaseStatics {
fn get_lints(&self) -> LintArray {
lint_array!(non_uppercase_statics)
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
match it.node {
// only check static constants
@ -828,7 +904,7 @@ impl LintPass for NonUppercaseStatics {
// ones (some scripts don't have a concept of
// upper/lowercase)
if s.get().chars().any(|c| c.is_lowercase()) {
cx.span_lint(lint::NonUppercaseStatics, it.span,
cx.span_lint(non_uppercase_statics, it.span,
format!("static constant `{}` should have an uppercase name \
such as `{}`", s.get(),
s.get().chars().map(|c| c.to_uppercase())
@ -838,6 +914,18 @@ impl LintPass for NonUppercaseStatics {
_ => {}
}
}
}
declare_lint!(non_uppercase_pattern_statics, Warn,
"static constants in match patterns should be all caps")
#[deriving(Default)]
pub struct NonUppercasePatternStatics;
impl LintPass for NonUppercasePatternStatics {
fn get_lints(&self) -> LintArray {
lint_array!(non_uppercase_pattern_statics)
}
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
// Lint for constants that look like binding identifiers (#7526)
@ -847,7 +935,7 @@ impl LintPass for NonUppercaseStatics {
let ident = path.segments.last().unwrap().identifier;
let s = token::get_ident(ident);
if s.get().chars().any(|c| c.is_lowercase()) {
cx.span_lint(lint::NonUppercasePatternStatics, path.span,
cx.span_lint(non_uppercase_pattern_statics, path.span,
format!("static constant in pattern `{}` should have an uppercase \
name such as `{}`", s.get(),
s.get().chars().map(|c| c.to_uppercase())
@ -859,10 +947,17 @@ impl LintPass for NonUppercaseStatics {
}
}
declare_lint!(uppercase_variables, Warn,
"variable and structure field names should start with a lowercase character")
#[deriving(Default)]
pub struct UppercaseVariables;
impl LintPass for UppercaseVariables {
fn get_lints(&self) -> LintArray {
lint_array!(uppercase_variables)
}
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
match &p.node {
&ast::PatIdent(_, ref path, _) => {
@ -873,9 +968,7 @@ impl LintPass for UppercaseVariables {
let ident = path.segments.last().unwrap().identifier;
let s = token::get_ident(ident);
if s.get().len() > 0 && s.get().char_at(0).is_uppercase() {
cx.span_lint(lint::
UppercaseVariables,
path.span,
cx.span_lint(uppercase_variables, path.span,
"variable names should start with a lowercase character");
}
}
@ -893,8 +986,7 @@ impl LintPass for UppercaseVariables {
ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
let s = token::get_ident(ident);
if s.get().char_at(0).is_uppercase() {
cx.span_lint(lint::UppercaseVariables,
sf.span,
cx.span_lint(uppercase_variables, sf.span,
"structure field names should start with a lowercase character");
}
}
@ -904,6 +996,9 @@ impl LintPass for UppercaseVariables {
}
}
declare_lint!(unnecessary_parens, Warn,
"`if`, `match`, `while` and `return` do not need parentheses")
#[deriving(Default)]
pub struct UnnecessaryParens;
@ -911,9 +1006,8 @@ impl UnnecessaryParens {
fn check_unnecessary_parens_core(&self, cx: &Context, value: &ast::Expr, msg: &str) {
match value.node {
ast::ExprParen(_) => {
cx.span_lint(lint::UnnecessaryParens, value.span,
format!("unnecessary parentheses around {}",
msg).as_slice())
cx.span_lint(unnecessary_parens, value.span,
format!("unnecessary parentheses around {}", msg).as_slice())
}
_ => {}
}
@ -921,6 +1015,10 @@ impl UnnecessaryParens {
}
impl LintPass for UnnecessaryParens {
fn get_lints(&self) -> LintArray {
lint_array!(unnecessary_parens)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
let (value, msg) = match e.node {
ast::ExprIf(cond, _, _) => (cond, "`if` condition"),
@ -949,18 +1047,24 @@ impl LintPass for UnnecessaryParens {
}
}
declare_lint!(unused_unsafe, Warn,
"unnecessary use of an `unsafe` block")
#[deriving(Default)]
pub struct UnusedUnsafe;
impl LintPass for UnusedUnsafe {
fn get_lints(&self) -> LintArray {
lint_array!(unused_unsafe)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
// Don't warn about generated blocks, that'll just pollute the output.
ast::ExprBlock(ref blk) => {
if blk.rules == ast::UnsafeBlock(ast::UserProvided) &&
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
cx.span_lint(lint::UnusedUnsafe, blk.span,
"unnecessary `unsafe` block");
cx.span_lint(unused_unsafe, blk.span, "unnecessary `unsafe` block");
}
}
_ => ()
@ -968,21 +1072,31 @@ impl LintPass for UnusedUnsafe {
}
}
declare_lint!(unsafe_block, Allow,
"usage of an `unsafe` block")
#[deriving(Default)]
pub struct UnsafeBlock;
impl LintPass for UnsafeBlock {
fn get_lints(&self) -> LintArray {
lint_array!(unsafe_block)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
// Don't warn about generated blocks, that'll just pollute the output.
ast::ExprBlock(ref blk) if blk.rules == ast::UnsafeBlock(ast::UserProvided) => {
cx.span_lint(lint::UnsafeBlock, blk.span, "usage of an `unsafe` block");
cx.span_lint(unsafe_block, blk.span, "usage of an `unsafe` block");
}
_ => ()
}
}
}
declare_lint!(unused_mut, Warn,
"detect mut variables which don't need to be mutable")
#[deriving(Default)]
pub struct UnusedMut;
@ -1016,14 +1130,18 @@ impl UnusedMut {
let used_mutables = cx.tcx.used_mut_nodes.borrow();
for (_, v) in mutables.iter() {
if !v.iter().any(|e| used_mutables.contains(e)) {
cx.span_lint(lint::UnusedMut, cx.tcx.map.span(*v.get(0)),
"variable does not need to be mutable");
cx.span_lint(unused_mut, cx.tcx.map.span(*v.get(0)),
"variable does not need to be mutable");
}
}
}
}
impl LintPass for UnusedMut {
fn get_lints(&self) -> LintArray {
lint_array!(unused_mut)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
ast::ExprMatch(_, ref arms) => {
@ -1063,10 +1181,17 @@ enum Allocation {
BoxAllocation
}
declare_lint!(unnecessary_allocation, Warn,
"detects unnecessary allocations that can be eliminated")
#[deriving(Default)]
pub struct UnnecessaryAllocation;
impl LintPass for UnnecessaryAllocation {
fn get_lints(&self) -> LintArray {
lint_array!(unnecessary_allocation)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
// Warn if string and vector literals with sigils, or boxing expressions,
// are immediately borrowed.
@ -1086,27 +1211,24 @@ impl LintPass for UnnecessaryAllocation {
_ => return
};
let report = |msg| {
cx.span_lint(lint::UnnecessaryAllocation, e.span, msg);
};
match cx.tcx.adjustments.borrow().find(&e.id) {
Some(adjustment) => {
match *adjustment {
ty::AutoDerefRef(ty::AutoDerefRef { autoref, .. }) => {
match (allocation, autoref) {
(VectorAllocation, Some(ty::AutoBorrowVec(..))) => {
report("unnecessary allocation, the sigil can be \
removed");
cx.span_lint(unnecessary_allocation, e.span,
"unnecessary allocation, the sigil can be removed");
}
(BoxAllocation,
Some(ty::AutoPtr(_, ast::MutImmutable))) => {
report("unnecessary allocation, use & instead");
cx.span_lint(unnecessary_allocation, e.span,
"unnecessary allocation, use & instead");
}
(BoxAllocation,
Some(ty::AutoPtr(_, ast::MutMutable))) => {
report("unnecessary allocation, use &mut \
instead");
cx.span_lint(unnecessary_allocation, e.span,
"unnecessary allocation, use &mut instead");
}
_ => ()
}
@ -1119,6 +1241,9 @@ impl LintPass for UnnecessaryAllocation {
}
}
declare_lint!(missing_doc, Allow,
"detects missing documentation for public members")
pub struct MissingDoc {
/// Set of nodes exported from this module.
exported_items: Option<ExportedItems>,
@ -1175,15 +1300,17 @@ impl MissingDoc {
}
});
if !has_doc {
cx.span_lint(lint::MissingDoc,
sp,
format!("missing documentation for {}",
desc).as_slice());
cx.span_lint(missing_doc, sp,
format!("missing documentation for {}", desc).as_slice());
}
}
}
impl LintPass for MissingDoc {
fn get_lints(&self) -> LintArray {
lint_array!(missing_doc)
}
fn enter_lint_attrs(&mut self, _: &Context, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
@ -1268,12 +1395,25 @@ impl LintPass for MissingDoc {
}
}
declare_lint!(deprecated, Warn,
"detects use of #[deprecated] items")
declare_lint!(experimental, Warn,
"detects use of #[experimental] items")
declare_lint!(unstable, Allow,
"detects use of #[unstable] items (incl. items with no stability attribute)")
/// Checks for use of items with #[deprecated], #[experimental] and
/// #[unstable] (or none of them) attributes.
#[deriving(Default)]
pub struct Stability;
impl LintPass for Stability {
fn get_lints(&self) -> LintArray {
lint_array!(deprecated, experimental, unstable)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
let id = match e.node {
ast::ExprPath(..) | ast::ExprStruct(..) => {
@ -1342,13 +1482,13 @@ impl LintPass for Stability {
let (lint, label) = match stability {
// no stability attributes == Unstable
None => (lint::Unstable, "unmarked"),
None => (unstable, "unmarked"),
Some(attr::Stability { level: attr::Unstable, .. }) =>
(lint::Unstable, "unstable"),
(unstable, "unstable"),
Some(attr::Stability { level: attr::Experimental, .. }) =>
(lint::Experimental, "experimental"),
(experimental, "experimental"),
Some(attr::Stability { level: attr::Deprecated, .. }) =>
(lint::Deprecated, "deprecated"),
(deprecated, "deprecated"),
_ => return
};
@ -1362,3 +1502,80 @@ impl LintPass for Stability {
cx.span_lint(lint, e.span, msg.as_slice());
}
}
/// Doesn't actually warn; just gathers information for use by
/// checks in trans.
#[deriving(Default)]
pub struct GatherNodeLevels;
impl LintPass for GatherNodeLevels {
fn get_lints(&self) -> LintArray {
lint_array!()
}
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
match it.node {
ast::ItemEnum(..) => {
let lint_id = lint::LintId::of(variant_size_difference);
match cx.get_level_source(lint_id) {
lvlsrc @ (lvl, _) if lvl != lint::Allow => {
cx.insert_node_level(it.id, lint_id, lvlsrc);
},
_ => { }
}
},
_ => { }
}
}
}
declare_lint!(pub unused_imports, Warn,
"imports that are never used")
declare_lint!(pub unnecessary_qualification, Allow,
"detects unnecessarily qualified names")
declare_lint!(pub unrecognized_lint, Warn,
"unrecognized lint attribute")
declare_lint!(pub unused_variable, Warn,
"detect variables which are not used in any way")
declare_lint!(pub dead_assignment, Warn,
"detect assignments that will never be read")
declare_lint!(pub dead_code, Warn,
"detect piece of code that will never be used")
declare_lint!(pub visible_private_types, Warn,
"detect use of private types in exported type signatures")
declare_lint!(pub unreachable_code, Warn,
"detects unreachable code")
declare_lint!(pub warnings, Warn,
"mass-change the level for lints which produce warnings")
declare_lint!(pub unknown_features, Deny,
"unknown features found in crate-level #[feature] directives")
declare_lint!(pub unknown_crate_type, Deny,
"unknown crate type found in #[crate_type] directive")
declare_lint!(pub variant_size_difference, Allow,
"detects enums with widely varying variant sizes")
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[deriving(Default)]
pub struct HardwiredLints;
impl LintPass for HardwiredLints {
fn get_lints(&self) -> LintArray {
lint_array!(
unused_imports, unnecessary_qualification, unrecognized_lint,
unused_variable, dead_assignment, dead_code, visible_private_types,
unreachable_code, warnings, unknown_features, unknown_crate_type,
variant_size_difference)
}
}

View File

@ -41,13 +41,13 @@
//! this file, use `span_lint` instead of `add_lint`.
#![allow(non_camel_case_types)]
#![macro_escape]
use driver::session;
use middle::dead::DEAD_CODE_LINT_STR;
use middle::privacy::ExportedItems;
use middle::ty;
use middle::typeck::astconv::AstConv;
use middle::typeck::infer;
use driver::session::Session;
use std::collections::HashMap;
use std::rc::Rc;
@ -55,23 +55,83 @@ use std::gc::Gc;
use std::to_str::ToStr;
use std::cell::RefCell;
use std::default::Default;
use std::collections::SmallIntMap;
use std::hash::Hash;
use std::tuple::Tuple2;
use std::hash;
use syntax::ast_util::IdVisitingOperation;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::visit::{Visitor, FnKind};
use syntax::{ast, ast_util, visit};
mod builtin;
#[macro_export]
macro_rules! lint_initializer (
($name:ident, $level:ident, $desc:expr) => (
::rustc::lint::Lint {
name: stringify!($name),
default_level: ::rustc::lint::$level,
desc: $desc,
}
)
)
/// Trait for types providing lint checks. Each method checks a single syntax
/// node, and should not invoke methods recursively (unlike `Visitor`). Each
/// method has a default do-nothing implementation. The trait also contains a
/// few lint-specific methods with no equivalent in `Visitor`.
#[macro_export]
macro_rules! declare_lint (
// 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);
);
)
#[macro_export]
macro_rules! lint_array ( ($( $lint:expr ),*) => (
{
static array: LintArray = &[ $( $lint ),* ];
array
}
))
pub mod builtin;
/// Specification of a single lint.
pub struct Lint {
/// An identifier for the lint, written with underscores,
/// e.g. "unused_imports". This identifies the lint in
/// attributes and in command-line arguments. On the
/// command line, underscores become dashes.
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,
}
type LintArray = &'static [&'static Lint];
/// 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.
//
// FIXME: eliminate the duplication with `Visitor`
// FIXME: eliminate the duplication with `Visitor`. But this also
// contains a few lint-specific methods with no equivalent in `Visitor`.
trait LintPass {
/// 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;
fn check_crate(&mut self, _: &Context, _: &ExportedItems, _: &ast::Crate) { }
fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
@ -116,63 +176,37 @@ trait LintPass {
type LintPassObject = Box<LintPass + 'static>;
#[deriving(Clone, Show, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum LintId {
CTypes,
UnusedImports,
UnnecessaryQualification,
WhileTrue,
PathStatement,
UnrecognizedLint,
NonCamelCaseTypes,
NonUppercaseStatics,
NonUppercasePatternStatics,
NonSnakeCaseFunctions,
UppercaseVariables,
UnnecessaryParens,
TypeLimits,
TypeOverflow,
UnusedUnsafe,
UnsafeBlock,
UnusedAttribute,
UnknownFeatures,
UnknownCrateType,
UnsignedNegate,
VariantSizeDifference,
ManagedHeapMemory,
OwnedHeapMemory,
HeapMemory,
UnusedVariable,
DeadAssignment,
UnusedMut,
UnnecessaryAllocation,
DeadCode,
VisiblePrivateTypes,
UnnecessaryTypecast,
MissingDoc,
UnreachableCode,
Deprecated,
Experimental,
Unstable,
UnusedMustUse,
UnusedResult,
Warnings,
RawPointerDeriving,
/// Identifies a lint known to the compiler.
#[deriving(Clone)]
pub struct LintId {
// Identity is based on pointer equality of this field.
lint: &'static Lint,
}
pub fn level_to_str(lv: Level) -> &'static str {
match lv {
Allow => "allow",
Warn => "warn",
Deny => "deny",
Forbid => "forbid"
impl PartialEq for LintId {
fn eq(&self, other: &LintId) -> bool {
(self.lint as *Lint) == (other.lint as *Lint)
}
}
impl Eq for LintId { }
impl<S: hash::Writer> Hash<S> for LintId {
fn hash(&self, state: &mut S) {
let ptr = self.lint as *Lint;
ptr.hash(state);
}
}
impl LintId {
pub fn of(lint: &'static Lint) -> LintId {
LintId {
lint: lint,
}
}
pub fn as_str(&self) -> &'static str {
self.lint.name
}
}
@ -181,14 +215,26 @@ pub enum Level {
Allow, Warn, Deny, Forbid
}
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct LintSpec {
pub default: Level,
pub lint: LintId,
pub desc: &'static str,
}
impl Level {
pub fn as_str(self) -> &'static str {
match self {
Allow => "allow",
Warn => "warn",
Deny => "deny",
Forbid => "forbid",
}
}
pub type LintDict = HashMap<&'static str, LintSpec>;
pub fn from_str(x: &str) -> Option<Level> {
match x {
"allow" => Some(Allow),
"warn" => Some(Warn),
"deny" => Some(Deny),
"forbid" => Some(Forbid),
_ => None,
}
}
}
// this is public for the lints that run in trans
#[deriving(PartialEq)]
@ -198,331 +244,49 @@ pub enum LintSource {
CommandLine
}
static lint_table: &'static [(&'static str, LintSpec)] = &[
("ctypes",
LintSpec {
lint: CTypes,
desc: "proper use of libc types in foreign modules",
default: Warn
}),
("unused_imports",
LintSpec {
lint: UnusedImports,
desc: "imports that are never used",
default: Warn
}),
("unnecessary_qualification",
LintSpec {
lint: UnnecessaryQualification,
desc: "detects unnecessarily qualified names",
default: Allow
}),
("while_true",
LintSpec {
lint: WhileTrue,
desc: "suggest using `loop { }` instead of `while true { }`",
default: Warn
}),
("path_statement",
LintSpec {
lint: PathStatement,
desc: "path statements with no effect",
default: Warn
}),
("unrecognized_lint",
LintSpec {
lint: UnrecognizedLint,
desc: "unrecognized lint attribute",
default: Warn
}),
("non_camel_case_types",
LintSpec {
lint: NonCamelCaseTypes,
desc: "types, variants and traits should have camel case names",
default: Warn
}),
("non_uppercase_statics",
LintSpec {
lint: NonUppercaseStatics,
desc: "static constants should have uppercase identifiers",
default: Allow
}),
("non_uppercase_pattern_statics",
LintSpec {
lint: NonUppercasePatternStatics,
desc: "static constants in match patterns should be all caps",
default: Warn
}),
("non_snake_case_functions",
LintSpec {
lint: NonSnakeCaseFunctions,
desc: "methods and functions should have snake case names",
default: Warn
}),
("uppercase_variables",
LintSpec {
lint: UppercaseVariables,
desc: "variable and structure field names should start with a lowercase character",
default: Warn
}),
("unnecessary_parens",
LintSpec {
lint: UnnecessaryParens,
desc: "`if`, `match`, `while` and `return` do not need parentheses",
default: Warn
}),
("managed_heap_memory",
LintSpec {
lint: ManagedHeapMemory,
desc: "use of managed (@ type) heap memory",
default: Allow
}),
("owned_heap_memory",
LintSpec {
lint: OwnedHeapMemory,
desc: "use of owned (Box type) heap memory",
default: Allow
}),
("heap_memory",
LintSpec {
lint: HeapMemory,
desc: "use of any (Box type or @ type) heap memory",
default: Allow
}),
("type_limits",
LintSpec {
lint: TypeLimits,
desc: "comparisons made useless by limits of the types involved",
default: Warn
}),
("type_overflow",
LintSpec {
lint: TypeOverflow,
desc: "literal out of range for its type",
default: Warn
}),
("unused_unsafe",
LintSpec {
lint: UnusedUnsafe,
desc: "unnecessary use of an `unsafe` block",
default: Warn
}),
("unsafe_block",
LintSpec {
lint: UnsafeBlock,
desc: "usage of an `unsafe` block",
default: Allow
}),
("unused_attribute",
LintSpec {
lint: UnusedAttribute,
desc: "detects attributes that were not used by the compiler",
default: Warn
}),
("unused_variable",
LintSpec {
lint: UnusedVariable,
desc: "detect variables which are not used in any way",
default: Warn
}),
("dead_assignment",
LintSpec {
lint: DeadAssignment,
desc: "detect assignments that will never be read",
default: Warn
}),
("unnecessary_typecast",
LintSpec {
lint: UnnecessaryTypecast,
desc: "detects unnecessary type casts, that can be removed",
default: Allow,
}),
("unused_mut",
LintSpec {
lint: UnusedMut,
desc: "detect mut variables which don't need to be mutable",
default: Warn
}),
("unnecessary_allocation",
LintSpec {
lint: UnnecessaryAllocation,
desc: "detects unnecessary allocations that can be eliminated",
default: Warn
}),
(DEAD_CODE_LINT_STR,
LintSpec {
lint: DeadCode,
desc: "detect piece of code that will never be used",
default: Warn
}),
("visible_private_types",
LintSpec {
lint: VisiblePrivateTypes,
desc: "detect use of private types in exported type signatures",
default: Warn
}),
("missing_doc",
LintSpec {
lint: MissingDoc,
desc: "detects missing documentation for public members",
default: Allow
}),
("unreachable_code",
LintSpec {
lint: UnreachableCode,
desc: "detects unreachable code",
default: Warn
}),
("deprecated",
LintSpec {
lint: Deprecated,
desc: "detects use of #[deprecated] items",
default: Warn
}),
("experimental",
LintSpec {
lint: Experimental,
desc: "detects use of #[experimental] items",
// FIXME #6875: Change to Warn after std library stabilization is complete
default: Allow
}),
("unstable",
LintSpec {
lint: Unstable,
desc: "detects use of #[unstable] items (incl. items with no stability attribute)",
default: Allow
}),
("warnings",
LintSpec {
lint: Warnings,
desc: "mass-change the level for lints which produce warnings",
default: Warn
}),
("unknown_features",
LintSpec {
lint: UnknownFeatures,
desc: "unknown features found in crate-level #[feature] directives",
default: Deny,
}),
("unknown_crate_type",
LintSpec {
lint: UnknownCrateType,
desc: "unknown crate type found in #[crate_type] directive",
default: Deny,
}),
("unsigned_negate",
LintSpec {
lint: UnsignedNegate,
desc: "using an unary minus operator on unsigned type",
default: Warn
}),
("variant_size_difference",
LintSpec {
lint: VariantSizeDifference,
desc: "detects enums with widely varying variant sizes",
default: Allow,
}),
("unused_must_use",
LintSpec {
lint: UnusedMustUse,
desc: "unused result of a type flagged as #[must_use]",
default: Warn,
}),
("unused_result",
LintSpec {
lint: UnusedResult,
desc: "unused result of an expression in a statement",
default: Allow,
}),
("raw_pointer_deriving",
LintSpec {
lint: RawPointerDeriving,
desc: "uses of #[deriving] with raw pointers are rarely correct",
default: Warn,
}),
];
/*
Pass names should not contain a '-', as the compiler normalizes
'-' to '_' in command-line flags
*/
pub fn get_lint_dict() -> LintDict {
lint_table.iter().map(|&(k, v)| (k, v)).collect()
}
pub type LevelSource = (Level, LintSource);
struct Context<'a> {
/// All known lint modes (string versions)
dict: LintDict,
/// Current levels of each lint warning
cur: SmallIntMap<(Level, LintSource)>,
/// Context we're checking in (used to access fields like sess)
/// Trait objects for each lint pass.
lint_objects: Vec<RefCell<LintPassObject>>,
/// Lints indexed by name.
lints_by_name: HashMap<&'static str, LintId>,
/// Current levels of each lint, and where they were set.
levels: HashMap<LintId, LevelSource>,
/// Context we're checking in (used to access fields like sess).
tcx: &'a ty::ctxt,
/// When recursing into an attributed node of the ast which modifies lint
/// levels, this stack keeps track of the previous lint levels of whatever
/// was modified.
level_stack: Vec<(LintId, Level, LintSource)>,
level_stack: Vec<(LintId, LevelSource)>,
/// Level of lints for certain NodeIds, stored here because the body of
/// the lint needs to run in trans.
node_levels: RefCell<HashMap<(ast::NodeId, LintId), (Level, LintSource)>>,
/// Trait objects for each lint.
lints: Vec<RefCell<LintPassObject>>,
node_levels: RefCell<HashMap<(ast::NodeId, LintId), LevelSource>>,
}
/// Convenience macro for calling a `LintPass` method on every lint in the context.
/// Convenience macro for calling a `LintPass` method on every pass in the context.
macro_rules! run_lints ( ($cx:expr, $f:ident, $($args:expr),*) => (
for tl in $cx.lints.iter() {
tl.borrow_mut().$f($cx, $($args),*);
for obj in $cx.lint_objects.iter() {
obj.borrow_mut().$f($cx, $($args),*);
}
))
pub fn emit_lint(level: Level, src: LintSource, msg: &str, span: Span,
lint_str: &str, tcx: &ty::ctxt) {
/// Emit a lint as a `span_warn` or `span_err` (or not at all)
/// according to `level`. This lives outside of `Context` so
/// it can be used by checks in trans that run after the main
/// lint phase is finished.
pub fn emit_lint(sess: &Session, lint: &'static Lint,
lvlsrc: LevelSource, span: Span, msg: &str) {
let (level, source) = lvlsrc;
if level == Allow { return }
let mut note = None;
let msg = match src {
let msg = match source {
Default => {
format!("{}, #[{}({})] on by default", msg,
level_to_str(level), lint_str)
@ -532,75 +296,50 @@ pub fn emit_lint(level: Level, src: LintSource, msg: &str, span: Span,
match level {
Warn => 'W', Deny => 'D', Forbid => 'F',
Allow => fail!()
}, lint_str.replace("_", "-"))
}, lint.name.replace("_", "-"))
},
Node(src) => {
note = Some(src);
msg.to_str()
msg.to_string()
}
};
match level {
Warn => { tcx.sess.span_warn(span, msg.as_slice()); }
Deny | Forbid => { tcx.sess.span_err(span, msg.as_slice()); }
Warn => { sess.span_warn(span, msg.as_slice()); }
Deny | Forbid => { sess.span_err(span, msg.as_slice()); }
Allow => fail!(),
}
for &span in note.iter() {
tcx.sess.span_note(span, "lint level defined here");
for span in note.move_iter() {
sess.span_note(span, "lint level defined here");
}
}
pub fn lint_to_str(lint: LintId) -> &'static str {
for &(name, lspec) in lint_table.iter() {
if lspec.lint == lint {
return name;
}
}
fail!("unrecognized lint: {}", lint);
}
impl<'a> Context<'a> {
fn get_level(&self, lint: LintId) -> Level {
match self.cur.find(&(lint as uint)) {
Some(&(lvl, _)) => lvl,
None => Allow
fn get_level_source(&self, lint: LintId) -> LevelSource {
match self.levels.find(&lint) {
Some(&s) => s,
None => (Allow, Default),
}
}
fn get_source(&self, lint: LintId) -> LintSource {
match self.cur.find(&(lint as uint)) {
Some(&(_, src)) => src,
None => Default
}
}
fn set_level(&mut self, lint: LintId, level: Level, src: LintSource) {
if level == Allow {
self.cur.remove(&(lint as uint));
fn set_level(&mut self, lint: LintId, lvlsrc: LevelSource) {
if lvlsrc.val0() == Allow {
self.levels.remove(&lint);
} else {
self.cur.insert(lint as uint, (level, src));
self.levels.insert(lint, lvlsrc);
}
}
fn lint_to_str(&self, lint: LintId) -> &'static str {
for (k, v) in self.dict.iter() {
if v.lint == lint {
return *k;
}
}
fail!("unregistered lint {}", lint);
}
fn span_lint(&self, lint: LintId, span: Span, msg: &str) {
let (level, src) = match self.cur.find(&(lint as uint)) {
None => { return }
Some(&(Warn, src)) => (self.get_level(Warnings), src),
fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
let (level, src) = match self.levels.find(&LintId::of(lint)) {
None => return,
Some(&(Warn, src))
=> (self.get_level_source(LintId::of(builtin::warnings)).val0(), src),
Some(&pair) => pair,
};
emit_lint(level, src, msg, span, self.lint_to_str(lint), self.tcx);
emit_lint(&self.tcx.sess, lint, (level, src), span, msg);
}
/**
@ -615,35 +354,22 @@ impl<'a> Context<'a> {
// current dictionary of lint information. Along the way, keep a history
// of what we changed so we can roll everything back after invoking the
// specified closure
let lint_attrs = self.gather_lint_attrs(attrs);
let mut pushed = 0u;
each_lint(&self.tcx.sess, attrs, |meta, level, lintname| {
match self.dict.find_equiv(&lintname) {
None => {
self.span_lint(
UnrecognizedLint,
meta.span,
format!("unknown `{}` attribute: `{}`",
level_to_str(level), lintname).as_slice());
}
Some(lint) => {
let lint = lint.lint;
let now = self.get_level(lint);
if now == Forbid && level != Forbid {
self.tcx.sess.span_err(meta.span,
format!("{}({}) overruled by outer forbid({})",
level_to_str(level),
lintname,
lintname).as_slice());
} else if now != level {
let src = self.get_source(lint);
self.level_stack.push((lint, now, src));
pushed += 1;
self.set_level(lint, level, Node(meta.span));
}
}
for (lint_id, level, span) in lint_attrs.move_iter() {
let now = self.get_level_source(lint_id).val0();
if now == Forbid && level != Forbid {
let lint_name = lint_id.as_str();
self.tcx.sess.span_err(span,
format!("{}({}) overruled by outer forbid({})",
level.as_str(), lint_name, lint_name).as_slice());
} else if now != level {
let src = self.get_level_source(lint_id).val1();
self.level_stack.push((lint_id, (now, src)));
pushed += 1;
self.set_level(lint_id, (level, Node(span)));
}
true
});
}
run_lints!(self, enter_lint_attrs, attrs);
f(self);
@ -651,8 +377,8 @@ impl<'a> Context<'a> {
// rollback
for _ in range(0, pushed) {
let (lint, lvl, src) = self.level_stack.pop().unwrap();
self.set_level(lint, lvl, src);
let (lint, lvlsrc) = self.level_stack.pop().unwrap();
self.set_level(lint, lvlsrc);
}
}
@ -665,65 +391,49 @@ impl<'a> Context<'a> {
f(&mut v);
}
fn insert_node_level(&self, id: ast::NodeId, lint: LintId, lvl: Level, src: LintSource) {
self.node_levels.borrow_mut().insert((id, lint), (lvl, src));
fn insert_node_level(&self, id: ast::NodeId, lint: LintId, lvlsrc: LevelSource) {
self.node_levels.borrow_mut().insert((id, lint), lvlsrc);
}
}
/// Check that every lint from the list of attributes satisfies `f`.
/// Return true if that's the case. Otherwise return false.
pub fn each_lint(sess: &session::Session,
attrs: &[ast::Attribute],
f: |Gc<ast::MetaItem>, Level, InternedString| -> bool)
-> bool {
let xs = [Allow, Warn, Deny, Forbid];
for &level in xs.iter() {
let level_name = level_to_str(level);
for attr in attrs.iter().filter(|m| m.check_name(level_name)) {
fn gather_lint_attrs(&mut self, attrs: &[ast::Attribute]) -> Vec<(LintId, Level, Span)> {
// Doing this as an iterator is messy due to multiple borrowing.
// Allocating and copying these should be quick.
let mut out = vec!();
for attr in attrs.iter() {
let level = match Level::from_str(attr.name().get()) {
None => continue,
Some(lvl) => lvl,
};
attr::mark_used(attr);
let meta = attr.node.value;
let metas = match meta.node {
ast::MetaList(_, ref metas) => metas,
_ => {
sess.span_err(meta.span, "malformed lint attribute");
self.tcx.sess.span_err(meta.span, "malformed lint attribute");
continue;
}
};
for meta in metas.iter() {
match meta.node {
ast::MetaWord(ref lintname) => {
if !f(*meta, level, (*lintname).clone()) {
return false;
ast::MetaWord(ref lint_name) => {
match self.lints_by_name.find_equiv(lint_name) {
Some(lint_id) => out.push((*lint_id, level, meta.span)),
None => self.span_lint(builtin::unrecognized_lint,
meta.span,
format!("unknown `{}` attribute: `{}`",
level.as_str(), lint_name).as_slice()),
}
}
_ => {
sess.span_err(meta.span, "malformed lint attribute");
}
_ => self.tcx.sess.span_err(meta.span, "malformed lint attribute"),
}
}
}
out
}
true
}
/// Check from a list of attributes if it contains the appropriate
/// `#[level(lintname)]` attribute (e.g. `#[allow(dead_code)]).
pub fn contains_lint(attrs: &[ast::Attribute],
level: Level,
lintname: &'static str)
-> bool {
let level_name = level_to_str(level);
for attr in attrs.iter().filter(|m| m.name().equiv(&level_name)) {
if attr.meta_item_list().is_none() {
continue
}
let list = attr.meta_item_list().unwrap();
for meta_item in list.iter() {
if meta_item.name().equiv(&lintname) {
return true;
}
}
}
false
}
impl<'a> AstConv for Context<'a>{
@ -912,59 +622,90 @@ impl<'a> Visitor<()> for Context<'a> {
}
}
// Output any lints that were previously added to the session.
impl<'a> IdVisitingOperation for Context<'a> {
fn visit_id(&self, id: ast::NodeId) {
match self.tcx.sess.lints.borrow_mut().pop(&id) {
None => {}
Some(l) => {
for (lint, span, msg) in l.move_iter() {
self.span_lint(lint, span, msg.as_slice())
Some(lints) => {
for (lint_id, span, msg) in lints.move_iter() {
self.span_lint(lint_id.lint, span, msg.as_slice())
}
}
}
}
}
pub fn check_crate(tcx: &ty::ctxt,
exported_items: &ExportedItems,
krate: &ast::Crate) {
fn builtin_lints() -> Vec<Box<LintPass>> {
macro_rules! builtin_lints (( $($name:ident),*, ) => (
vec!($(
{
let obj: builtin::$name = Default::default();
RefCell::new(box obj as LintPassObject)
box obj as LintPassObject
}
),*)
))
let builtin_lints = builtin_lints!(
GatherNodeLevels, WhileTrue, UnusedCasts, TypeLimits, CTypes,
HeapMemory, RawPointerDeriving, UnusedAttribute,
PathStatement, UnusedMustUse, DeprecatedOwnedVector,
NonCamelCaseTypes, NonSnakeCaseFunctions, NonUppercaseStatics,
UppercaseVariables, UnnecessaryParens, UnusedUnsafe, UnsafeBlock,
UnusedMut, UnnecessaryAllocation, MissingDoc, Stability,
);
builtin_lints!(
WhileTrue, UnusedCasts, TypeLimits, CTypes, HeapMemory,
RawPointerDeriving, UnusedAttribute, PathStatement,
UnusedResult, DeprecatedOwnedVector, NonCamelCaseTypes,
NonSnakeCaseFunctions, NonUppercaseStatics,
NonUppercasePatternStatics, UppercaseVariables,
UnnecessaryParens, UnusedUnsafe, UnsafeBlock, UnusedMut,
UnnecessaryAllocation, MissingDoc, Stability,
GatherNodeLevels, HardwiredLints,
)
}
/// Get specs for all builtin lints. Used for `-W help`.
pub fn builtin_lint_specs() -> Vec<&'static Lint> {
builtin_lints().move_iter()
.flat_map(|x| x.get_lints().iter().map(|&y| y))
.collect()
}
pub fn check_crate(tcx: &ty::ctxt,
exported_items: &ExportedItems,
krate: &ast::Crate) {
let lints = builtin_lints().move_iter().map(|x| RefCell::new(x)).collect();
let mut cx = Context {
dict: get_lint_dict(),
cur: SmallIntMap::new(),
lint_objects: lints,
lints_by_name: HashMap::new(),
levels: HashMap::new(),
tcx: tcx,
level_stack: Vec::new(),
node_levels: RefCell::new(HashMap::new()),
lints: builtin_lints,
};
// Install default lint levels, followed by the command line levels, and
// then actually visit the whole crate.
for (_, spec) in cx.dict.iter() {
if spec.default != Allow {
cx.cur.insert(spec.lint as uint, (spec.default, Default));
// Index the lints by name, and set the default levels.
for obj in cx.lint_objects.iter() {
for &lint in obj.borrow_mut().get_lints().iter() {
let id = LintId::of(lint);
if !cx.lints_by_name.insert(lint.name, id) {
cx.tcx.sess.err(format!("duplicate specification of lint {}",
lint.name).as_slice());
}
if lint.default_level != Allow {
cx.levels.insert(id, (lint.default_level, Default));
}
}
}
for &(lint, level) in tcx.sess.opts.lint_opts.iter() {
cx.set_level(lint, level, CommandLine);
// Set command line lint levels.
for &(ref lint_name, level) in tcx.sess.opts.lint_opts.iter() {
match cx.lints_by_name.find_equiv(&lint_name.as_slice()) {
Some(&lint_id) => cx.set_level(lint_id, (level, CommandLine)),
None => cx.tcx.sess.err(format!("unknown {} flag: {}",
level.as_str(), lint_name).as_slice()),
}
}
tcx.sess.abort_if_errors();
// Visit the whole crate.
cx.with_lint_attrs(krate.attrs.as_slice(), |cx| {
cx.visit_id(ast::CRATE_NODE_ID);
cx.visit_ids(|v| {
@ -983,8 +724,10 @@ pub fn check_crate(tcx: &ty::ctxt,
// in the iteration code.
for (id, v) in tcx.sess.lints.borrow().iter() {
for &(lint, span, ref msg) in v.iter() {
tcx.sess.span_bug(span, format!("unprocessed lint {} at {}: {}",
lint, tcx.map.node_to_str(*id), *msg).as_slice())
tcx.sess.span_bug(span,
format!("unprocessed lint {} at {}: {}",
lint.as_str(), tcx.map.node_to_str(*id), *msg)
.as_slice())
}
}

View File

@ -13,7 +13,7 @@
// from live codes are live, and everything else is dead.
use middle::def;
use lint::{Allow, contains_lint, DeadCode};
use lint;
use middle::privacy;
use middle::ty;
use middle::typeck;
@ -23,14 +23,13 @@ use std::collections::HashSet;
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{local_def, is_local};
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap;
use syntax::parse::token;
use syntax::visit::Visitor;
use syntax::visit;
pub static DEAD_CODE_LINT_STR: &'static str = "dead_code";
// Any local node that may call something in its body block should be
// explored. For example, if it's a live NodeItem that is a
// function, then we should explore its block to check for codes that
@ -266,8 +265,24 @@ impl<'a> Visitor<MarkSymbolVisitorContext> for MarkSymbolVisitor<'a> {
}
fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
contains_lint(attrs, Allow, DEAD_CODE_LINT_STR)
|| attr::contains_name(attrs.as_slice(), "lang")
if attr::contains_name(attrs.as_slice(), "lang") {
return true;
}
// FIXME: use the lint attr parsing already in rustc::lint
for attr in attrs.iter().filter(|a| a.check_name("allow")) {
match attr.node.value.node {
ast::MetaList(_, ref metas) => for meta in metas.iter() {
match meta.node {
ast::MetaWord(ref name) if name.get() == "dead_code"
=> return true,
_ => (),
}
},
_ => (),
}
}
false
}
// This visitor seeds items that
@ -446,7 +461,7 @@ impl<'a> DeadVisitor<'a> {
ident: ast::Ident) {
self.tcx
.sess
.add_lint(DeadCode,
.add_lint(lint::builtin::dead_code,
id,
span,
format!("code is never used: `{}`",

View File

@ -107,7 +107,7 @@ use middle::freevars;
use middle::mem_categorization::Typer;
use middle::pat_util;
use middle::ty;
use lint::{UnusedVariable, DeadAssignment};
use lint;
use util::nodemap::NodeMap;
use std::fmt;
@ -1560,11 +1560,11 @@ impl<'a> Liveness<'a> {
};
if is_assigned {
self.ir.tcx.sess.add_lint(UnusedVariable, id, sp,
self.ir.tcx.sess.add_lint(lint::builtin::unused_variable, id, sp,
format!("variable `{}` is assigned to, but never used",
*name));
} else {
self.ir.tcx.sess.add_lint(UnusedVariable, id, sp,
self.ir.tcx.sess.add_lint(lint::builtin::unused_variable, id, sp,
format!("unused variable: `{}`", *name));
}
}
@ -1582,7 +1582,7 @@ impl<'a> Liveness<'a> {
if self.live_on_exit(ln, var).is_none() {
let r = self.should_warn(var);
for name in r.iter() {
self.ir.tcx.sess.add_lint(DeadAssignment, id, sp,
self.ir.tcx.sess.add_lint(lint::builtin::dead_assignment, id, sp,
format!("value assigned to `{}` is never read", *name));
}
}

View File

@ -1394,7 +1394,7 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
ast::TyPath(ref p, _, path_id) => {
if self.path_is_private_type(path_id) {
self.tcx.sess.add_lint(
lint::VisiblePrivateTypes,
lint::builtin::visible_private_types,
path_id, p.span,
"private type in exported type \
signature".to_string());

View File

@ -15,9 +15,9 @@ use metadata::csearch;
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use middle::def::*;
use middle::lang_items::LanguageItems;
use lint::{UnnecessaryQualification, UnusedImports};
use middle::pat_util::pat_bindings;
use middle::subst::{ParamSpace, FnSpace, TypeSpace};
use lint;
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
use syntax::ast::*;
@ -4632,7 +4632,7 @@ impl<'a> Resolver<'a> {
match (def, unqualified_def) {
(Some((d, _)), Some((ud, _))) if d == ud => {
self.session
.add_lint(UnnecessaryQualification,
.add_lint(lint::builtin::unnecessary_qualification,
id,
path.span,
"unnecessary qualification".to_string());
@ -5487,7 +5487,7 @@ impl<'a> Resolver<'a> {
if !self.used_imports.contains(&(id, TypeNS)) &&
!self.used_imports.contains(&(id, ValueNS)) {
self.session
.add_lint(UnusedImports,
.add_lint(lint::builtin::unused_imports,
id,
p.span,
"unused import".to_string());
@ -5511,7 +5511,7 @@ impl<'a> Resolver<'a> {
if !self.used_imports.contains(&(id, TypeNS)) &&
!self.used_imports.contains(&(id, ValueNS)) {
self.session.add_lint(UnusedImports,
self.session.add_lint(lint::builtin::unused_imports,
id,
span,
"unused import".to_string());

View File

@ -1552,48 +1552,50 @@ fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef,
fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) {
let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
let (lvl, src) = ccx.tcx.node_lint_levels.borrow()
.find(&(id, lint::VariantSizeDifference))
.map_or((lint::Allow, lint::Default), |&(lvl,src)| (lvl, src));
if lvl != lint::Allow {
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
match *avar {
adt::General(_, ref variants) => {
for var in variants.iter() {
let mut size = 0;
for field in var.fields.iter().skip(1) {
// skip the discriminant
size += llsize_of_real(ccx, sizing_type_of(ccx, *field));
let levels = ccx.tcx.node_lint_levels.borrow();
match levels.find(&(id, lint::LintId::of(lint::builtin::variant_size_difference))) {
None | Some(&(lint::Allow, _)) => (),
Some(&lvlsrc) => {
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
match *avar {
adt::General(_, ref variants) => {
for var in variants.iter() {
let mut size = 0;
for field in var.fields.iter().skip(1) {
// skip the discriminant
size += llsize_of_real(ccx, sizing_type_of(ccx, *field));
}
sizes.push(size);
}
sizes.push(size);
}
},
_ => { /* its size is either constant or unimportant */ }
}
},
_ => { /* its size is either constant or unimportant */ }
}
let (largest, slargest, largest_index) = sizes.iter().enumerate().fold((0, 0, 0),
|(l, s, li), (idx, &size)|
if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
}
);
let (largest, slargest, largest_index) = sizes.iter().enumerate().fold((0, 0, 0),
|(l, s, li), (idx, &size)|
if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
}
);
// we only warn if the largest variant is at least thrice as large as
// the second-largest.
if largest > slargest * 3 && slargest > 0 {
lint::emit_lint(lvl, src,
format!("enum variant is more than three times larger \
({} bytes) than the next largest (ignoring padding)",
largest).as_slice(),
sp, lint::lint_to_str(lint::VariantSizeDifference), ccx.tcx());
// we only warn if the largest variant is at least thrice as large as
// the second-largest.
if largest > slargest * 3 && slargest > 0 {
// Use lint::emit_lint rather than sess.add_lint because the lint-printing
// pass for the latter already ran.
lint::emit_lint(&ccx.tcx().sess, lint::builtin::variant_size_difference,
lvlsrc, sp,
format!("enum variant is more than three times larger \
({} bytes) than the next largest (ignoring padding)",
largest).as_slice());
ccx.sess().span_note(enum_def.variants.get(largest_index).span,
"this variant is the largest");
ccx.sess().span_note(enum_def.variants.get(largest_index).span,
"this variant is the largest");
}
}
}
}

View File

@ -368,7 +368,7 @@ pub struct ctxt {
pub dependency_formats: RefCell<dependency_format::Dependencies>,
pub node_lint_levels: RefCell<HashMap<(ast::NodeId, lint::LintId),
(lint::Level, lint::LintSource)>>,
lint::LevelSource>>,
/// The types that must be asserted to be the same size for `transmute`
/// to be valid. We gather up these restrictions in the intrinsicck pass

View File

@ -79,7 +79,6 @@ type parameter).
use middle::const_eval;
use middle::def;
use lint::UnreachableCode;
use middle::pat_util::pat_id_map;
use middle::pat_util;
use middle::subst;
@ -111,6 +110,7 @@ use middle::typeck::{require_same_types, vtable_map};
use middle::typeck::{MethodCall, MethodMap};
use middle::typeck::{TypeAndSubsts};
use middle::lang_items::TypeIdLangItem;
use lint;
use util::common::{block_query, indenter, loop_query};
use util::ppaux;
use util::ppaux::{UserString, Repr};
@ -3416,7 +3416,7 @@ pub fn check_block_with_expected(fcx: &FnCtxt,
fcx.ccx
.tcx
.sess
.add_lint(UnreachableCode,
.add_lint(lint::builtin::unreachable_code,
s_id,
s.span,
"unreachable statement".to_string());
@ -3443,7 +3443,7 @@ pub fn check_block_with_expected(fcx: &FnCtxt,
fcx.ccx
.tcx
.sess
.add_lint(UnreachableCode,
.add_lint(lint::builtin::unreachable_code,
e.id,
e.span,
"unreachable expression".to_string());

View File

@ -75,11 +75,13 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
let input = FileInput(cpath.clone());
let warning_lint = lint::builtin::warnings.name.to_string();
let sessopts = driver::config::Options {
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: RefCell::new(libs),
crate_types: vec!(driver::config::CrateTypeRlib),
lint_opts: vec!((lint::Warnings, lint::Allow)),
lint_opts: vec!((warning_lint, lint::Allow)),
..rustc::driver::config::basic_options().clone()
};