Replace enum LintId with an extensible alternative
This commit is contained in:
parent
69b6bc5eee
commit
442fbc473e
16 changed files with 742 additions and 764 deletions
|
@ -70,7 +70,8 @@ pub struct Options {
|
||||||
pub gc: bool,
|
pub gc: bool,
|
||||||
pub optimize: OptLevel,
|
pub optimize: OptLevel,
|
||||||
pub debuginfo: DebugInfoLevel,
|
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> ,
|
pub output_types: Vec<back::link::OutputType> ,
|
||||||
// This was mutable for rustpkg, which updates search paths based on the
|
// This was mutable for rustpkg, which updates search paths based on the
|
||||||
// parsed code. It remains mutable in case its replacements wants to use
|
// parsed code. It remains mutable in case its replacements wants to use
|
||||||
|
@ -104,6 +105,7 @@ pub fn basic_options() -> Options {
|
||||||
optimize: No,
|
optimize: No,
|
||||||
debuginfo: NoDebugInfo,
|
debuginfo: NoDebugInfo,
|
||||||
lint_opts: Vec::new(),
|
lint_opts: Vec::new(),
|
||||||
|
describe_lints: false,
|
||||||
output_types: Vec::new(),
|
output_types: Vec::new(),
|
||||||
addl_lib_search_paths: RefCell::new(HashSet::new()),
|
addl_lib_search_paths: RefCell::new(HashSet::new()),
|
||||||
maybe_sysroot: None,
|
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_trans = matches.opt_present("no-trans");
|
||||||
let no_analysis = matches.opt_present("no-analysis");
|
let no_analysis = matches.opt_present("no-analysis");
|
||||||
|
|
||||||
let lint_levels = [lint::Allow, lint::Warn,
|
let mut lint_opts = vec!();
|
||||||
lint::Deny, lint::Forbid];
|
let mut describe_lints = false;
|
||||||
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 level_short = level_name.slice_chars(0, 1);
|
for &level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid].iter() {
|
||||||
let level_short = level_short.to_ascii().to_upper().into_str();
|
for lint_name in matches.opt_strs(level.as_str()).move_iter() {
|
||||||
let flags = matches.opt_strs(level_short.as_slice())
|
if lint_name.as_slice() == "help" {
|
||||||
.move_iter()
|
describe_lints = true;
|
||||||
.collect::<Vec<_>>()
|
} else {
|
||||||
.append(matches.opt_strs(level_name).as_slice());
|
lint_opts.push((lint_name.replace("-", "_").into_string(), level));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,6 +739,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
optimize: opt_level,
|
optimize: opt_level,
|
||||||
debuginfo: debuginfo,
|
debuginfo: debuginfo,
|
||||||
lint_opts: lint_opts,
|
lint_opts: lint_opts,
|
||||||
|
describe_lints: describe_lints,
|
||||||
output_types: output_types,
|
output_types: output_types,
|
||||||
addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
|
addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
|
||||||
maybe_sysroot: sysroot_opt,
|
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(ref n) if n.equiv(&("bin")) => Some(config::CrateTypeExecutable),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
session.add_lint(lint::UnknownCrateType,
|
session.add_lint(lint::builtin::unknown_crate_type,
|
||||||
ast::CRATE_NODE_ID,
|
ast::CRATE_NODE_ID,
|
||||||
a.span,
|
a.span,
|
||||||
"invalid `crate_type` \
|
"invalid `crate_type` \
|
||||||
|
@ -775,7 +775,7 @@ pub fn collect_crate_types(session: &Session,
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
session.add_lint(lint::UnknownCrateType,
|
session.add_lint(lint::builtin::unknown_crate_type,
|
||||||
ast::CRATE_NODE_ID,
|
ast::CRATE_NODE_ID,
|
||||||
a.span,
|
a.span,
|
||||||
"`crate_type` requires a \
|
"`crate_type` requires a \
|
||||||
|
|
|
@ -17,7 +17,6 @@ use lint;
|
||||||
use metadata;
|
use metadata;
|
||||||
|
|
||||||
use std::any::AnyRefExt;
|
use std::any::AnyRefExt;
|
||||||
use std::cmp;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
@ -50,6 +49,12 @@ fn run_compiler(args: &[String]) {
|
||||||
None => return
|
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() {
|
let (input, input_file_path) = match matches.free.len() {
|
||||||
0u => early_error("no input filename given"),
|
0u => early_error("no input filename given"),
|
||||||
1u => {
|
1u => {
|
||||||
|
@ -66,7 +71,6 @@ fn run_compiler(args: &[String]) {
|
||||||
_ => early_error("multiple input filenames provided")
|
_ => early_error("multiple input filenames provided")
|
||||||
};
|
};
|
||||||
|
|
||||||
let sopts = config::build_session_options(&matches);
|
|
||||||
let sess = build_session(sopts, input_file_path);
|
let sess = build_session(sopts, input_file_path);
|
||||||
let cfg = config::build_configuration(&sess);
|
let cfg = config::build_configuration(&sess);
|
||||||
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
||||||
|
@ -124,7 +128,7 @@ Additional help:
|
||||||
config::optgroups().as_slice()));
|
config::optgroups().as_slice()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe_warnings() {
|
fn describe_lints() {
|
||||||
println!("
|
println!("
|
||||||
Available lint options:
|
Available lint options:
|
||||||
-W <foo> Warn about <foo>
|
-W <foo> Warn about <foo>
|
||||||
|
@ -133,30 +137,32 @@ Available lint options:
|
||||||
-F <foo> Forbid <foo> (deny, and deny all overrides)
|
-F <foo> Forbid <foo> (deny, and deny all overrides)
|
||||||
");
|
");
|
||||||
|
|
||||||
let lint_dict = lint::get_lint_dict();
|
let mut builtin_specs = lint::builtin_lint_specs();
|
||||||
let mut lint_dict = lint_dict.move_iter()
|
builtin_specs.sort_by(|x, y| {
|
||||||
.map(|(k, v)| (v, k))
|
match x.default_level.cmp(&y.default_level) {
|
||||||
.collect::<Vec<(lint::LintSpec, &'static str)> >();
|
Equal => x.name.cmp(&y.name),
|
||||||
lint_dict.as_mut_slice().sort();
|
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!("\nAvailable lint checks:\n");
|
||||||
println!(" {} {:7.7s} {}",
|
println!(" {} {:7.7s} {}", padded("name"), "default", "meaning");
|
||||||
padded(max_key, "name"), "default", "meaning");
|
println!(" {} {:7.7s} {}", padded("----"), "-------", "-------");
|
||||||
println!(" {} {:7.7s} {}\n",
|
println!("");
|
||||||
padded(max_key, "----"), "-------", "-------");
|
|
||||||
for (spec, name) in lint_dict.move_iter() {
|
for spec in builtin_specs.move_iter() {
|
||||||
let name = name.replace("_", "-");
|
let name = spec.name.replace("_", "-");
|
||||||
println!(" {} {:7.7s} {}",
|
println!(" {} {:7.7s} {}",
|
||||||
padded(max_key, name.as_slice()),
|
padded(name.as_slice()), spec.default_level.as_str(), spec.desc);
|
||||||
lint::level_to_str(spec.default),
|
|
||||||
spec.desc);
|
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
|
@ -214,12 +220,7 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lint_flags = matches.opt_strs("W").move_iter().collect::<Vec<_>>().append(
|
// Don't handle -W help here, because we might first load plugins.
|
||||||
matches.opt_strs("warn").as_slice());
|
|
||||||
if lint_flags.iter().any(|x| x.as_slice() == "help") {
|
|
||||||
describe_warnings();
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = matches.opt_strs("Z");
|
let r = matches.opt_strs("Z");
|
||||||
if r.iter().any(|x| x.as_slice() == "help") {
|
if r.iter().any(|x| x.as_slice() == "help") {
|
||||||
|
|
|
@ -106,16 +106,17 @@ impl Session {
|
||||||
self.diagnostic().handler().unimpl(msg)
|
self.diagnostic().handler().unimpl(msg)
|
||||||
}
|
}
|
||||||
pub fn add_lint(&self,
|
pub fn add_lint(&self,
|
||||||
lint: lint::LintId,
|
lint: &'static lint::Lint,
|
||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
msg: String) {
|
msg: String) {
|
||||||
|
let lint_id = lint::LintId::of(lint);
|
||||||
let mut lints = self.lints.borrow_mut();
|
let mut lints = self.lints.borrow_mut();
|
||||||
match lints.find_mut(&id) {
|
match lints.find_mut(&id) {
|
||||||
Some(arr) => { arr.push((lint, sp, msg)); return; }
|
Some(arr) => { arr.push((lint_id, sp, msg)); return; }
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
lints.insert(id, vec!((lint, sp, msg)));
|
lints.insert(id, vec!((lint_id, sp, msg)));
|
||||||
}
|
}
|
||||||
pub fn next_node_id(&self) -> ast::NodeId {
|
pub fn next_node_id(&self) -> ast::NodeId {
|
||||||
self.reserve_node_ids(1)
|
self.reserve_node_ids(1)
|
||||||
|
|
|
@ -409,7 +409,7 @@ pub fn check_crate(sess: &Session, krate: &ast::Crate) {
|
||||||
directive not necessary");
|
directive not necessary");
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
sess.add_lint(lint::UnknownFeatures,
|
sess.add_lint(lint::builtin::unknown_features,
|
||||||
ast::CRATE_NODE_ID,
|
ast::CRATE_NODE_ID,
|
||||||
mi.span,
|
mi.span,
|
||||||
"unknown feature".to_string());
|
"unknown feature".to_string());
|
||||||
|
|
|
@ -127,6 +127,15 @@ pub mod lib {
|
||||||
pub mod llvmdeps;
|
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() {
|
pub fn main() {
|
||||||
let args = std::os::args().iter()
|
let args = std::os::args().iter()
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.to_string())
|
||||||
|
|
|
@ -19,7 +19,7 @@ use middle::privacy::ExportedItems;
|
||||||
use middle::{typeck, ty, def, pat_util};
|
use middle::{typeck, ty, def, pat_util};
|
||||||
use util::ppaux::{ty_to_str};
|
use util::ppaux::{ty_to_str};
|
||||||
use util::nodemap::NodeSet;
|
use util::nodemap::NodeSet;
|
||||||
use lint::{Context, LintPass};
|
use lint::{Context, LintPass, LintArray};
|
||||||
use lint;
|
use lint;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -41,31 +41,17 @@ use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::{ast, ast_util, visit};
|
use syntax::{ast, ast_util, visit};
|
||||||
|
|
||||||
/// Doesn't actually warn; just gathers information for use by
|
declare_lint!(while_true, Warn,
|
||||||
/// checks in trans.
|
"suggest using `loop { }` instead of `while true { }`")
|
||||||
#[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);
|
|
||||||
},
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deriving(Default)]
|
#[deriving(Default)]
|
||||||
pub struct WhileTrue;
|
pub struct WhileTrue;
|
||||||
|
|
||||||
impl LintPass for WhileTrue {
|
impl LintPass for WhileTrue {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(while_true)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprWhile(cond, _) => {
|
ast::ExprWhile(cond, _) => {
|
||||||
|
@ -73,8 +59,7 @@ impl LintPass for WhileTrue {
|
||||||
ast::ExprLit(lit) => {
|
ast::ExprLit(lit) => {
|
||||||
match lit.node {
|
match lit.node {
|
||||||
ast::LitBool(true) => {
|
ast::LitBool(true) => {
|
||||||
cx.span_lint(lint::WhileTrue,
|
cx.span_lint(while_true, e.span,
|
||||||
e.span,
|
|
||||||
"denote infinite loops with loop \
|
"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)]
|
#[deriving(Default)]
|
||||||
pub struct UnusedCasts;
|
pub struct UnusedCasts;
|
||||||
|
|
||||||
impl LintPass for UnusedCasts {
|
impl LintPass for UnusedCasts {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unnecessary_typecast)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprCast(expr, ty) => {
|
ast::ExprCast(expr, ty) => {
|
||||||
let t_t = ast_ty_to_ty(cx, &infer::new_infer_ctxt(cx.tcx), 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 {
|
if ty::get(ty::expr_ty(cx.tcx, expr)).sty == ty::get(t_t).sty {
|
||||||
cx.span_lint(lint::UnnecessaryTypecast, ty.span,
|
cx.span_lint(unnecessary_typecast, ty.span, "unnecessary type cast");
|
||||||
"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 {
|
pub struct TypeLimits {
|
||||||
/// Id of the last visited negated expression
|
/// Id of the last visited negated expression
|
||||||
negated_expr_id: ast::NodeId,
|
negated_expr_id: ast::NodeId,
|
||||||
|
@ -121,6 +121,10 @@ impl Default for TypeLimits {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass 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) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprUnary(ast::UnNeg, expr) => {
|
ast::ExprUnary(ast::UnNeg, expr) => {
|
||||||
|
@ -128,7 +132,7 @@ impl LintPass for TypeLimits {
|
||||||
ast::ExprLit(lit) => {
|
ast::ExprLit(lit) => {
|
||||||
match lit.node {
|
match lit.node {
|
||||||
ast::LitUint(..) => {
|
ast::LitUint(..) => {
|
||||||
cx.span_lint(lint::UnsignedNegate, e.span,
|
cx.span_lint(unsigned_negate, e.span,
|
||||||
"negation of unsigned int literal may \
|
"negation of unsigned int literal may \
|
||||||
be unintentional");
|
be unintentional");
|
||||||
},
|
},
|
||||||
|
@ -139,7 +143,7 @@ impl LintPass for TypeLimits {
|
||||||
let t = ty::expr_ty(cx.tcx, expr);
|
let t = ty::expr_ty(cx.tcx, expr);
|
||||||
match ty::get(t).sty {
|
match ty::get(t).sty {
|
||||||
ty::ty_uint(_) => {
|
ty::ty_uint(_) => {
|
||||||
cx.span_lint(lint::UnsignedNegate, e.span,
|
cx.span_lint(unsigned_negate, e.span,
|
||||||
"negation of unsigned int variable may \
|
"negation of unsigned int variable may \
|
||||||
be unintentional");
|
be unintentional");
|
||||||
},
|
},
|
||||||
|
@ -157,7 +161,7 @@ impl LintPass for TypeLimits {
|
||||||
},
|
},
|
||||||
ast::ExprBinary(binop, l, r) => {
|
ast::ExprBinary(binop, l, r) => {
|
||||||
if is_comparison(binop) && !check_limits(cx.tcx, 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");
|
"comparison is useless due to type limits");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -178,7 +182,7 @@ impl LintPass for TypeLimits {
|
||||||
lit_val *= -1;
|
lit_val *= -1;
|
||||||
}
|
}
|
||||||
if lit_val < min || lit_val > max {
|
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");
|
"literal out of range for its type");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -194,7 +198,7 @@ impl LintPass for TypeLimits {
|
||||||
_ => fail!()
|
_ => fail!()
|
||||||
};
|
};
|
||||||
if lit_val < min || lit_val > max {
|
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");
|
"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)]
|
#[deriving(Default)]
|
||||||
pub struct CTypes;
|
pub struct CTypes;
|
||||||
|
|
||||||
impl LintPass for 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_item(&mut self, cx: &Context, it: &ast::Item) {
|
||||||
fn check_ty(cx: &Context, ty: &ast::Ty) {
|
fn check_ty(cx: &Context, ty: &ast::Ty) {
|
||||||
match ty.node {
|
match ty.node {
|
||||||
ast::TyPath(_, _, id) => {
|
ast::TyPath(_, _, id) => {
|
||||||
match cx.tcx.def_map.borrow().get_copy(&id) {
|
match cx.tcx.def_map.borrow().get_copy(&id) {
|
||||||
def::DefPrimTy(ast::TyInt(ast::TyI)) => {
|
def::DefPrimTy(ast::TyInt(ast::TyI)) => {
|
||||||
cx.span_lint(lint::CTypes, ty.span,
|
cx.span_lint(ctypes, ty.span,
|
||||||
"found rust type `int` in foreign module, while \
|
"found rust type `int` in foreign module, while \
|
||||||
libc::c_int or libc::c_long should be used");
|
libc::c_int or libc::c_long should be used");
|
||||||
}
|
}
|
||||||
def::DefPrimTy(ast::TyUint(ast::TyU)) => {
|
def::DefPrimTy(ast::TyUint(ast::TyU)) => {
|
||||||
cx.span_lint(lint::CTypes, ty.span,
|
cx.span_lint(ctypes, ty.span,
|
||||||
"found rust type `uint` in foreign module, while \
|
"found rust type `uint` in foreign module, while \
|
||||||
libc::c_uint or libc::c_ulong should be used");
|
libc::c_uint or libc::c_ulong should be used");
|
||||||
}
|
}
|
||||||
def::DefTy(def_id) => {
|
def::DefTy(def_id) => {
|
||||||
if !adt::is_ffi_safe(cx.tcx, def_id) {
|
if !adt::is_ffi_safe(cx.tcx, def_id) {
|
||||||
cx.span_lint(lint::CTypes, ty.span,
|
cx.span_lint(ctypes, ty.span,
|
||||||
"found enum type without foreign-function-safe \
|
"found enum type without foreign-function-safe \
|
||||||
representation annotation in foreign module");
|
representation annotation in foreign module");
|
||||||
// hmm... this message could be more helpful
|
// 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)]
|
#[deriving(Default)]
|
||||||
pub struct HeapMemory;
|
pub struct HeapMemory;
|
||||||
|
|
||||||
impl HeapMemory {
|
impl HeapMemory {
|
||||||
fn check_heap_type(&self, cx: &Context, span: Span, ty: ty::t) {
|
fn check_heap_type(&self, cx: &Context, span: Span, ty: ty::t) {
|
||||||
let xs = [lint::ManagedHeapMemory, lint::OwnedHeapMemory, lint::HeapMemory];
|
let mut n_box = 0;
|
||||||
for &lint in xs.iter() {
|
let mut n_uniq = 0;
|
||||||
if cx.get_level(lint) == lint::Allow { continue }
|
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| {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => ()
|
if n_uniq > 0 {
|
||||||
};
|
let s = ty_to_str(cx.tcx, ty);
|
||||||
t
|
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 {
|
if n_box > 0 {
|
||||||
let s = ty_to_str(cx.tcx, ty);
|
let s = ty_to_str(cx.tcx, ty);
|
||||||
let m = format!("type uses owned (Box type) pointers: {}", s);
|
let m = format!("type uses managed (@ type) pointers: {}", s);
|
||||||
cx.span_lint(lint, span, m.as_slice());
|
cx.span_lint(managed_heap_memory, span, m.as_slice());
|
||||||
}
|
cx.span_lint(heap_memory, 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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass for HeapMemory {
|
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) {
|
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
|
||||||
match it.node {
|
match it.node {
|
||||||
ast::ItemFn(..) |
|
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> {
|
struct RawPtrDerivingVisitor<'a> {
|
||||||
cx: &'a Context<'a>
|
cx: &'a Context<'a>
|
||||||
}
|
}
|
||||||
|
@ -442,7 +466,7 @@ impl<'a> visit::Visitor<()> for RawPtrDerivingVisitor<'a> {
|
||||||
fn visit_ty(&mut self, ty: &ast::Ty, _: ()) {
|
fn visit_ty(&mut self, ty: &ast::Ty, _: ()) {
|
||||||
static MSG: &'static str = "use of `#[deriving]` with a raw pointer";
|
static MSG: &'static str = "use of `#[deriving]` with a raw pointer";
|
||||||
match ty.node {
|
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, ());
|
visit::walk_ty(self, ty, ());
|
||||||
|
@ -465,6 +489,10 @@ impl Default for RawPointerDeriving {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass 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) {
|
fn check_item(&mut self, cx: &Context, item: &ast::Item) {
|
||||||
if !attr::contains_name(item.attrs.as_slice(), "automatically_derived") {
|
if !attr::contains_name(item.attrs.as_slice(), "automatically_derived") {
|
||||||
return
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct UnusedAttribute;
|
pub struct UnusedAttribute;
|
||||||
|
|
||||||
impl LintPass for UnusedAttribute {
|
impl LintPass for UnusedAttribute {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unused_attribute)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
|
fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
|
||||||
static ATTRIBUTE_WHITELIST: &'static [&'static str] = &'static [
|
static ATTRIBUTE_WHITELIST: &'static [&'static str] = &'static [
|
||||||
// FIXME: #14408 whitelist docs since rustdoc looks at them
|
// FIXME: #14408 whitelist docs since rustdoc looks at them
|
||||||
|
@ -556,7 +591,7 @@ impl LintPass for UnusedAttribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !attr::is_used(attr) {
|
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()) {
|
if CRATE_ATTRS.contains(&attr.name().get()) {
|
||||||
let msg = match attr.node.style {
|
let msg = match attr.node.style {
|
||||||
ast::AttrOuter => "crate-level attribute should be an inner \
|
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 \
|
ast::AttrInner => "crate-level attribute should be in the \
|
||||||
root module",
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct PathStatement;
|
pub struct PathStatement;
|
||||||
|
|
||||||
impl LintPass for PathStatement {
|
impl LintPass for PathStatement {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(path_statement)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
|
fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
|
||||||
match s.node {
|
match s.node {
|
||||||
ast::StmtSemi(expr, _) => {
|
ast::StmtSemi(expr, _) => {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprPath(_) => {
|
ast::ExprPath(_) => cx.span_lint(path_statement, s.span,
|
||||||
cx.span_lint(lint::PathStatement,
|
"path statement with no effect"),
|
||||||
s.span,
|
_ => ()
|
||||||
"path statement with no effect");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
|
@ -591,10 +630,20 @@ impl LintPass for PathStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Default)]
|
declare_lint!(unused_must_use, Warn,
|
||||||
pub struct UnusedMustUse;
|
"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) {
|
fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
|
||||||
let expr = match s.node {
|
let expr = match s.node {
|
||||||
ast::StmtSemi(expr, _) => expr,
|
ast::StmtSemi(expr, _) => expr,
|
||||||
|
@ -620,7 +669,7 @@ impl LintPass for UnusedMustUse {
|
||||||
ast_map::NodeItem(it) => {
|
ast_map::NodeItem(it) => {
|
||||||
if attr::contains_name(it.attrs.as_slice(),
|
if attr::contains_name(it.attrs.as_slice(),
|
||||||
"must_use") {
|
"must_use") {
|
||||||
cx.span_lint(lint::UnusedMustUse, s.span,
|
cx.span_lint(unused_must_use, s.span,
|
||||||
"unused result which must be used");
|
"unused result which must be used");
|
||||||
warned = true;
|
warned = true;
|
||||||
}
|
}
|
||||||
|
@ -630,7 +679,7 @@ impl LintPass for UnusedMustUse {
|
||||||
} else {
|
} else {
|
||||||
csearch::get_item_attrs(&cx.tcx.sess.cstore, did, |attrs| {
|
csearch::get_item_attrs(&cx.tcx.sess.cstore, did, |attrs| {
|
||||||
if attr::contains_name(attrs.as_slice(), "must_use") {
|
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");
|
"unused result which must be used");
|
||||||
warned = true;
|
warned = true;
|
||||||
}
|
}
|
||||||
|
@ -640,21 +689,28 @@ impl LintPass for UnusedMustUse {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if !warned {
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct DeprecatedOwnedVector;
|
pub struct DeprecatedOwnedVector;
|
||||||
|
|
||||||
impl LintPass for 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) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
let t = ty::expr_ty(cx.tcx, e);
|
let t = ty::expr_ty(cx.tcx, e);
|
||||||
match ty::get(t).sty {
|
match ty::get(t).sty {
|
||||||
ty::ty_uniq(t) => match ty::get(t).sty {
|
ty::ty_uniq(t) => match ty::get(t).sty {
|
||||||
ty::ty_vec(_, None) => {
|
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`")
|
"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)]
|
#[deriving(Default)]
|
||||||
pub struct NonCamelCaseTypes;
|
pub struct NonCamelCaseTypes;
|
||||||
|
|
||||||
impl LintPass for 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 check_item(&mut self, cx: &Context, it: &ast::Item) {
|
||||||
fn is_camel_case(ident: ast::Ident) -> bool {
|
fn is_camel_case(ident: ast::Ident) -> bool {
|
||||||
let ident = token::get_ident(ident);
|
let ident = token::get_ident(ident);
|
||||||
|
@ -690,8 +753,7 @@ impl LintPass for NonCamelCaseTypes {
|
||||||
let s = token::get_ident(ident);
|
let s = token::get_ident(ident);
|
||||||
|
|
||||||
if !is_camel_case(ident) {
|
if !is_camel_case(ident) {
|
||||||
cx.span_lint(lint::
|
cx.span_lint(non_camel_case_types, span,
|
||||||
NonCamelCaseTypes, span,
|
|
||||||
format!("{} `{}` should have a camel case name such as `{}`",
|
format!("{} `{}` should have a camel case name such as `{}`",
|
||||||
sort, s, to_camel_case(s.get())).as_slice());
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct NonSnakeCaseFunctions;
|
pub struct NonSnakeCaseFunctions;
|
||||||
|
|
||||||
|
@ -785,7 +850,7 @@ impl NonSnakeCaseFunctions {
|
||||||
let s = token::get_ident(ident);
|
let s = token::get_ident(ident);
|
||||||
|
|
||||||
if !is_snake_case(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 `{}`",
|
format!("{} `{}` should have a snake case name such as `{}`",
|
||||||
sort, s, to_snake_case(s.get())).as_slice());
|
sort, s, to_snake_case(s.get())).as_slice());
|
||||||
}
|
}
|
||||||
|
@ -793,6 +858,10 @@ impl NonSnakeCaseFunctions {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass for NonSnakeCaseFunctions {
|
impl LintPass for NonSnakeCaseFunctions {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(non_snake_case_functions)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_fn(&mut self, cx: &Context,
|
fn check_fn(&mut self, cx: &Context,
|
||||||
fk: &visit::FnKind, _: &ast::FnDecl,
|
fk: &visit::FnKind, _: &ast::FnDecl,
|
||||||
_: &ast::Block, span: Span, _: ast::NodeId) {
|
_: &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)]
|
#[deriving(Default)]
|
||||||
pub struct NonUppercaseStatics;
|
pub struct NonUppercaseStatics;
|
||||||
|
|
||||||
impl LintPass for 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) {
|
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
|
||||||
match it.node {
|
match it.node {
|
||||||
// only check static constants
|
// only check static constants
|
||||||
|
@ -828,7 +904,7 @@ impl LintPass for NonUppercaseStatics {
|
||||||
// ones (some scripts don't have a concept of
|
// ones (some scripts don't have a concept of
|
||||||
// upper/lowercase)
|
// upper/lowercase)
|
||||||
if s.get().chars().any(|c| c.is_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 \
|
format!("static constant `{}` should have an uppercase name \
|
||||||
such as `{}`", s.get(),
|
such as `{}`", s.get(),
|
||||||
s.get().chars().map(|c| c.to_uppercase())
|
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) {
|
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||||
// Lint for constants that look like binding identifiers (#7526)
|
// 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 ident = path.segments.last().unwrap().identifier;
|
||||||
let s = token::get_ident(ident);
|
let s = token::get_ident(ident);
|
||||||
if s.get().chars().any(|c| c.is_lowercase()) {
|
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 \
|
format!("static constant in pattern `{}` should have an uppercase \
|
||||||
name such as `{}`", s.get(),
|
name such as `{}`", s.get(),
|
||||||
s.get().chars().map(|c| c.to_uppercase())
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct UppercaseVariables;
|
pub struct UppercaseVariables;
|
||||||
|
|
||||||
impl LintPass for UppercaseVariables {
|
impl LintPass for UppercaseVariables {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(uppercase_variables)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||||
match &p.node {
|
match &p.node {
|
||||||
&ast::PatIdent(_, ref path, _) => {
|
&ast::PatIdent(_, ref path, _) => {
|
||||||
|
@ -873,9 +968,7 @@ impl LintPass for UppercaseVariables {
|
||||||
let ident = path.segments.last().unwrap().identifier;
|
let ident = path.segments.last().unwrap().identifier;
|
||||||
let s = token::get_ident(ident);
|
let s = token::get_ident(ident);
|
||||||
if s.get().len() > 0 && s.get().char_at(0).is_uppercase() {
|
if s.get().len() > 0 && s.get().char_at(0).is_uppercase() {
|
||||||
cx.span_lint(lint::
|
cx.span_lint(uppercase_variables, path.span,
|
||||||
UppercaseVariables,
|
|
||||||
path.span,
|
|
||||||
"variable names should start with a lowercase character");
|
"variable names should start with a lowercase character");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -893,8 +986,7 @@ impl LintPass for UppercaseVariables {
|
||||||
ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
|
ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
|
||||||
let s = token::get_ident(ident);
|
let s = token::get_ident(ident);
|
||||||
if s.get().char_at(0).is_uppercase() {
|
if s.get().char_at(0).is_uppercase() {
|
||||||
cx.span_lint(lint::UppercaseVariables,
|
cx.span_lint(uppercase_variables, sf.span,
|
||||||
sf.span,
|
|
||||||
"structure field names should start with a lowercase character");
|
"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)]
|
#[deriving(Default)]
|
||||||
pub struct UnnecessaryParens;
|
pub struct UnnecessaryParens;
|
||||||
|
|
||||||
|
@ -911,9 +1006,8 @@ impl UnnecessaryParens {
|
||||||
fn check_unnecessary_parens_core(&self, cx: &Context, value: &ast::Expr, msg: &str) {
|
fn check_unnecessary_parens_core(&self, cx: &Context, value: &ast::Expr, msg: &str) {
|
||||||
match value.node {
|
match value.node {
|
||||||
ast::ExprParen(_) => {
|
ast::ExprParen(_) => {
|
||||||
cx.span_lint(lint::UnnecessaryParens, value.span,
|
cx.span_lint(unnecessary_parens, value.span,
|
||||||
format!("unnecessary parentheses around {}",
|
format!("unnecessary parentheses around {}", msg).as_slice())
|
||||||
msg).as_slice())
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -921,6 +1015,10 @@ impl UnnecessaryParens {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass for UnnecessaryParens {
|
impl LintPass for UnnecessaryParens {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unnecessary_parens)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
let (value, msg) = match e.node {
|
let (value, msg) = match e.node {
|
||||||
ast::ExprIf(cond, _, _) => (cond, "`if` condition"),
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct UnusedUnsafe;
|
pub struct UnusedUnsafe;
|
||||||
|
|
||||||
impl LintPass for UnusedUnsafe {
|
impl LintPass for UnusedUnsafe {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unused_unsafe)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
// Don't warn about generated blocks, that'll just pollute the output.
|
// Don't warn about generated blocks, that'll just pollute the output.
|
||||||
ast::ExprBlock(ref blk) => {
|
ast::ExprBlock(ref blk) => {
|
||||||
if blk.rules == ast::UnsafeBlock(ast::UserProvided) &&
|
if blk.rules == ast::UnsafeBlock(ast::UserProvided) &&
|
||||||
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
|
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
|
||||||
cx.span_lint(lint::UnusedUnsafe, blk.span,
|
cx.span_lint(unused_unsafe, blk.span, "unnecessary `unsafe` block");
|
||||||
"unnecessary `unsafe` block");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
|
@ -968,21 +1072,31 @@ impl LintPass for UnusedUnsafe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint!(unsafe_block, Allow,
|
||||||
|
"usage of an `unsafe` block")
|
||||||
|
|
||||||
#[deriving(Default)]
|
#[deriving(Default)]
|
||||||
pub struct UnsafeBlock;
|
pub struct UnsafeBlock;
|
||||||
|
|
||||||
impl LintPass for UnsafeBlock {
|
impl LintPass for UnsafeBlock {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unsafe_block)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
// Don't warn about generated blocks, that'll just pollute the output.
|
// Don't warn about generated blocks, that'll just pollute the output.
|
||||||
ast::ExprBlock(ref blk) if blk.rules == ast::UnsafeBlock(ast::UserProvided) => {
|
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)]
|
#[deriving(Default)]
|
||||||
pub struct UnusedMut;
|
pub struct UnusedMut;
|
||||||
|
|
||||||
|
@ -1016,14 +1130,18 @@ impl UnusedMut {
|
||||||
let used_mutables = cx.tcx.used_mut_nodes.borrow();
|
let used_mutables = cx.tcx.used_mut_nodes.borrow();
|
||||||
for (_, v) in mutables.iter() {
|
for (_, v) in mutables.iter() {
|
||||||
if !v.iter().any(|e| used_mutables.contains(e)) {
|
if !v.iter().any(|e| used_mutables.contains(e)) {
|
||||||
cx.span_lint(lint::UnusedMut, cx.tcx.map.span(*v.get(0)),
|
cx.span_lint(unused_mut, cx.tcx.map.span(*v.get(0)),
|
||||||
"variable does not need to be mutable");
|
"variable does not need to be mutable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass for UnusedMut {
|
impl LintPass for UnusedMut {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unused_mut)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprMatch(_, ref arms) => {
|
ast::ExprMatch(_, ref arms) => {
|
||||||
|
@ -1063,10 +1181,17 @@ enum Allocation {
|
||||||
BoxAllocation
|
BoxAllocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint!(unnecessary_allocation, Warn,
|
||||||
|
"detects unnecessary allocations that can be eliminated")
|
||||||
|
|
||||||
#[deriving(Default)]
|
#[deriving(Default)]
|
||||||
pub struct UnnecessaryAllocation;
|
pub struct UnnecessaryAllocation;
|
||||||
|
|
||||||
impl LintPass for UnnecessaryAllocation {
|
impl LintPass for UnnecessaryAllocation {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(unnecessary_allocation)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
// Warn if string and vector literals with sigils, or boxing expressions,
|
// Warn if string and vector literals with sigils, or boxing expressions,
|
||||||
// are immediately borrowed.
|
// are immediately borrowed.
|
||||||
|
@ -1086,27 +1211,24 @@ impl LintPass for UnnecessaryAllocation {
|
||||||
_ => return
|
_ => return
|
||||||
};
|
};
|
||||||
|
|
||||||
let report = |msg| {
|
|
||||||
cx.span_lint(lint::UnnecessaryAllocation, e.span, msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
match cx.tcx.adjustments.borrow().find(&e.id) {
|
match cx.tcx.adjustments.borrow().find(&e.id) {
|
||||||
Some(adjustment) => {
|
Some(adjustment) => {
|
||||||
match *adjustment {
|
match *adjustment {
|
||||||
ty::AutoDerefRef(ty::AutoDerefRef { autoref, .. }) => {
|
ty::AutoDerefRef(ty::AutoDerefRef { autoref, .. }) => {
|
||||||
match (allocation, autoref) {
|
match (allocation, autoref) {
|
||||||
(VectorAllocation, Some(ty::AutoBorrowVec(..))) => {
|
(VectorAllocation, Some(ty::AutoBorrowVec(..))) => {
|
||||||
report("unnecessary allocation, the sigil can be \
|
cx.span_lint(unnecessary_allocation, e.span,
|
||||||
removed");
|
"unnecessary allocation, the sigil can be removed");
|
||||||
}
|
}
|
||||||
(BoxAllocation,
|
(BoxAllocation,
|
||||||
Some(ty::AutoPtr(_, ast::MutImmutable))) => {
|
Some(ty::AutoPtr(_, ast::MutImmutable))) => {
|
||||||
report("unnecessary allocation, use & instead");
|
cx.span_lint(unnecessary_allocation, e.span,
|
||||||
|
"unnecessary allocation, use & instead");
|
||||||
}
|
}
|
||||||
(BoxAllocation,
|
(BoxAllocation,
|
||||||
Some(ty::AutoPtr(_, ast::MutMutable))) => {
|
Some(ty::AutoPtr(_, ast::MutMutable))) => {
|
||||||
report("unnecessary allocation, use &mut \
|
cx.span_lint(unnecessary_allocation, e.span,
|
||||||
instead");
|
"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 {
|
pub struct MissingDoc {
|
||||||
/// Set of nodes exported from this module.
|
/// Set of nodes exported from this module.
|
||||||
exported_items: Option<ExportedItems>,
|
exported_items: Option<ExportedItems>,
|
||||||
|
@ -1175,15 +1300,17 @@ impl MissingDoc {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if !has_doc {
|
if !has_doc {
|
||||||
cx.span_lint(lint::MissingDoc,
|
cx.span_lint(missing_doc, sp,
|
||||||
sp,
|
format!("missing documentation for {}", desc).as_slice());
|
||||||
format!("missing documentation for {}",
|
|
||||||
desc).as_slice());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LintPass for MissingDoc {
|
impl LintPass for MissingDoc {
|
||||||
|
fn get_lints(&self) -> LintArray {
|
||||||
|
lint_array!(missing_doc)
|
||||||
|
}
|
||||||
|
|
||||||
fn enter_lint_attrs(&mut self, _: &Context, attrs: &[ast::Attribute]) {
|
fn enter_lint_attrs(&mut self, _: &Context, attrs: &[ast::Attribute]) {
|
||||||
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
|
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
|
||||||
attr.check_name("doc") && match attr.meta_item_list() {
|
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
|
/// Checks for use of items with #[deprecated], #[experimental] and
|
||||||
/// #[unstable] (or none of them) attributes.
|
/// #[unstable] (or none of them) attributes.
|
||||||
#[deriving(Default)]
|
#[deriving(Default)]
|
||||||
pub struct Stability;
|
pub struct Stability;
|
||||||
|
|
||||||
impl LintPass for 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) {
|
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||||
let id = match e.node {
|
let id = match e.node {
|
||||||
ast::ExprPath(..) | ast::ExprStruct(..) => {
|
ast::ExprPath(..) | ast::ExprStruct(..) => {
|
||||||
|
@ -1342,13 +1482,13 @@ impl LintPass for Stability {
|
||||||
|
|
||||||
let (lint, label) = match stability {
|
let (lint, label) = match stability {
|
||||||
// no stability attributes == Unstable
|
// no stability attributes == Unstable
|
||||||
None => (lint::Unstable, "unmarked"),
|
None => (unstable, "unmarked"),
|
||||||
Some(attr::Stability { level: attr::Unstable, .. }) =>
|
Some(attr::Stability { level: attr::Unstable, .. }) =>
|
||||||
(lint::Unstable, "unstable"),
|
(unstable, "unstable"),
|
||||||
Some(attr::Stability { level: attr::Experimental, .. }) =>
|
Some(attr::Stability { level: attr::Experimental, .. }) =>
|
||||||
(lint::Experimental, "experimental"),
|
(experimental, "experimental"),
|
||||||
Some(attr::Stability { level: attr::Deprecated, .. }) =>
|
Some(attr::Stability { level: attr::Deprecated, .. }) =>
|
||||||
(lint::Deprecated, "deprecated"),
|
(deprecated, "deprecated"),
|
||||||
_ => return
|
_ => return
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1362,3 +1502,80 @@ impl LintPass for Stability {
|
||||||
cx.span_lint(lint, e.span, msg.as_slice());
|
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`.
|
//! this file, use `span_lint` instead of `add_lint`.
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
#![macro_escape]
|
||||||
|
|
||||||
use driver::session;
|
|
||||||
use middle::dead::DEAD_CODE_LINT_STR;
|
|
||||||
use middle::privacy::ExportedItems;
|
use middle::privacy::ExportedItems;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
|
use driver::session::Session;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -55,23 +55,83 @@ use std::gc::Gc;
|
||||||
use std::to_str::ToStr;
|
use std::to_str::ToStr;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::default::Default;
|
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::ast_util::IdVisitingOperation;
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
|
use syntax::attr;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token::InternedString;
|
|
||||||
use syntax::visit::{Visitor, FnKind};
|
use syntax::visit::{Visitor, FnKind};
|
||||||
use syntax::{ast, ast_util, visit};
|
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
|
#[macro_export]
|
||||||
/// node, and should not invoke methods recursively (unlike `Visitor`). Each
|
macro_rules! declare_lint (
|
||||||
/// method has a default do-nothing implementation. The trait also contains a
|
// FIXME(#14660): deduplicate
|
||||||
/// few lint-specific methods with no equivalent in `Visitor`.
|
(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 {
|
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_crate(&mut self, _: &Context, _: &ExportedItems, _: &ast::Crate) { }
|
||||||
fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
|
fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
|
||||||
fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
|
fn check_mod(&mut self, _: &Context, _: &ast::Mod, _: Span, _: ast::NodeId) { }
|
||||||
|
@ -116,63 +176,37 @@ trait LintPass {
|
||||||
|
|
||||||
type LintPassObject = Box<LintPass + 'static>;
|
type LintPassObject = Box<LintPass + 'static>;
|
||||||
|
|
||||||
#[deriving(Clone, Show, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
/// Identifies a lint known to the compiler.
|
||||||
pub enum LintId {
|
#[deriving(Clone)]
|
||||||
CTypes,
|
pub struct LintId {
|
||||||
UnusedImports,
|
// Identity is based on pointer equality of this field.
|
||||||
UnnecessaryQualification,
|
lint: &'static Lint,
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn level_to_str(lv: Level) -> &'static str {
|
impl PartialEq for LintId {
|
||||||
match lv {
|
fn eq(&self, other: &LintId) -> bool {
|
||||||
Allow => "allow",
|
(self.lint as *Lint) == (other.lint as *Lint)
|
||||||
Warn => "warn",
|
}
|
||||||
Deny => "deny",
|
}
|
||||||
Forbid => "forbid"
|
|
||||||
|
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
|
Allow, Warn, Deny, Forbid
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
|
impl Level {
|
||||||
pub struct LintSpec {
|
pub fn as_str(self) -> &'static str {
|
||||||
pub default: Level,
|
match self {
|
||||||
pub lint: LintId,
|
Allow => "allow",
|
||||||
pub desc: &'static str,
|
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
|
// this is public for the lints that run in trans
|
||||||
#[deriving(PartialEq)]
|
#[deriving(PartialEq)]
|
||||||
|
@ -198,331 +244,49 @@ pub enum LintSource {
|
||||||
CommandLine
|
CommandLine
|
||||||
}
|
}
|
||||||
|
|
||||||
static lint_table: &'static [(&'static str, LintSpec)] = &[
|
pub type LevelSource = (Level, LintSource);
|
||||||
("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()
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Context<'a> {
|
struct Context<'a> {
|
||||||
/// All known lint modes (string versions)
|
/// Trait objects for each lint pass.
|
||||||
dict: LintDict,
|
lint_objects: Vec<RefCell<LintPassObject>>,
|
||||||
/// Current levels of each lint warning
|
|
||||||
cur: SmallIntMap<(Level, LintSource)>,
|
/// Lints indexed by name.
|
||||||
/// Context we're checking in (used to access fields like sess)
|
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,
|
tcx: &'a ty::ctxt,
|
||||||
|
|
||||||
/// When recursing into an attributed node of the ast which modifies lint
|
/// When recursing into an attributed node of the ast which modifies lint
|
||||||
/// levels, this stack keeps track of the previous lint levels of whatever
|
/// levels, this stack keeps track of the previous lint levels of whatever
|
||||||
/// was modified.
|
/// 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
|
/// Level of lints for certain NodeIds, stored here because the body of
|
||||||
/// the lint needs to run in trans.
|
/// the lint needs to run in trans.
|
||||||
node_levels: RefCell<HashMap<(ast::NodeId, LintId), (Level, LintSource)>>,
|
node_levels: RefCell<HashMap<(ast::NodeId, LintId), LevelSource>>,
|
||||||
|
|
||||||
/// Trait objects for each lint.
|
|
||||||
lints: Vec<RefCell<LintPassObject>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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),*) => (
|
macro_rules! run_lints ( ($cx:expr, $f:ident, $($args:expr),*) => (
|
||||||
for tl in $cx.lints.iter() {
|
for obj in $cx.lint_objects.iter() {
|
||||||
tl.borrow_mut().$f($cx, $($args),*);
|
obj.borrow_mut().$f($cx, $($args),*);
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
||||||
pub fn emit_lint(level: Level, src: LintSource, msg: &str, span: Span,
|
/// Emit a lint as a `span_warn` or `span_err` (or not at all)
|
||||||
lint_str: &str, tcx: &ty::ctxt) {
|
/// 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 }
|
if level == Allow { return }
|
||||||
|
|
||||||
let mut note = None;
|
let mut note = None;
|
||||||
let msg = match src {
|
let msg = match source {
|
||||||
Default => {
|
Default => {
|
||||||
format!("{}, #[{}({})] on by default", msg,
|
format!("{}, #[{}({})] on by default", msg,
|
||||||
level_to_str(level), lint_str)
|
level_to_str(level), lint_str)
|
||||||
|
@ -532,75 +296,50 @@ pub fn emit_lint(level: Level, src: LintSource, msg: &str, span: Span,
|
||||||
match level {
|
match level {
|
||||||
Warn => 'W', Deny => 'D', Forbid => 'F',
|
Warn => 'W', Deny => 'D', Forbid => 'F',
|
||||||
Allow => fail!()
|
Allow => fail!()
|
||||||
}, lint_str.replace("_", "-"))
|
}, lint.name.replace("_", "-"))
|
||||||
},
|
},
|
||||||
Node(src) => {
|
Node(src) => {
|
||||||
note = Some(src);
|
note = Some(src);
|
||||||
msg.to_str()
|
msg.to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match level {
|
match level {
|
||||||
Warn => { tcx.sess.span_warn(span, msg.as_slice()); }
|
Warn => { sess.span_warn(span, msg.as_slice()); }
|
||||||
Deny | Forbid => { tcx.sess.span_err(span, msg.as_slice()); }
|
Deny | Forbid => { sess.span_err(span, msg.as_slice()); }
|
||||||
Allow => fail!(),
|
Allow => fail!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for &span in note.iter() {
|
for span in note.move_iter() {
|
||||||
tcx.sess.span_note(span, "lint level defined here");
|
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> {
|
impl<'a> Context<'a> {
|
||||||
fn get_level(&self, lint: LintId) -> Level {
|
fn get_level_source(&self, lint: LintId) -> LevelSource {
|
||||||
match self.cur.find(&(lint as uint)) {
|
match self.levels.find(&lint) {
|
||||||
Some(&(lvl, _)) => lvl,
|
Some(&s) => s,
|
||||||
None => Allow
|
None => (Allow, Default),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_source(&self, lint: LintId) -> LintSource {
|
fn set_level(&mut self, lint: LintId, lvlsrc: LevelSource) {
|
||||||
match self.cur.find(&(lint as uint)) {
|
if lvlsrc.val0() == Allow {
|
||||||
Some(&(_, src)) => src,
|
self.levels.remove(&lint);
|
||||||
None => Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_level(&mut self, lint: LintId, level: Level, src: LintSource) {
|
|
||||||
if level == Allow {
|
|
||||||
self.cur.remove(&(lint as uint));
|
|
||||||
} else {
|
} else {
|
||||||
self.cur.insert(lint as uint, (level, src));
|
self.levels.insert(lint, lvlsrc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_to_str(&self, lint: LintId) -> &'static str {
|
fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
|
||||||
for (k, v) in self.dict.iter() {
|
let (level, src) = match self.levels.find(&LintId::of(lint)) {
|
||||||
if v.lint == lint {
|
None => return,
|
||||||
return *k;
|
Some(&(Warn, src))
|
||||||
}
|
=> (self.get_level_source(LintId::of(builtin::warnings)).val0(), src),
|
||||||
}
|
|
||||||
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),
|
|
||||||
Some(&pair) => pair,
|
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
|
// current dictionary of lint information. Along the way, keep a history
|
||||||
// of what we changed so we can roll everything back after invoking the
|
// of what we changed so we can roll everything back after invoking the
|
||||||
// specified closure
|
// specified closure
|
||||||
|
let lint_attrs = self.gather_lint_attrs(attrs);
|
||||||
let mut pushed = 0u;
|
let mut pushed = 0u;
|
||||||
each_lint(&self.tcx.sess, attrs, |meta, level, lintname| {
|
for (lint_id, level, span) in lint_attrs.move_iter() {
|
||||||
match self.dict.find_equiv(&lintname) {
|
let now = self.get_level_source(lint_id).val0();
|
||||||
None => {
|
if now == Forbid && level != Forbid {
|
||||||
self.span_lint(
|
let lint_name = lint_id.as_str();
|
||||||
UnrecognizedLint,
|
self.tcx.sess.span_err(span,
|
||||||
meta.span,
|
format!("{}({}) overruled by outer forbid({})",
|
||||||
format!("unknown `{}` attribute: `{}`",
|
level.as_str(), lint_name, lint_name).as_slice());
|
||||||
level_to_str(level), lintname).as_slice());
|
} else if now != level {
|
||||||
}
|
let src = self.get_level_source(lint_id).val1();
|
||||||
Some(lint) => {
|
self.level_stack.push((lint_id, (now, src)));
|
||||||
let lint = lint.lint;
|
pushed += 1;
|
||||||
let now = self.get_level(lint);
|
self.set_level(lint_id, (level, Node(span)));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
true
|
}
|
||||||
});
|
|
||||||
|
|
||||||
run_lints!(self, enter_lint_attrs, attrs);
|
run_lints!(self, enter_lint_attrs, attrs);
|
||||||
f(self);
|
f(self);
|
||||||
|
@ -651,8 +377,8 @@ impl<'a> Context<'a> {
|
||||||
|
|
||||||
// rollback
|
// rollback
|
||||||
for _ in range(0, pushed) {
|
for _ in range(0, pushed) {
|
||||||
let (lint, lvl, src) = self.level_stack.pop().unwrap();
|
let (lint, lvlsrc) = self.level_stack.pop().unwrap();
|
||||||
self.set_level(lint, lvl, src);
|
self.set_level(lint, lvlsrc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,65 +391,49 @@ impl<'a> Context<'a> {
|
||||||
f(&mut v);
|
f(&mut v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_node_level(&self, id: ast::NodeId, lint: LintId, lvl: Level, src: LintSource) {
|
fn insert_node_level(&self, id: ast::NodeId, lint: LintId, lvlsrc: LevelSource) {
|
||||||
self.node_levels.borrow_mut().insert((id, lint), (lvl, src));
|
self.node_levels.borrow_mut().insert((id, lint), lvlsrc);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that every lint from the list of attributes satisfies `f`.
|
fn gather_lint_attrs(&mut self, attrs: &[ast::Attribute]) -> Vec<(LintId, Level, Span)> {
|
||||||
/// Return true if that's the case. Otherwise return false.
|
// Doing this as an iterator is messy due to multiple borrowing.
|
||||||
pub fn each_lint(sess: &session::Session,
|
// Allocating and copying these should be quick.
|
||||||
attrs: &[ast::Attribute],
|
let mut out = vec!();
|
||||||
f: |Gc<ast::MetaItem>, Level, InternedString| -> bool)
|
for attr in attrs.iter() {
|
||||||
-> bool {
|
let level = match Level::from_str(attr.name().get()) {
|
||||||
let xs = [Allow, Warn, Deny, Forbid];
|
None => continue,
|
||||||
for &level in xs.iter() {
|
Some(lvl) => lvl,
|
||||||
let level_name = level_to_str(level);
|
};
|
||||||
for attr in attrs.iter().filter(|m| m.check_name(level_name)) {
|
|
||||||
|
attr::mark_used(attr);
|
||||||
|
|
||||||
let meta = attr.node.value;
|
let meta = attr.node.value;
|
||||||
let metas = match meta.node {
|
let metas = match meta.node {
|
||||||
ast::MetaList(_, ref metas) => metas,
|
ast::MetaList(_, ref metas) => metas,
|
||||||
_ => {
|
_ => {
|
||||||
sess.span_err(meta.span, "malformed lint attribute");
|
self.tcx.sess.span_err(meta.span, "malformed lint attribute");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for meta in metas.iter() {
|
for meta in metas.iter() {
|
||||||
match meta.node {
|
match meta.node {
|
||||||
ast::MetaWord(ref lintname) => {
|
ast::MetaWord(ref lint_name) => {
|
||||||
if !f(*meta, level, (*lintname).clone()) {
|
match self.lints_by_name.find_equiv(lint_name) {
|
||||||
return false;
|
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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => self.tcx.sess.span_err(meta.span, "malformed lint attribute"),
|
||||||
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>{
|
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> {
|
impl<'a> IdVisitingOperation for Context<'a> {
|
||||||
fn visit_id(&self, id: ast::NodeId) {
|
fn visit_id(&self, id: ast::NodeId) {
|
||||||
match self.tcx.sess.lints.borrow_mut().pop(&id) {
|
match self.tcx.sess.lints.borrow_mut().pop(&id) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(l) => {
|
Some(lints) => {
|
||||||
for (lint, span, msg) in l.move_iter() {
|
for (lint_id, span, msg) in lints.move_iter() {
|
||||||
self.span_lint(lint, span, msg.as_slice())
|
self.span_lint(lint_id.lint, span, msg.as_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate(tcx: &ty::ctxt,
|
fn builtin_lints() -> Vec<Box<LintPass>> {
|
||||||
exported_items: &ExportedItems,
|
|
||||||
krate: &ast::Crate) {
|
|
||||||
macro_rules! builtin_lints (( $($name:ident),*, ) => (
|
macro_rules! builtin_lints (( $($name:ident),*, ) => (
|
||||||
vec!($(
|
vec!($(
|
||||||
{
|
{
|
||||||
let obj: builtin::$name = Default::default();
|
let obj: builtin::$name = Default::default();
|
||||||
RefCell::new(box obj as LintPassObject)
|
box obj as LintPassObject
|
||||||
}
|
}
|
||||||
),*)
|
),*)
|
||||||
))
|
))
|
||||||
|
|
||||||
let builtin_lints = builtin_lints!(
|
builtin_lints!(
|
||||||
GatherNodeLevels, WhileTrue, UnusedCasts, TypeLimits, CTypes,
|
WhileTrue, UnusedCasts, TypeLimits, CTypes, HeapMemory,
|
||||||
HeapMemory, RawPointerDeriving, UnusedAttribute,
|
RawPointerDeriving, UnusedAttribute, PathStatement,
|
||||||
PathStatement, UnusedMustUse, DeprecatedOwnedVector,
|
UnusedResult, DeprecatedOwnedVector, NonCamelCaseTypes,
|
||||||
NonCamelCaseTypes, NonSnakeCaseFunctions, NonUppercaseStatics,
|
NonSnakeCaseFunctions, NonUppercaseStatics,
|
||||||
UppercaseVariables, UnnecessaryParens, UnusedUnsafe, UnsafeBlock,
|
NonUppercasePatternStatics, UppercaseVariables,
|
||||||
UnusedMut, UnnecessaryAllocation, MissingDoc, Stability,
|
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 {
|
let mut cx = Context {
|
||||||
dict: get_lint_dict(),
|
lint_objects: lints,
|
||||||
cur: SmallIntMap::new(),
|
lints_by_name: HashMap::new(),
|
||||||
|
levels: HashMap::new(),
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
level_stack: Vec::new(),
|
level_stack: Vec::new(),
|
||||||
node_levels: RefCell::new(HashMap::new()),
|
node_levels: RefCell::new(HashMap::new()),
|
||||||
lints: builtin_lints,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Install default lint levels, followed by the command line levels, and
|
// Index the lints by name, and set the default levels.
|
||||||
// then actually visit the whole crate.
|
for obj in cx.lint_objects.iter() {
|
||||||
for (_, spec) in cx.dict.iter() {
|
for &lint in obj.borrow_mut().get_lints().iter() {
|
||||||
if spec.default != Allow {
|
let id = LintId::of(lint);
|
||||||
cx.cur.insert(spec.lint as uint, (spec.default, Default));
|
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.with_lint_attrs(krate.attrs.as_slice(), |cx| {
|
||||||
cx.visit_id(ast::CRATE_NODE_ID);
|
cx.visit_id(ast::CRATE_NODE_ID);
|
||||||
cx.visit_ids(|v| {
|
cx.visit_ids(|v| {
|
||||||
|
@ -983,8 +724,10 @@ pub fn check_crate(tcx: &ty::ctxt,
|
||||||
// in the iteration code.
|
// in the iteration code.
|
||||||
for (id, v) in tcx.sess.lints.borrow().iter() {
|
for (id, v) in tcx.sess.lints.borrow().iter() {
|
||||||
for &(lint, span, ref msg) in v.iter() {
|
for &(lint, span, ref msg) in v.iter() {
|
||||||
tcx.sess.span_bug(span, format!("unprocessed lint {} at {}: {}",
|
tcx.sess.span_bug(span,
|
||||||
lint, tcx.map.node_to_str(*id), *msg).as_slice())
|
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.
|
// from live codes are live, and everything else is dead.
|
||||||
|
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use lint::{Allow, contains_lint, DeadCode};
|
use lint;
|
||||||
use middle::privacy;
|
use middle::privacy;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
|
@ -23,14 +23,13 @@ use std::collections::HashSet;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_map;
|
use syntax::ast_map;
|
||||||
use syntax::ast_util::{local_def, is_local};
|
use syntax::ast_util::{local_def, is_local};
|
||||||
|
use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
use syntax::visit;
|
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
|
// 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
|
// explored. For example, if it's a live NodeItem that is a
|
||||||
// function, then we should explore its block to check for codes that
|
// 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 {
|
fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
|
||||||
contains_lint(attrs, Allow, DEAD_CODE_LINT_STR)
|
if attr::contains_name(attrs.as_slice(), "lang") {
|
||||||
|| 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
|
// This visitor seeds items that
|
||||||
|
@ -446,7 +461,7 @@ impl<'a> DeadVisitor<'a> {
|
||||||
ident: ast::Ident) {
|
ident: ast::Ident) {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.add_lint(DeadCode,
|
.add_lint(lint::builtin::dead_code,
|
||||||
id,
|
id,
|
||||||
span,
|
span,
|
||||||
format!("code is never used: `{}`",
|
format!("code is never used: `{}`",
|
||||||
|
|
|
@ -107,7 +107,7 @@ use middle::freevars;
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use lint::{UnusedVariable, DeadAssignment};
|
use lint;
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -1560,11 +1560,11 @@ impl<'a> Liveness<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_assigned {
|
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",
|
format!("variable `{}` is assigned to, but never used",
|
||||||
*name));
|
*name));
|
||||||
} else {
|
} 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));
|
format!("unused variable: `{}`", *name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1582,7 +1582,7 @@ impl<'a> Liveness<'a> {
|
||||||
if self.live_on_exit(ln, var).is_none() {
|
if self.live_on_exit(ln, var).is_none() {
|
||||||
let r = self.should_warn(var);
|
let r = self.should_warn(var);
|
||||||
for name in r.iter() {
|
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));
|
format!("value assigned to `{}` is never read", *name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1394,7 +1394,7 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
|
||||||
ast::TyPath(ref p, _, path_id) => {
|
ast::TyPath(ref p, _, path_id) => {
|
||||||
if self.path_is_private_type(path_id) {
|
if self.path_is_private_type(path_id) {
|
||||||
self.tcx.sess.add_lint(
|
self.tcx.sess.add_lint(
|
||||||
lint::VisiblePrivateTypes,
|
lint::builtin::visible_private_types,
|
||||||
path_id, p.span,
|
path_id, p.span,
|
||||||
"private type in exported type \
|
"private type in exported type \
|
||||||
signature".to_string());
|
signature".to_string());
|
||||||
|
|
|
@ -15,9 +15,9 @@ use metadata::csearch;
|
||||||
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
|
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
|
||||||
use middle::def::*;
|
use middle::def::*;
|
||||||
use middle::lang_items::LanguageItems;
|
use middle::lang_items::LanguageItems;
|
||||||
use lint::{UnnecessaryQualification, UnusedImports};
|
|
||||||
use middle::pat_util::pat_bindings;
|
use middle::pat_util::pat_bindings;
|
||||||
use middle::subst::{ParamSpace, FnSpace, TypeSpace};
|
use middle::subst::{ParamSpace, FnSpace, TypeSpace};
|
||||||
|
use lint;
|
||||||
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
|
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
|
||||||
|
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
|
@ -4632,7 +4632,7 @@ impl<'a> Resolver<'a> {
|
||||||
match (def, unqualified_def) {
|
match (def, unqualified_def) {
|
||||||
(Some((d, _)), Some((ud, _))) if d == ud => {
|
(Some((d, _)), Some((ud, _))) if d == ud => {
|
||||||
self.session
|
self.session
|
||||||
.add_lint(UnnecessaryQualification,
|
.add_lint(lint::builtin::unnecessary_qualification,
|
||||||
id,
|
id,
|
||||||
path.span,
|
path.span,
|
||||||
"unnecessary qualification".to_string());
|
"unnecessary qualification".to_string());
|
||||||
|
@ -5487,7 +5487,7 @@ impl<'a> Resolver<'a> {
|
||||||
if !self.used_imports.contains(&(id, TypeNS)) &&
|
if !self.used_imports.contains(&(id, TypeNS)) &&
|
||||||
!self.used_imports.contains(&(id, ValueNS)) {
|
!self.used_imports.contains(&(id, ValueNS)) {
|
||||||
self.session
|
self.session
|
||||||
.add_lint(UnusedImports,
|
.add_lint(lint::builtin::unused_imports,
|
||||||
id,
|
id,
|
||||||
p.span,
|
p.span,
|
||||||
"unused import".to_string());
|
"unused import".to_string());
|
||||||
|
@ -5511,7 +5511,7 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
if !self.used_imports.contains(&(id, TypeNS)) &&
|
if !self.used_imports.contains(&(id, TypeNS)) &&
|
||||||
!self.used_imports.contains(&(id, ValueNS)) {
|
!self.used_imports.contains(&(id, ValueNS)) {
|
||||||
self.session.add_lint(UnusedImports,
|
self.session.add_lint(lint::builtin::unused_imports,
|
||||||
id,
|
id,
|
||||||
span,
|
span,
|
||||||
"unused import".to_string());
|
"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) {
|
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 mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
|
||||||
|
|
||||||
let (lvl, src) = ccx.tcx.node_lint_levels.borrow()
|
let levels = ccx.tcx.node_lint_levels.borrow();
|
||||||
.find(&(id, lint::VariantSizeDifference))
|
match levels.find(&(id, lint::LintId::of(lint::builtin::variant_size_difference))) {
|
||||||
.map_or((lint::Allow, lint::Default), |&(lvl,src)| (lvl, src));
|
None | Some(&(lint::Allow, _)) => (),
|
||||||
|
Some(&lvlsrc) => {
|
||||||
if lvl != lint::Allow {
|
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
|
||||||
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
|
match *avar {
|
||||||
match *avar {
|
adt::General(_, ref variants) => {
|
||||||
adt::General(_, ref variants) => {
|
for var in variants.iter() {
|
||||||
for var in variants.iter() {
|
let mut size = 0;
|
||||||
let mut size = 0;
|
for field in var.fields.iter().skip(1) {
|
||||||
for field in var.fields.iter().skip(1) {
|
// skip the discriminant
|
||||||
// skip the discriminant
|
size += llsize_of_real(ccx, sizing_type_of(ccx, *field));
|
||||||
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),
|
let (largest, slargest, largest_index) = sizes.iter().enumerate().fold((0, 0, 0),
|
||||||
|(l, s, li), (idx, &size)|
|
|(l, s, li), (idx, &size)|
|
||||||
if size > l {
|
if size > l {
|
||||||
(size, l, idx)
|
(size, l, idx)
|
||||||
} else if size > s {
|
} else if size > s {
|
||||||
(l, size, li)
|
(l, size, li)
|
||||||
} else {
|
} else {
|
||||||
(l, s, li)
|
(l, s, li)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// we only warn if the largest variant is at least thrice as large as
|
// we only warn if the largest variant is at least thrice as large as
|
||||||
// the second-largest.
|
// the second-largest.
|
||||||
if largest > slargest * 3 && slargest > 0 {
|
if largest > slargest * 3 && slargest > 0 {
|
||||||
lint::emit_lint(lvl, src,
|
// Use lint::emit_lint rather than sess.add_lint because the lint-printing
|
||||||
format!("enum variant is more than three times larger \
|
// pass for the latter already ran.
|
||||||
({} bytes) than the next largest (ignoring padding)",
|
lint::emit_lint(&ccx.tcx().sess, lint::builtin::variant_size_difference,
|
||||||
largest).as_slice(),
|
lvlsrc, sp,
|
||||||
sp, lint::lint_to_str(lint::VariantSizeDifference), ccx.tcx());
|
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,
|
ccx.sess().span_note(enum_def.variants.get(largest_index).span,
|
||||||
"this variant is the largest");
|
"this variant is the largest");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -368,7 +368,7 @@ pub struct ctxt {
|
||||||
pub dependency_formats: RefCell<dependency_format::Dependencies>,
|
pub dependency_formats: RefCell<dependency_format::Dependencies>,
|
||||||
|
|
||||||
pub node_lint_levels: RefCell<HashMap<(ast::NodeId, lint::LintId),
|
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`
|
/// 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
|
/// to be valid. We gather up these restrictions in the intrinsicck pass
|
||||||
|
|
|
@ -79,7 +79,6 @@ type parameter).
|
||||||
|
|
||||||
use middle::const_eval;
|
use middle::const_eval;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use lint::UnreachableCode;
|
|
||||||
use middle::pat_util::pat_id_map;
|
use middle::pat_util::pat_id_map;
|
||||||
use middle::pat_util;
|
use middle::pat_util;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
|
@ -111,6 +110,7 @@ use middle::typeck::{require_same_types, vtable_map};
|
||||||
use middle::typeck::{MethodCall, MethodMap};
|
use middle::typeck::{MethodCall, MethodMap};
|
||||||
use middle::typeck::{TypeAndSubsts};
|
use middle::typeck::{TypeAndSubsts};
|
||||||
use middle::lang_items::TypeIdLangItem;
|
use middle::lang_items::TypeIdLangItem;
|
||||||
|
use lint;
|
||||||
use util::common::{block_query, indenter, loop_query};
|
use util::common::{block_query, indenter, loop_query};
|
||||||
use util::ppaux;
|
use util::ppaux;
|
||||||
use util::ppaux::{UserString, Repr};
|
use util::ppaux::{UserString, Repr};
|
||||||
|
@ -3416,7 +3416,7 @@ pub fn check_block_with_expected(fcx: &FnCtxt,
|
||||||
fcx.ccx
|
fcx.ccx
|
||||||
.tcx
|
.tcx
|
||||||
.sess
|
.sess
|
||||||
.add_lint(UnreachableCode,
|
.add_lint(lint::builtin::unreachable_code,
|
||||||
s_id,
|
s_id,
|
||||||
s.span,
|
s.span,
|
||||||
"unreachable statement".to_string());
|
"unreachable statement".to_string());
|
||||||
|
@ -3443,7 +3443,7 @@ pub fn check_block_with_expected(fcx: &FnCtxt,
|
||||||
fcx.ccx
|
fcx.ccx
|
||||||
.tcx
|
.tcx
|
||||||
.sess
|
.sess
|
||||||
.add_lint(UnreachableCode,
|
.add_lint(lint::builtin::unreachable_code,
|
||||||
e.id,
|
e.id,
|
||||||
e.span,
|
e.span,
|
||||||
"unreachable expression".to_string());
|
"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 input = FileInput(cpath.clone());
|
||||||
|
|
||||||
|
let warning_lint = lint::builtin::warnings.name.to_string();
|
||||||
|
|
||||||
let sessopts = driver::config::Options {
|
let sessopts = driver::config::Options {
|
||||||
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
|
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
|
||||||
addl_lib_search_paths: RefCell::new(libs),
|
addl_lib_search_paths: RefCell::new(libs),
|
||||||
crate_types: vec!(driver::config::CrateTypeRlib),
|
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()
|
..rustc::driver::config::basic_options().clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue