Replace enum LintId with an extensible alternative
This commit is contained in:
parent
69b6bc5eee
commit
442fbc473e
@ -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,
|
||||
|
@ -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 \
|
||||
|
@ -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") {
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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: `{}`",
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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()
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user