1
Fork 0
This commit is contained in:
Manish Goregaokar 2016-02-29 16:49:32 +05:30
parent e256055dc4
commit bd45cfd273
18 changed files with 137 additions and 203 deletions

View file

@ -92,8 +92,7 @@ impl LateLintPass for BlockInIfCondition {
snippet_block(cx, then.span, ".."))); snippet_block(cx, then.span, "..")));
} }
} else { } else {
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|e| e.span);
if in_macro(cx, span) || differing_macro_contexts(expr.span, span) { if in_macro(cx, span) || differing_macro_contexts(expr.span, span) {
return; return;
} }

View file

@ -71,15 +71,13 @@ fn check_if(cx: &LateContext, e: &Expr) {
}); });
}} }}
} else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) = } else if let Some(&Expr{ node: ExprIf(ref check_inner, ref content, None), span: sp, ..}) =
single_stmt_of_block(then) { single_stmt_of_block(then) {
if e.span.expn_id != sp.expn_id { if e.span.expn_id != sp.expn_id {
return; return;
} }
span_lint_and_then(cx, span_lint_and_then(cx, COLLAPSIBLE_IF, e.span, "this if statement can be collapsed", |db| {
COLLAPSIBLE_IF, db.span_suggestion(e.span,
e.span, "try",
"this if statement can be collapsed", |db| {
db.span_suggestion(e.span, "try",
format!("if {} && {} {}", format!("if {} && {} {}",
check_to_string(cx, check), check_to_string(cx, check),
check_to_string(cx, check_inner), check_to_string(cx, check_inner),

View file

@ -91,9 +91,7 @@ fn lint_same_then_else(cx: &LateContext, blocks: &[&Block]) {
h.finish() h.finish()
}; };
let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { let eq: &Fn(&&Block, &&Block) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).eq_block(lhs, rhs) };
SpanlessEq::new(cx).eq_block(lhs, rhs)
};
if let Some((i, j)) = search_same(blocks, hash, eq) { if let Some((i, j)) = search_same(blocks, hash, eq) {
span_note_and_lint(cx, span_note_and_lint(cx,

View file

@ -87,13 +87,7 @@ impl LateLintPass for Derive {
} }
/// Implementation of the `DERIVE_HASH_XOR_EQ` lint. /// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
fn check_hash_peq( fn check_hash_peq(cx: &LateContext, span: Span, trait_ref: &TraitRef, ty: ty::Ty, hash_is_automatically_derived: bool) {
cx: &LateContext,
span: Span,
trait_ref: &TraitRef,
ty: ty::Ty,
hash_is_automatically_derived: bool
) {
if_let_chain! {[ if_let_chain! {[
match_path(&trait_ref.path, &HASH_PATH), match_path(&trait_ref.path, &HASH_PATH),
let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait() let Some(peq_trait_def_id) = cx.tcx.lang_items.eq_trait()
@ -143,9 +137,7 @@ fn check_hash_peq(
} }
/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint. /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: ty::Ty<'tcx>) {
item: &Item,
trait_ref: &TraitRef, ty: ty::Ty<'tcx>) {
if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) { if match_path(&trait_ref.path, &CLONE_TRAIT_PATH) {
let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id); let parameter_environment = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
let subst_ty = ty.subst(cx.tcx, &parameter_environment.free_substs); let subst_ty = ty.subst(cx.tcx, &parameter_environment.free_substs);

View file

@ -48,7 +48,7 @@ impl LateLintPass for HashMapLint {
// in case of `if !m.contains_key(&k) { m.insert(k, v); }` // in case of `if !m.contains_key(&k) { m.insert(k, v); }`
// we can give a better error message // we can give a better error message
let sole_expr = else_block.is_none() && let sole_expr = else_block.is_none() &&
if then_block.expr.is_some() { 1 } else { 0 } + then_block.stmts.len() == 1; ((then_block.expr.is_some() as usize) + then_block.stmts.len() == 1);
let mut visitor = InsertVisitor { let mut visitor = InsertVisitor {
cx: cx, cx: cx,

View file

@ -31,17 +31,16 @@ fn var2str(var: &Variant) -> InternedString {
var.node.name.name.as_str() var.node.name.name.as_str()
} }
/* // FIXME: waiting for https://github.com/rust-lang/rust/pull/31700
FIXME: waiting for https://github.com/rust-lang/rust/pull/31700 // fn partial_match(pre: &str, name: &str) -> usize {
fn partial_match(pre: &str, name: &str) -> usize { // // skip(1) to ensure that the prefix never takes the whole variant name
// skip(1) to ensure that the prefix never takes the whole variant name // pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count()
pre.chars().zip(name.chars().rev().skip(1).rev()).take_while(|&(l, r)| l == r).count() // }
} //
// fn partial_rmatch(post: &str, name: &str) -> usize {
fn partial_rmatch(post: &str, name: &str) -> usize { // // skip(1) to ensure that the postfix never takes the whole variant name
// skip(1) to ensure that the postfix never takes the whole variant name // post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count()
post.chars().rev().zip(name.chars().skip(1).rev()).take_while(|&(l, r)| l == r).count() // }
}*/
fn partial_match(pre: &str, name: &str) -> usize { fn partial_match(pre: &str, name: &str) -> usize {
let mut name_iter = name.chars(); let mut name_iter = name.chars();
@ -99,7 +98,8 @@ impl EarlyLintPass for EnumVariantNames {
item.span, item.span,
&format!("All variants have the same {}fix: `{}`", what, value), &format!("All variants have the same {}fix: `{}`", what, value),
&format!("remove the {}fixes and use full paths to \ &format!("remove the {}fixes and use full paths to \
the variants instead of glob imports", what)); the variants instead of glob imports",
what));
} }
} }
} }

View file

@ -96,9 +96,11 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) {
span_note_and_lint(cx, span_note_and_lint(cx,
SUSPICIOUS_ASSIGNMENT_FORMATTING, SUSPICIOUS_ASSIGNMENT_FORMATTING,
eqop_span, eqop_span,
&format!("this looks like you are trying to use `.. {op}= ..`, but you really are doing `.. = ({op} ..)`", op=op), &format!("this looks like you are trying to use `.. {op}= ..`, but you \
really are doing `.. = ({op} ..)`",
op = op),
eqop_span, eqop_span,
&format!("to remove this lint, use either `{op}=` or `= {op}`", op=op)); &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op));
} }
} }
} }
@ -109,9 +111,7 @@ fn check_assign(cx: &EarlyContext, expr: &ast::Expr) {
/// Implementation of the SUSPICIOUS_ELSE_FORMATTING lint for weird `else if`. /// Implementation of the SUSPICIOUS_ELSE_FORMATTING lint for weird `else if`.
fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) { fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) {
if let Some((then, &Some(ref else_))) = unsugar_if(expr) { if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
if unsugar_if(else_).is_some() && if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(cx, then.span) {
!differing_macro_contexts(then.span, else_.span) &&
!in_macro(cx, then.span) {
// this will be a span from the closing } of the “then” block (excluding) to the // this will be a span from the closing } of the “then” block (excluding) to the
// “if” of the “else if” block (excluding) // “if” of the “else if” block (excluding)
let else_span = mk_sp(then.span.hi, else_.span.lo); let else_span = mk_sp(then.span.hi, else_.span.lo);
@ -127,7 +127,8 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) {
else_span, else_span,
"this is an `else if` but the formatting might hide it", "this is an `else if` but the formatting might hide it",
else_span, else_span,
"to remove this lint, remove the `else` or remove the new line between `else` and `if`"); "to remove this lint, remove the `else` or remove the new line between `else` \
and `if`");
} }
} }
} }
@ -136,10 +137,8 @@ fn check_else_if(cx: &EarlyContext, expr: &ast::Expr) {
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) { fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Expr) {
if !differing_macro_contexts(first.span, second.span) && if !differing_macro_contexts(first.span, second.span) && !in_macro(cx, first.span) &&
!in_macro(cx, first.span) && unsugar_if(first).is_some() && unsugar_if(second).is_some() {
unsugar_if(first).is_some() &&
unsugar_if(second).is_some() {
// where the else would be // where the else would be
let else_span = mk_sp(first.span.hi, second.span.lo); let else_span = mk_sp(first.span.hi, second.span.lo);
@ -150,14 +149,15 @@ fn check_consecutive_ifs(cx: &EarlyContext, first: &ast::Expr, second: &ast::Exp
else_span, else_span,
"this looks like an `else if` but the `else` is missing", "this looks like an `else if` but the `else` is missing",
else_span, else_span,
"to remove this lint, add the missing `else` or add a new line before the second `if`"); "to remove this lint, add the missing `else` or add a new line before the second \
`if`");
} }
} }
} }
} }
/// Match `if` or `else if` expressions and return the `then` and `else` block. /// Match `if` or `else if` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)>{ fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
match expr.node { match expr.node {
ast::ExprKind::If(_, ref then, ref else_) | ast::ExprKind::If(_, ref then, ref else_) |
ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)), ast::ExprKind::IfLet(_, _, ref then, ref else_) => Some((then, else_)),

View file

@ -155,17 +155,11 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str)
fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) { fn check_len_zero(cx: &LateContext, span: Span, name: &Name, args: &[P<Expr>], lit: &Lit, op: &str) {
if let Spanned{node: LitKind::Int(0, _), ..} = *lit { if let Spanned{node: LitKind::Int(0, _), ..} = *lit {
if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { if name.as_str() == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
span_lint_and_then(cx, span_lint_and_then(cx, LEN_ZERO, span, "length comparison to zero", |db| {
LEN_ZERO, db.span_suggestion(span,
span, "consider using `is_empty`",
"length comparison to zero", format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")));
|db| { });
db.span_suggestion(span,
"consider using `is_empty`",
format!("{}{}.is_empty()",
op,
snippet(cx, args[0].span, "_")));
});
} }
} }
} }

View file

@ -370,14 +370,14 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex
span_lint(cx, span_lint(cx,
NEEDLESS_RANGE_LOOP, NEEDLESS_RANGE_LOOP,
expr.span, expr.span,
&format!("the loop variable `{}` is used to index `{}`. \ &format!("the loop variable `{}` is used to index `{}`. Consider using `for ({}, \
Consider using `for ({}, item) in {}.iter().enumerate(){}{}` or similar iterators", item) in {}.iter().enumerate(){}{}` or similar iterators",
ident.node.name, ident.node.name,
indexed, indexed,
ident.node.name, ident.node.name,
indexed, indexed,
take, take,
skip)); skip));
} else { } else {
let repl = if starts_at_zero && take.is_empty() { let repl = if starts_at_zero && take.is_empty() {
format!("&{}", indexed) format!("&{}", indexed)
@ -390,9 +390,9 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex
expr.span, expr.span,
&format!("the loop variable `{}` is only used to index `{}`. \ &format!("the loop variable `{}` is only used to index `{}`. \
Consider using `for item in {}` or similar iterators", Consider using `for item in {}` or similar iterators",
ident.node.name, ident.node.name,
indexed, indexed,
repl)); repl));
} }
} }
} }
@ -447,9 +447,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
"consider using the following if \ "consider using the following if \
you are attempting to iterate \ you are attempting to iterate \
over this range in reverse", over this range in reverse",
format!("({}..{}).rev()` ", format!("({}..{}).rev()` ", stop_snippet, start_snippet));
stop_snippet,
start_snippet));
}); });
} else if eq { } else if eq {
// if they are equal, it's also problematic - this loop // if they are equal, it's also problematic - this loop
@ -744,6 +742,7 @@ impl<'v, 't> Visitor<'v> for VarUsedAfterLoopVisitor<'v, 't> {
/// Return true if the type of expr is one that provides IntoIterator impls /// Return true if the type of expr is one that provides IntoIterator impls
/// for &T and &mut T, such as Vec. /// for &T and &mut T, such as Vec.
#[cfg_attr(rustfmt, rustfmt_skip)]
fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool {
// no walk_ptrs_ty: calling iter() on a reference can make sense because it // no walk_ptrs_ty: calling iter() on a reference can make sense because it
// will allow further borrows afterwards // will allow further borrows afterwards

View file

@ -1,10 +1,8 @@
use rustc::lint::*; use rustc::lint::*;
use rustc_front::hir::*; use rustc_front::hir::*;
use utils::{CLONE_PATH, OPTION_PATH}; use utils::{CLONE_PATH, OPTION_PATH};
use utils::{ use utils::{is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, walk_ptrs_ty,
is_adjusted, match_path, match_trait_method, match_type, snippet, span_help_and_lint, walk_ptrs_ty_depth};
walk_ptrs_ty, walk_ptrs_ty_depth
};
/// **What it does:** This lint checks for mapping clone() over an iterator. /// **What it does:** This lint checks for mapping clone() over an iterator.
/// ///

View file

@ -134,10 +134,11 @@ impl LateLintPass for MatchPass {
} }
} }
#[cfg_attr(rustfmt, rustfmt_skip)]
fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
if arms.len() == 2 && if arms.len() == 2 &&
arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
arms[1].pats.len() == 1 && arms[1].guard.is_none() { arms[1].pats.len() == 1 && arms[1].guard.is_none() {
let els = if is_unit_expr(&arms[1].body) { let els = if is_unit_expr(&arms[1].body) {
None None
} else if let ExprBlock(_) = arms[1].body.node { } else if let ExprBlock(_) = arms[1].body.node {
@ -167,28 +168,28 @@ fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm],
lint, lint,
expr.span, expr.span,
"you seem to be trying to use match for destructuring a single pattern. \ "you seem to be trying to use match for destructuring a single pattern. \
Consider using `if let`", |db| { Consider using `if let`",
db.span_suggestion(expr.span, "try this", |db| {
format!("if let {} = {} {}{}", db.span_suggestion(expr.span,
snippet(cx, arms[0].pats[0].span, ".."), "try this",
snippet(cx, ex.span, ".."), format!("if let {} = {} {}{}",
expr_block(cx, &arms[0].body, None, ".."), snippet(cx, arms[0].pats[0].span, ".."),
els_str)); snippet(cx, ex.span, ".."),
}); expr_block(cx, &arms[0].body, None, ".."),
els_str));
});
} }
} }
fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: ty::Ty, els: Option<&Expr>) { fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, ty: ty::Ty, els: Option<&Expr>) {
// list of candidate Enums we know will never get any more members // list of candidate Enums we know will never get any more members
let candidates = &[ let candidates = &[(&COW_PATH, "Borrowed"),
(&COW_PATH, "Borrowed"), (&COW_PATH, "Cow::Borrowed"),
(&COW_PATH, "Cow::Borrowed"), (&COW_PATH, "Cow::Owned"),
(&COW_PATH, "Cow::Owned"), (&COW_PATH, "Owned"),
(&COW_PATH, "Owned"), (&OPTION_PATH, "None"),
(&OPTION_PATH, "None"), (&RESULT_PATH, "Err"),
(&RESULT_PATH, "Err"), (&RESULT_PATH, "Ok")];
(&RESULT_PATH, "Ok"),
];
let path = match arms[1].pats[0].node { let path = match arms[1].pats[0].node {
PatKind::TupleStruct(ref path, Some(ref inner)) => { PatKind::TupleStruct(ref path, Some(ref inner)) => {

View file

@ -565,7 +565,9 @@ fn lint_clone_double_ref(cx: &LateContext, expr: &Expr, arg: &Expr) {
let ty = cx.tcx.expr_ty(arg); let ty = cx.tcx.expr_ty(arg);
if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty { if let ty::TyRef(_, ty::TypeAndMut { ty: ref inner, .. }) = ty.sty {
if let ty::TyRef(..) = inner.sty { if let ty::TyRef(..) = inner.sty {
let mut db = span_lint(cx, CLONE_DOUBLE_REF, expr.span, let mut db = span_lint(cx,
CLONE_DOUBLE_REF,
expr.span,
"using `clone` on a double-reference; \ "using `clone` on a double-reference; \
this will copy the reference instead of cloning \ this will copy the reference instead of cloning \
the inner type"); the inner type");
@ -583,10 +585,7 @@ fn lint_extend(cx: &LateContext, expr: &Expr, args: &MethodArgs) {
} }
let arg_ty = cx.tcx.expr_ty(&args[1]); let arg_ty = cx.tcx.expr_ty(&args[1]);
if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) { if let Some((span, r)) = derefs_to_slice(cx, &args[1], &arg_ty) {
span_lint(cx, span_lint(cx, EXTEND_FROM_SLICE, expr.span, "use of `extend` to extend a Vec by a slice")
EXTEND_FROM_SLICE,
expr.span,
"use of `extend` to extend a Vec by a slice")
.span_suggestion(expr.span, .span_suggestion(expr.span,
"try this", "try this",
format!("{}.extend_from_slice({}{})", format!("{}.extend_from_slice({}{})",

View file

@ -60,9 +60,8 @@ impl LateLintPass for PrintLint {
// `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)` // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
else if args.len() == 2 && match_path(path, &FMT_ARGUMENTV1_NEW_PATH) { else if args.len() == 2 && match_path(path, &FMT_ARGUMENTV1_NEW_PATH) {
if let ExprPath(None, ref path) = args[1].node { if let ExprPath(None, ref path) = args[1].node {
if match_path(path, &DEBUG_FMT_METHOD_PATH) && if match_path(path, &DEBUG_FMT_METHOD_PATH) && !is_in_debug_impl(cx, expr) &&
!is_in_debug_impl(cx, expr) && is_expn_of(cx, expr.span, "panic").is_none() {
is_expn_of(cx, expr.span, "panic").is_none() {
span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting"); span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
} }
} }
@ -75,8 +74,10 @@ impl LateLintPass for PrintLint {
fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
let map = &cx.tcx.map; let map = &cx.tcx.map;
if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) { // `fmt` method // `fmt` method
if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) { // `Debug` impl if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) {
// `Debug` impl
if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) {
if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node { if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
return match_path(&tr.path, &["Debug"]); return match_path(&tr.path, &["Debug"]);
} }

View file

@ -147,7 +147,11 @@ fn str_span(base: Span, s: &str, c: usize) -> Span {
Some((b, _)) => base.lo + BytePos(b as u32), Some((b, _)) => base.lo + BytePos(b as u32),
_ => base.hi, _ => base.hi,
}; };
Span{ lo: lo, hi: lo, ..base } Span {
lo: lo,
hi: lo,
..base
}
} }
fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> { fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> {

View file

@ -144,7 +144,7 @@ impl LateLintPass for StringLitAsBytes {
let msg = format!("calling `as_bytes()` on a string literal. \ let msg = format!("calling `as_bytes()` on a string literal. \
Consider using a byte string literal instead: \ Consider using a byte string literal instead: \
`b{}`", `b{}`",
snippet(cx, args[0].span, r#""foo""#)); snippet(cx, args[0].span, r#""foo""#));
span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg); span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg);
} }
} }

View file

@ -390,7 +390,8 @@ impl LateLintPass for CastPass {
check_truncation_and_wrapping(cx, expr, cast_from, cast_to); check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
} }
(false, false) => { (false, false) => {
if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) = (&cast_from.sty, &cast_to.sty) { if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) = (&cast_from.sty,
&cast_to.sty) {
span_lint(cx, span_lint(cx,
CAST_POSSIBLE_TRUNCATION, CAST_POSSIBLE_TRUNCATION,
expr.span, expr.span,
@ -570,7 +571,7 @@ impl LateLintPass for CharLitAsU8 {
truncates them"; truncates them";
let help = format!("Consider using a byte literal \ let help = format!("Consider using a byte literal \
instead:\nb{}", instead:\nb{}",
snippet(cx, e.span, "'x'")); snippet(cx, e.span, "'x'"));
span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help); span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help);
} }
} }
@ -623,7 +624,10 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs
type Extr<'a> = ExtremeExpr<'a>; type Extr<'a> = ExtremeExpr<'a>;
// Put the expression in the form lhs < rhs or lhs <= rhs. // Put the expression in the form lhs < rhs or lhs <= rhs.
enum Rel { Lt, Le }; enum Rel {
Lt,
Le,
};
let (rel, lhs2, rhs2) = match op { let (rel, lhs2, rhs2) = match op {
BiLt => (Rel::Lt, lhs, rhs), BiLt => (Rel::Lt, lhs, rhs),
BiLe => (Rel::Le, lhs, rhs), BiLe => (Rel::Le, lhs, rhs),

View file

@ -38,10 +38,8 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
(&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => { (&StmtDecl(ref l, _), &StmtDecl(ref r, _)) => {
if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) { if let (&DeclLocal(ref l), &DeclLocal(ref r)) = (&l.node, &r.node) {
// TODO: tys // TODO: tys
l.ty.is_none() && r.ty.is_none() && l.ty.is_none() && r.ty.is_none() && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) } else {
}
else {
false false
} }
} }
@ -71,15 +69,9 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
} }
match (&left.node, &right.node) { match (&left.node, &right.node) {
(&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => { (&ExprAddrOf(lmut, ref le), &ExprAddrOf(rmut, ref re)) => lmut == rmut && self.eq_expr(le, re),
lmut == rmut && self.eq_expr(le, re) (&ExprAgain(li), &ExprAgain(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()),
} (&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr),
(&ExprAgain(li), &ExprAgain(ri)) => {
both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str())
}
(&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => {
self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
}
(&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => { (&ExprAssignOp(ref lo, ref ll, ref lr), &ExprAssignOp(ref ro, ref rl, ref rr)) => {
lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
} }
@ -87,79 +79,50 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
(&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => { (&ExprBinary(lop, ref ll, ref lr), &ExprBinary(rop, ref rl, ref rr)) => {
lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) lop.node == rop.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
} }
(&ExprBreak(li), &ExprBreak(ri)) => { (&ExprBreak(li), &ExprBreak(ri)) => both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()),
both(&li, &ri, |l, r| l.node.name.as_str() == r.node.name.as_str()) (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
}
(&ExprBox(ref l), &ExprBox(ref r)) => {
self.eq_expr(l, r)
}
(&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => { (&ExprCall(ref lfun, ref largs), &ExprCall(ref rfun, ref rargs)) => {
!self.ignore_fn && !self.ignore_fn && self.eq_expr(lfun, rfun) && self.eq_exprs(largs, rargs)
self.eq_expr(lfun, rfun) &&
self.eq_exprs(largs, rargs)
}
(&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => {
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
} }
(&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt),
(&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => { (&ExprField(ref lfexp, ref lfident), &ExprField(ref rfexp, ref rfident)) => {
lfident.node == rfident.node && self.eq_expr(lfexp, rfexp) lfident.node == rfident.node && self.eq_expr(lfexp, rfexp)
} }
(&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => { (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
self.eq_expr(la, ra) && self.eq_expr(li, ri)
}
(&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => { (&ExprIf(ref lc, ref lt, ref le), &ExprIf(ref rc, ref rt, ref re)) => {
self.eq_expr(lc, rc) && self.eq_expr(lc, rc) && self.eq_block(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
self.eq_block(lt, rt) &&
both(le, re, |l, r| self.eq_expr(l, r))
} }
(&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node, (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
(&ExprLoop(ref lb, ref ll), &ExprLoop(ref rb, ref rl)) => { (&ExprLoop(ref lb, ref ll), &ExprLoop(ref rb, ref rl)) => {
self.eq_block(lb, rb) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
} }
(&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => { (&ExprMatch(ref le, ref la, ref ls), &ExprMatch(ref re, ref ra, ref rs)) => {
ls == rs && ls == rs && self.eq_expr(le, re) &&
self.eq_expr(le, re) && over(la, ra, |l, r| {
over(la, ra, |l, r| { self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) &&
self.eq_expr(&l.body, &r.body) && over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) && })
over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
})
} }
(&ExprMethodCall(ref lname, ref ltys, ref largs), &ExprMethodCall(ref rname, ref rtys, ref rargs)) => { (&ExprMethodCall(ref lname, ref ltys, ref largs),
&ExprMethodCall(ref rname, ref rtys, ref rargs)) => {
// TODO: tys // TODO: tys
!self.ignore_fn && !self.ignore_fn && lname.node == rname.node && ltys.is_empty() && rtys.is_empty() &&
lname.node == rname.node && self.eq_exprs(largs, rargs)
ltys.is_empty() &&
rtys.is_empty() &&
self.eq_exprs(largs, rargs)
} }
(&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => { (&ExprRange(ref lb, ref le), &ExprRange(ref rb, ref re)) => {
both(lb, rb, |l, r| self.eq_expr(l, r)) && both(lb, rb, |l, r| self.eq_expr(l, r)) && both(le, re, |l, r| self.eq_expr(l, r))
both(le, re, |l, r| self.eq_expr(l, r))
}
(&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => {
self.eq_expr(le, re) && self.eq_expr(ll, rl)
}
(&ExprRet(ref l), &ExprRet(ref r)) => {
both(l, r, |l, r| self.eq_expr(l, r))
} }
(&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => self.eq_expr(le, re) && self.eq_expr(ll, rl),
(&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => { (&ExprPath(ref lqself, ref lsubpath), &ExprPath(ref rqself, ref rsubpath)) => {
both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath) both(lqself, rqself, |l, r| self.eq_qself(l, r)) && self.eq_path(lsubpath, rsubpath)
} }
(&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup), (&ExprTup(ref ltup), &ExprTup(ref rtup)) => self.eq_exprs(ltup, rtup),
(&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => { (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
li.node == ri.node && self.eq_expr(le, re) (&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => lop == rop && self.eq_expr(le, re),
}
(&ExprUnary(lop, ref le), &ExprUnary(rop, ref re)) => {
lop == rop && self.eq_expr(le, re)
}
(&ExprVec(ref l), &ExprVec(ref r)) => self.eq_exprs(l, r), (&ExprVec(ref l), &ExprVec(ref r)) => self.eq_exprs(l, r),
(&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => { (&ExprWhile(ref lc, ref lb, ref ll), &ExprWhile(ref rc, ref rb, ref rl)) => {
self.eq_expr(lc, rc) && self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
self.eq_block(lb, rb) &&
both(ll, rl, |l, r| l.name.as_str() == r.name.as_str())
} }
_ => false, _ => false,
} }
@ -172,39 +135,25 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
/// Check whether two patterns are the same. /// Check whether two patterns are the same.
pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool { pub fn eq_pat(&self, left: &Pat, right: &Pat) -> bool {
match (&left.node, &right.node) { match (&left.node, &right.node) {
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => { (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
self.eq_pat(l, r)
}
(&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => { (&PatKind::TupleStruct(ref lp, ref la), &PatKind::TupleStruct(ref rp, ref ra)) => {
self.eq_path(lp, rp) && self.eq_path(lp, rp) && both(la, ra, |l, r| over(l, r, |l, r| self.eq_pat(l, r)))
both(la, ra, |l, r| {
over(l, r, |l, r| self.eq_pat(l, r))
})
} }
(&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(ref rb, ref ri, ref rp)) => { (&PatKind::Ident(ref lb, ref li, ref lp), &PatKind::Ident(ref rb, ref ri, ref rp)) => {
lb == rb && li.node.name.as_str() == ri.node.name.as_str() && lb == rb && li.node.name.as_str() == ri.node.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
both(lp, rp, |l, r| self.eq_pat(l, r))
}
(&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => {
self.eq_expr(l, r)
} }
(&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
(&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => { (&PatKind::QPath(ref ls, ref lp), &PatKind::QPath(ref rs, ref rp)) => {
self.eq_qself(ls, rs) && self.eq_path(lp, rp) self.eq_qself(ls, rs) && self.eq_path(lp, rp)
} }
(&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => { (&PatKind::Tup(ref l), &PatKind::Tup(ref r)) => over(l, r, |l, r| self.eq_pat(l, r)),
over(l, r, |l, r| self.eq_pat(l, r))
}
(&PatKind::Range(ref ls, ref le), &PatKind::Range(ref rs, ref re)) => { (&PatKind::Range(ref ls, ref le), &PatKind::Range(ref rs, ref re)) => {
self.eq_expr(ls, rs) && self.eq_expr(ls, rs) && self.eq_expr(le, re)
self.eq_expr(le, re)
}
(&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => {
lm == rm && self.eq_pat(le, re)
} }
(&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
(&PatKind::Vec(ref ls, ref li, ref le), &PatKind::Vec(ref rs, ref ri, ref re)) => { (&PatKind::Vec(ref ls, ref li, ref le), &PatKind::Vec(ref rs, ref ri, ref re)) => {
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) &&
over(le, re, |l, r| self.eq_pat(l, r)) && both(li, ri, |l, r| self.eq_pat(l, r))
both(li, ri, |l, r| self.eq_pat(l, r))
} }
(&PatKind::Wild, &PatKind::Wild) => true, (&PatKind::Wild, &PatKind::Wild) => true,
_ => false, _ => false,

View file

@ -137,8 +137,7 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
iter.inspect(|_| len += 1) iter.inspect(|_| len += 1)
.zip(path) .zip(path)
.all(|(nm, p)| nm.name().as_str() == *p) .all(|(nm, p)| nm.name().as_str() == *p) && len == path.len()
&& len == path.len()
}) })
} }
@ -600,11 +599,10 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
/// Return the pre-expansion span if is this comes from an expansion of the macro `name`. /// Return the pre-expansion span if is this comes from an expansion of the macro `name`.
pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> { pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> {
loop { loop {
let span_name_span = cx.tcx.sess.codemap().with_expn_info(span.expn_id, |expn| { let span_name_span = cx.tcx
expn.map(|ei| { .sess
(ei.callee.name(), ei.call_site) .codemap()
}) .with_expn_info(span.expn_id, |expn| expn.map(|ei| (ei.callee.name(), ei.call_site)));
});
match span_name_span { match span_name_span {
Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span), Some((mac_name, new_span)) if mac_name.as_str() == name => return Some(new_span),