1
Fork 0

also run rustfmt on clippy-lints

This commit is contained in:
Oliver Schneider 2016-12-20 18:21:30 +01:00
parent 4d0864b277
commit 4a4e1ea2c5
No known key found for this signature in database
GPG key ID: 56D6EEA0FC67AC46
72 changed files with 1017 additions and 1204 deletions

View file

@ -25,6 +25,7 @@ script:
- remark -f README.md > /dev/null - remark -f README.md > /dev/null
- python util/update_lints.py -c - python util/update_lints.py -c
- PATH=$PATH:~/.cargo/bin cargo fmt -- --write-mode=diff - PATH=$PATH:~/.cargo/bin cargo fmt -- --write-mode=diff
- cd clippy_lints && PATH=$PATH:~/.cargo/bin cargo fmt -- --write-mode=diff
- set -e - set -e
- cargo build --features debugging - cargo build --features debugging
- cargo test --features debugging - cargo test --features debugging

View file

@ -67,7 +67,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
self.span = Some(expr.span); self.span = Some(expr.span);
} }
} },
hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
let ty = cx.tcx.tables().expr_ty(arg); let ty = cx.tcx.tables().expr_ty(arg);
if ty.is_integral() { if ty.is_integral() {
@ -77,7 +77,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
self.span = Some(expr.span); self.span = Some(expr.span);
} }
} },
_ => (), _ => (),
} }
} }

View file

@ -123,7 +123,7 @@ fn to_const_range(start: Option<Option<ConstVal>>, end: Option<Option<ConstVal>>
} else { } else {
x x
} }
} },
Some(_) => return None, Some(_) => return None,
None => array_size, None => array_size,
}; };

View file

@ -95,8 +95,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
expr.span, expr.span,
"variable appears on both sides of an assignment operation", "variable appears on both sides of an assignment operation",
|db| { |db| {
if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), if let (Some(snip_a), Some(snip_r)) =
snippet_opt(cx, rhs.span)) { (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) {
db.span_suggestion(expr.span, db.span_suggestion(expr.span,
"replace it with", "replace it with",
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); format!("{} {}= {}", snip_a, op.node.as_str(), snip_r));
@ -113,7 +113,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
} }
} }
} }
} },
hir::ExprAssign(ref assignee, ref e) => { hir::ExprAssign(ref assignee, ref e) => {
if let hir::ExprBinary(op, ref l, ref r) = e.node { if let hir::ExprBinary(op, ref l, ref r) = e.node {
let lint = |assignee: &hir::Expr, rhs: &hir::Expr| { let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
@ -176,8 +176,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
expr.span, expr.span,
"manual implementation of an assign operation", "manual implementation of an assign operation",
|db| { |db| {
if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), if let (Some(snip_a), Some(snip_r)) =
snippet_opt(cx, rhs.span)) { (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) {
db.span_suggestion(expr.span, db.span_suggestion(expr.span,
"replace it with", "replace it with",
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)); format!("{} {}= {}", snip_a, op.node.as_str(), snip_r));
@ -195,13 +195,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
hir::BiAdd | hir::BiMul | hir::BiAnd | hir::BiOr | hir::BiBitXor | hir::BiBitAnd | hir::BiAdd | hir::BiMul | hir::BiAnd | hir::BiOr | hir::BiBitXor | hir::BiBitAnd |
hir::BiBitOr => { hir::BiBitOr => {
lint(assignee, l); lint(assignee, l);
} },
_ => {} _ => {},
} }
} }
} }
} },
_ => {} _ => {},
} }
} }
} }
@ -209,23 +209,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
fn is_commutative(op: hir::BinOp_) -> bool { fn is_commutative(op: hir::BinOp_) -> bool {
use rustc::hir::BinOp_::*; use rustc::hir::BinOp_::*;
match op { match op {
BiAdd | BiAdd | BiMul | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr | BiEq | BiNe => true,
BiMul | BiSub | BiDiv | BiRem | BiShl | BiShr | BiLt | BiLe | BiGe | BiGt => false,
BiAnd |
BiOr |
BiBitXor |
BiBitAnd |
BiBitOr |
BiEq |
BiNe => true,
BiSub |
BiDiv |
BiRem |
BiShl |
BiShr |
BiLt |
BiLe |
BiGe |
BiGt => false,
} }
} }

View file

@ -120,11 +120,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
} }
if let Some(mut sugg) = snippet_opt(cx, attr.span) { if let Some(mut sugg) = snippet_opt(cx, attr.span) {
if sugg.len() > 1 { if sugg.len() > 1 {
span_lint_and_then(cx, USELESS_ATTRIBUTE, attr.span, span_lint_and_then(cx,
USELESS_ATTRIBUTE,
attr.span,
"useless lint attribute", "useless lint attribute",
|db| { |db| {
sugg.insert(1, '!'); sugg.insert(1, '!');
db.span_suggestion(attr.span, "if you just forgot a `!`, use", sugg); db.span_suggestion(attr.span,
"if you just forgot a `!`, use",
sugg);
}); });
} }
} }
@ -181,7 +185,7 @@ fn is_relevant_block(cx: &LateContext, block: &Block) -> bool {
StmtExpr(ref expr, _) | StmtExpr(ref expr, _) |
StmtSemi(ref expr, _) => { StmtSemi(ref expr, _) => {
return is_relevant_expr(cx, expr); return is_relevant_expr(cx, expr);
} },
} }
} }
block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, e)) block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, e))
@ -191,7 +195,8 @@ fn is_relevant_expr(cx: &LateContext, expr: &Expr) -> bool {
match expr.node { match expr.node {
ExprBlock(ref block) => is_relevant_block(cx, block), ExprBlock(ref block) => is_relevant_block(cx, block),
ExprRet(Some(ref e)) => is_relevant_expr(cx, e), ExprRet(Some(ref e)) => is_relevant_expr(cx, e),
ExprRet(None) | ExprBreak(_, None) => false, ExprRet(None) |
ExprBreak(_, None) => false,
ExprCall(ref path_expr, _) => { ExprCall(ref path_expr, _) => {
if let ExprPath(ref qpath) = path_expr.node { if let ExprPath(ref qpath) = path_expr.node {
let fun_id = resolve_node(cx, qpath, path_expr.id).def_id(); let fun_id = resolve_node(cx, qpath, path_expr.id).def_id();
@ -199,7 +204,7 @@ fn is_relevant_expr(cx: &LateContext, expr: &Expr) -> bool {
} else { } else {
true true
} }
} },
_ => true, _ => true,
} }
} }

View file

@ -134,7 +134,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value:
} else if mask_value == 0 { } else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
} }
} },
BiBitOr => { BiBitOr => {
if mask_value | cmp_value != cmp_value { if mask_value | cmp_value != cmp_value {
span_lint(cx, span_lint(cx,
@ -144,10 +144,10 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value:
mask_value, mask_value,
cmp_value)); cmp_value));
} }
} },
_ => (), _ => (),
} }
} },
BiLt | BiGe => { BiLt | BiGe => {
match bit_op { match bit_op {
BiBitAnd => { BiBitAnd => {
@ -161,7 +161,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value:
} else if mask_value == 0 { } else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
} }
} },
BiBitOr => { BiBitOr => {
if mask_value >= cmp_value { if mask_value >= cmp_value {
span_lint(cx, span_lint(cx,
@ -173,11 +173,11 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value:
} else { } else {
check_ineffective_lt(cx, *span, mask_value, cmp_value, "|"); check_ineffective_lt(cx, *span, mask_value, cmp_value, "|");
} }
} },
BiBitXor => check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"), BiBitXor => check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"),
_ => (), _ => (),
} }
} },
BiLe | BiGt => { BiLe | BiGt => {
match bit_op { match bit_op {
BiBitAnd => { BiBitAnd => {
@ -191,7 +191,7 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value:
} else if mask_value == 0 { } else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero"); span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
} }
} },
BiBitOr => { BiBitOr => {
if mask_value > cmp_value { if mask_value > cmp_value {
span_lint(cx, span_lint(cx,
@ -203,11 +203,11 @@ fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_, mask_value:
} else { } else {
check_ineffective_gt(cx, *span, mask_value, cmp_value, "|"); check_ineffective_gt(cx, *span, mask_value, cmp_value, "|");
} }
} },
BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"), BiBitXor => check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"),
_ => (), _ => (),
} }
} },
_ => (), _ => (),
} }
} }
@ -244,7 +244,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> {
} else { } else {
None None
} }
} },
ExprPath(ref qpath) => { ExprPath(ref qpath) => {
let def = cx.tcx.tables().qpath_def(qpath, lit.id); let def = cx.tcx.tables().qpath_def(qpath, lit.id);
if let Def::Const(def_id) = def { if let Def::Const(def_id) = def {
@ -252,7 +252,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option<u64> {
} else { } else {
None None
} }
} },
_ => None, _ => None,
} }
} }

View file

@ -110,7 +110,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
} }
} }
} else { } else {
let mut visitor = ExVisitor { found_block: None, cx: cx }; let mut visitor = ExVisitor {
found_block: None,
cx: cx,
};
walk_expr(&mut visitor, check); walk_expr(&mut visitor, check);
if let Some(block) = visitor.found_block { if let Some(block) = visitor.found_block {
span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE); span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);

View file

@ -94,14 +94,14 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)), BiAnd => return Ok(Bool::And(self.extract(BiAnd, &[lhs, rhs], Vec::new())?)),
_ => (), _ => (),
} }
} },
ExprLit(ref lit) => { ExprLit(ref lit) => {
match lit.node { match lit.node {
LitKind::Bool(true) => return Ok(Bool::True), LitKind::Bool(true) => return Ok(Bool::True),
LitKind::Bool(false) => return Ok(Bool::False), LitKind::Bool(false) => return Ok(Bool::False),
_ => (), _ => (),
} }
} },
_ => (), _ => (),
} }
} }
@ -129,7 +129,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
BiLe => mk_expr(BiGt), BiLe => mk_expr(BiGt),
_ => continue, _ => continue,
} }
} },
_ => continue, _ => continue,
}; };
if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) { if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) {
@ -156,17 +156,17 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
True => { True => {
s.push_str("true"); s.push_str("true");
s s
} },
False => { False => {
s.push_str("false"); s.push_str("false");
s s
} },
Not(ref inner) => { Not(ref inner) => {
match **inner { match **inner {
And(_) | Or(_) => { And(_) | Or(_) => {
s.push('!'); s.push('!');
recurse(true, cx, inner, terminals, s) recurse(true, cx, inner, terminals, s)
} },
Term(n) => { Term(n) => {
if let ExprBinary(binop, ref lhs, ref rhs) = terminals[n as usize].node { if let ExprBinary(binop, ref lhs, ref rhs) = terminals[n as usize].node {
let op = match binop.node { let op = match binop.node {
@ -179,7 +179,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
_ => { _ => {
s.push('!'); s.push('!');
return recurse(true, cx, inner, terminals, s); return recurse(true, cx, inner, terminals, s);
} },
}; };
s.push_str(&snip(lhs)); s.push_str(&snip(lhs));
s.push_str(op); s.push_str(op);
@ -189,13 +189,13 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
s.push('!'); s.push('!');
recurse(false, cx, inner, terminals, s) recurse(false, cx, inner, terminals, s)
} }
} },
_ => { _ => {
s.push('!'); s.push('!');
recurse(false, cx, inner, terminals, s) recurse(false, cx, inner, terminals, s)
},
} }
} },
}
And(ref v) => { And(ref v) => {
if brackets { if brackets {
s.push('('); s.push('(');
@ -217,7 +217,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
s.push(')'); s.push(')');
} }
s s
} },
Or(ref v) => { Or(ref v) => {
if brackets { if brackets {
s.push('('); s.push('(');
@ -231,7 +231,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
s.push(')'); s.push(')');
} }
s s
} },
Term(n) => { Term(n) => {
if brackets { if brackets {
if let ExprBinary(..) = terminals[n as usize].node { if let ExprBinary(..) = terminals[n as usize].node {
@ -245,7 +245,7 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
} }
} }
s s
} },
} }
} }
recurse(false, cx, suggestion, terminals, String::new()) recurse(false, cx, suggestion, terminals, String::new())
@ -262,13 +262,13 @@ fn simple_negate(b: Bool) -> Bool {
*el = simple_negate(::std::mem::replace(el, True)); *el = simple_negate(::std::mem::replace(el, True));
} }
Or(v) Or(v)
} },
Or(mut v) => { Or(mut v) => {
for el in &mut v { for el in &mut v {
*el = simple_negate(::std::mem::replace(el, True)); *el = simple_negate(::std::mem::replace(el, True));
} }
And(v) And(v)
} },
Not(inner) => *inner, Not(inner) => *inner,
} }
} }
@ -290,13 +290,13 @@ fn terminal_stats(b: &Bool) -> Stats {
_ => stats.negations += 1, _ => stats.negations += 1,
} }
recurse(inner, stats); recurse(inner, stats);
} },
And(ref v) | Or(ref v) => { And(ref v) | Or(ref v) => {
stats.ops += v.len() - 1; stats.ops += v.len() - 1;
for inner in v { for inner in v {
recurse(inner, stats); recurse(inner, stats);
} }
} },
Term(n) => stats.terminals[n as usize] += 1, Term(n) => stats.terminals[n as usize] += 1,
} }
} }
@ -325,7 +325,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
let mut simplified = expr.simplify(); let mut simplified = expr.simplify();
for simple in Bool::Not(Box::new(expr.clone())).simplify() { for simple in Bool::Not(Box::new(expr.clone())).simplify() {
match simple { match simple {
Bool::Not(_) | Bool::True | Bool::False => {} Bool::Not(_) | Bool::True | Bool::False => {},
_ => simplified.push(Bool::Not(Box::new(simple.clone()))), _ => simplified.push(Bool::Not(Box::new(simple.clone()))),
} }
let simple_negated = simple_negate(simple); let simple_negated = simple_negate(simple);
@ -399,7 +399,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
} else { } else {
walk_expr(self, e); walk_expr(self, e);
} }
} },
_ => walk_expr(self, e), _ => walk_expr(self, e),
} }
} }

View file

@ -92,10 +92,10 @@ fn check_if(cx: &EarlyContext, expr: &ast::Expr) {
} else { } else {
check_collapsible_no_if_let(cx, expr, check, then); check_collapsible_no_if_let(cx, expr, check, then);
} }
} },
ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => { ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => {
check_collapsible_maybe_if_let(cx, else_); check_collapsible_maybe_if_let(cx, else_);
} },
_ => (), _ => (),
} }
} }
@ -120,12 +120,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext, else_: &ast::Expr) {
}} }}
} }
fn check_collapsible_no_if_let( fn check_collapsible_no_if_let(cx: &EarlyContext, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) {
cx: &EarlyContext,
expr: &ast::Expr,
check: &ast::Expr,
then: &ast::Block,
) {
if_let_chain! {[ if_let_chain! {[
let Some(inner) = expr_block(then), let Some(inner) = expr_block(then),
let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node, let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node,
@ -151,7 +146,8 @@ fn expr_block(block: &ast::Block) -> Option<&ast::Expr> {
if let (Some(stmt), None) = (it.next(), it.next()) { if let (Some(stmt), None) = (it.next(), it.next()) {
match stmt.node { match stmt.node {
ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => Some(expr), ast::StmtKind::Expr(ref expr) |
ast::StmtKind::Semi(ref expr) => Some(expr),
_ => None, _ => None,
} }
} else { } else {

View file

@ -75,18 +75,16 @@ impl PartialEq for Constant {
(&Constant::Char(l), &Constant::Char(r)) => l == r, (&Constant::Char(l), &Constant::Char(r)) => l == r,
(&Constant::Int(l), &Constant::Int(r)) => { (&Constant::Int(l), &Constant::Int(r)) => {
l.is_negative() == r.is_negative() && l.to_u64_unchecked() == r.to_u64_unchecked() l.is_negative() == r.is_negative() && l.to_u64_unchecked() == r.to_u64_unchecked()
} },
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
// we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
// `Fw32 == Fw64` so dont compare them // `Fw32 == Fw64` so dont compare them
match (ls.parse::<f64>(), rs.parse::<f64>()) { match (ls.parse::<f64>(), rs.parse::<f64>()) {
// mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs
(Ok(l), Ok(r)) => unsafe { (Ok(l), Ok(r)) => unsafe { mem::transmute::<f64, u64>(l) == mem::transmute::<f64, u64>(r) },
mem::transmute::<f64, u64>(l) == mem::transmute::<f64, u64>(r)
},
_ => false, _ => false,
} }
} },
(&Constant::Bool(l), &Constant::Bool(r)) => l == r, (&Constant::Bool(l), &Constant::Bool(r)) => l == r,
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l == r, (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l == r,
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv, (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
@ -104,34 +102,34 @@ impl Hash for Constant {
Constant::Str(ref s, ref k) => { Constant::Str(ref s, ref k) => {
s.hash(state); s.hash(state);
k.hash(state); k.hash(state);
} },
Constant::Binary(ref b) => { Constant::Binary(ref b) => {
b.hash(state); b.hash(state);
} },
Constant::Char(c) => { Constant::Char(c) => {
c.hash(state); c.hash(state);
} },
Constant::Int(i) => { Constant::Int(i) => {
i.to_u64_unchecked().hash(state); i.to_u64_unchecked().hash(state);
i.is_negative().hash(state); i.is_negative().hash(state);
} },
Constant::Float(ref f, _) => { Constant::Float(ref f, _) => {
// dont use the width here because of PartialEq implementation // dont use the width here because of PartialEq implementation
if let Ok(f) = f.parse::<f64>() { if let Ok(f) = f.parse::<f64>() {
unsafe { mem::transmute::<f64, u64>(f) }.hash(state); unsafe { mem::transmute::<f64, u64>(f) }.hash(state);
} }
} },
Constant::Bool(b) => { Constant::Bool(b) => {
b.hash(state); b.hash(state);
} },
Constant::Vec(ref v) | Constant::Vec(ref v) |
Constant::Tuple(ref v) => { Constant::Tuple(ref v) => {
v.hash(state); v.hash(state);
} },
Constant::Repeat(ref c, l) => { Constant::Repeat(ref c, l) => {
c.hash(state); c.hash(state);
l.hash(state); l.hash(state);
} },
} }
} }
} }
@ -145,19 +143,21 @@ impl PartialOrd for Constant {
} else { } else {
None None
} }
} },
(&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)),
(&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)), (&Constant::Int(l), &Constant::Int(r)) => Some(l.cmp(&r)),
(&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => { (&Constant::Float(ref ls, _), &Constant::Float(ref rs, _)) => {
match (ls.parse::<f64>(), rs.parse::<f64>()) { match (ls.parse::<f64>(), rs.parse::<f64>()) {
(Ok(ref l), Ok(ref r)) => match (l.partial_cmp(r), l.is_sign_positive() == r.is_sign_positive()) { (Ok(ref l), Ok(ref r)) => {
match (l.partial_cmp(r), l.is_sign_positive() == r.is_sign_positive()) {
// Check for comparison of -0.0 and 0.0 // Check for comparison of -0.0 and 0.0
(Some(Ordering::Equal), false) => None, (Some(Ordering::Equal), false) => None,
(x, _) => x (x, _) => x,
}
}, },
_ => None, _ => None,
} }
} },
(&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)), (&Constant::Bool(ref l), &Constant::Bool(ref r)) => Some(l.cmp(r)),
(&Constant::Tuple(ref l), &Constant::Tuple(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) |
(&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(r), (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l.partial_cmp(r),
@ -166,7 +166,7 @@ impl PartialOrd for Constant {
Some(Equal) => Some(ls.cmp(rs)), Some(Equal) => Some(ls.cmp(rs)),
x => x, x => x,
} }
} },
_ => None, //TODO: Are there any useful inter-type orderings? _ => None, //TODO: Are there any useful inter-type orderings?
} }
} }
@ -187,14 +187,14 @@ pub fn lit_to_constant(lit: &LitKind) -> Constant {
LitKind::Int(value, LitIntType::Unsigned(UintTy::U64)) => Constant::Int(ConstInt::U64(value as u64)), LitKind::Int(value, LitIntType::Unsigned(UintTy::U64)) => Constant::Int(ConstInt::U64(value as u64)),
LitKind::Int(value, LitIntType::Unsigned(UintTy::Us)) => { LitKind::Int(value, LitIntType::Unsigned(UintTy::Us)) => {
Constant::Int(ConstInt::Usize(ConstUsize::Us32(value as u32))) Constant::Int(ConstInt::Usize(ConstUsize::Us32(value as u32)))
} },
LitKind::Int(value, LitIntType::Signed(IntTy::I8)) => Constant::Int(ConstInt::I8(value as i8)), LitKind::Int(value, LitIntType::Signed(IntTy::I8)) => Constant::Int(ConstInt::I8(value as i8)),
LitKind::Int(value, LitIntType::Signed(IntTy::I16)) => Constant::Int(ConstInt::I16(value as i16)), LitKind::Int(value, LitIntType::Signed(IntTy::I16)) => Constant::Int(ConstInt::I16(value as i16)),
LitKind::Int(value, LitIntType::Signed(IntTy::I32)) => Constant::Int(ConstInt::I32(value as i32)), LitKind::Int(value, LitIntType::Signed(IntTy::I32)) => Constant::Int(ConstInt::I32(value as i32)),
LitKind::Int(value, LitIntType::Signed(IntTy::I64)) => Constant::Int(ConstInt::I64(value as i64)), LitKind::Int(value, LitIntType::Signed(IntTy::I64)) => Constant::Int(ConstInt::I64(value as i64)),
LitKind::Int(value, LitIntType::Signed(IntTy::Is)) => { LitKind::Int(value, LitIntType::Signed(IntTy::Is)) => {
Constant::Int(ConstInt::Isize(ConstIsize::Is32(value as i32))) Constant::Int(ConstInt::Isize(ConstIsize::Is32(value as i32)))
} },
LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()), LitKind::Float(ref is, ty) => Constant::Float(is.to_string(), ty.into()),
LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any), LitKind::FloatUnsuffixed(ref is) => Constant::Float(is.to_string(), FloatWidth::Any),
LitKind::Bool(b) => Constant::Bool(b), LitKind::Bool(b) => Constant::Bool(b),
@ -260,7 +260,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple),
ExprRepeat(ref value, ref number) => { ExprRepeat(ref value, ref number) => {
self.binop_apply(value, number, |v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize))) self.binop_apply(value, number, |v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize)))
} },
ExprUnary(op, ref operand) => { ExprUnary(op, ref operand) => {
self.expr(operand).and_then(|o| { self.expr(operand).and_then(|o| {
match op { match op {
@ -269,7 +269,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
UnDeref => Some(o), UnDeref => Some(o),
} }
}) })
} },
ExprBinary(op, ref left, ref right) => self.binop(op, left, right), ExprBinary(op, ref left, ref right) => self.binop(op, left, right),
// TODO: add other expressions // TODO: add other expressions
_ => None, _ => None,
@ -289,8 +289,11 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
if let Some(lcx) = self.lcx { if let Some(lcx) = self.lcx {
let def = lcx.tcx.tables().qpath_def(qpath, id); let def = lcx.tcx.tables().qpath_def(qpath, id);
match def { match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => { Def::Const(def_id) |
let substs = Some(lcx.tcx.tables().node_id_item_substs(id) Def::AssociatedConst(def_id) => {
let substs = Some(lcx.tcx
.tables()
.node_id_item_substs(id)
.unwrap_or_else(|| lcx.tcx.intern_substs(&[]))); .unwrap_or_else(|| lcx.tcx.intern_substs(&[])));
if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, def_id, substs) { if let Some((const_expr, _ty)) = lookup_const_by_id(lcx.tcx, def_id, substs) {
let ret = self.expr(const_expr); let ret = self.expr(const_expr);

View file

@ -205,7 +205,9 @@ fn lint_match_arms(cx: &LateContext, expr: &Expr) {
if let PatKind::Wild = j.pats[0].node { if let PatKind::Wild = j.pats[0].node {
// if the last arm is _, then i could be integrated into _ // if the last arm is _, then i could be integrated into _
// note that i.pats[0] cannot be _, because that would mean that we're hiding all the subsequent arms, and rust won't compile // note that i.pats[0] cannot be _, because that would mean that we're hiding all the subsequent arms, and rust won't compile
db.span_note(i.body.span, &format!("`{}` has the same arm body as the `_` wildcard, consider removing it`", lhs)); db.span_note(i.body.span,
&format!("`{}` has the same arm body as the `_` wildcard, consider removing it`",
lhs));
} else { } else {
db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs)); db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
} }
@ -253,7 +255,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned
for pat in pats { for pat in pats {
bindings_impl(cx, pat, map); bindings_impl(cx, pat, map);
} }
} },
PatKind::Binding(_, _, ref ident, ref as_pat) => { PatKind::Binding(_, _, ref ident, ref as_pat) => {
if let Entry::Vacant(v) = map.entry(ident.node.as_str()) { if let Entry::Vacant(v) = map.entry(ident.node.as_str()) {
v.insert(cx.tcx.tables().pat_ty(pat)); v.insert(cx.tcx.tables().pat_ty(pat));
@ -261,17 +263,17 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned
if let Some(ref as_pat) = *as_pat { if let Some(ref as_pat) = *as_pat {
bindings_impl(cx, as_pat, map); bindings_impl(cx, as_pat, map);
} }
} },
PatKind::Struct(_, ref fields, _) => { PatKind::Struct(_, ref fields, _) => {
for pat in fields { for pat in fields {
bindings_impl(cx, &pat.node.pat, map); bindings_impl(cx, &pat.node.pat, map);
} }
} },
PatKind::Tuple(ref fields, _) => { PatKind::Tuple(ref fields, _) => {
for pat in fields { for pat in fields {
bindings_impl(cx, pat, map); bindings_impl(cx, pat, map);
} }
} },
PatKind::Slice(ref lhs, ref mid, ref rhs) => { PatKind::Slice(ref lhs, ref mid, ref rhs) => {
for pat in lhs { for pat in lhs {
bindings_impl(cx, pat, map); bindings_impl(cx, pat, map);
@ -282,7 +284,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<Interned
for pat in rhs { for pat in rhs {
bindings_impl(cx, pat, map); bindings_impl(cx, pat, map);
} }
} },
PatKind::Lit(..) | PatKind::Lit(..) |
PatKind::Range(..) | PatKind::Range(..) |
PatKind::Wild | PatKind::Wild |
@ -320,10 +322,10 @@ fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)>
return Some((o, expr)); return Some((o, expr));
} }
} }
} },
Entry::Vacant(v) => { Entry::Vacant(v) => {
v.insert(vec![expr]); v.insert(vec![expr]);
} },
} }
} }

View file

@ -136,7 +136,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
if arms_n > 1 { if arms_n > 1 {
self.match_arms += arms_n - 2; self.match_arms += arms_n - 2;
} }
} },
ExprCall(ref callee, _) => { ExprCall(ref callee, _) => {
walk_expr(self, e); walk_expr(self, e);
let ty = self.cx.tcx.tables().node_id_to_type(callee.id); let ty = self.cx.tcx.tables().node_id_to_type(callee.id);
@ -144,10 +144,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
ty::TyFnDef(_, _, ty) | ty::TyFnDef(_, _, ty) |
ty::TyFnPtr(ty) if ty.sig.skip_binder().output().sty == ty::TyNever => { ty::TyFnPtr(ty) if ty.sig.skip_binder().output().sty == ty::TyNever => {
self.divergence += 1; self.divergence += 1;
} },
_ => (), _ => (),
} }
} },
ExprClosure(..) => (), ExprClosure(..) => (),
ExprBinary(op, _, _) => { ExprBinary(op, _, _) => {
walk_expr(self, e); walk_expr(self, e);
@ -155,7 +155,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
BiAnd | BiOr => self.short_circuits += 1, BiAnd | BiOr => self.short_circuits += 1,
_ => (), _ => (),
} }
} },
ExprRet(_) => self.returns += 1, ExprRet(_) => self.returns += 1,
_ => walk_expr(self, e), _ => walk_expr(self, e),
} }

View file

@ -149,18 +149,18 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
match field.ty(cx.tcx, substs).sty { match field.ty(cx.tcx, substs).sty {
TypeVariants::TyArray(_, size) if size > 32 => { TypeVariants::TyArray(_, size) if size > 32 => {
return; return;
} },
TypeVariants::TyFnPtr(..) => { TypeVariants::TyFnPtr(..) => {
return; return;
} },
TypeVariants::TyTuple(tys) if tys.len() > 12 => { TypeVariants::TyTuple(tys) if tys.len() > 12 => {
return; return;
} },
_ => (), _ => (),
} }
} }
} }
} },
_ => (), _ => (),
} }

View file

@ -64,26 +64,21 @@ pub fn strip_doc_comment_decoration((comment, span): (String, Span)) -> Vec<(Str
const ONELINERS: &'static [&'static str] = &["///!", "///", "//!", "//"]; const ONELINERS: &'static [&'static str] = &["///!", "///", "//!", "//"];
for prefix in ONELINERS { for prefix in ONELINERS {
if comment.starts_with(*prefix) { if comment.starts_with(*prefix) {
return vec![( return vec![(comment[prefix.len()..].to_owned(),
comment[prefix.len()..].to_owned(), Span { lo: span.lo + BytePos(prefix.len() as u32), ..span })];
Span { lo: span.lo + BytePos(prefix.len() as u32), ..span }
)];
} }
} }
if comment.starts_with("/*") { if comment.starts_with("/*") {
return comment[3..comment.len() - 2].lines().map(|line| { return comment[3..comment.len() - 2]
.lines()
.map(|line| {
let offset = line.as_ptr() as usize - comment.as_ptr() as usize; let offset = line.as_ptr() as usize - comment.as_ptr() as usize;
debug_assert_eq!(offset as u32 as usize, offset); debug_assert_eq!(offset as u32 as usize, offset);
( (line.to_owned(), Span { lo: span.lo + BytePos(offset as u32), ..span })
line.to_owned(), })
Span { .collect();
lo: span.lo + BytePos(offset as u32),
..span
}
)
}).collect();
} }
panic!("not a doc-comment: {}", comment); panic!("not a doc-comment: {}", comment);
@ -299,16 +294,17 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)]
match parser.next() { match parser.next() {
Some((new_line, c)) => { Some((new_line, c)) => {
match c { match c {
'#' if new_line => { // dont warn on titles '#' if new_line => {
// dont warn on titles
parser.next_line(); parser.next_line();
} },
'`' => { '`' => {
if try!(check_block!(parser, '`', new_line)) { if try!(check_block!(parser, '`', new_line)) {
continue; continue;
} }
try!(parser.jump_to('`')); // not a code block, just inline code try!(parser.jump_to('`')); // not a code block, just inline code
} },
'~' => { '~' => {
if try!(check_block!(parser, '~', new_line)) { if try!(check_block!(parser, '~', new_line)) {
continue; continue;
@ -317,7 +313,7 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)]
// ~ does not introduce inline code, but two of them introduce // ~ does not introduce inline code, but two of them introduce
// strikethrough. Too bad for the consistency but we don't care about // strikethrough. Too bad for the consistency but we don't care about
// strikethrough. // strikethrough.
} },
'[' => { '[' => {
// Check for a reference definition `[foo]:` at the beginning of a line // Check for a reference definition `[foo]:` at the beginning of a line
let mut link = true; let mut link = true;
@ -335,24 +331,24 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)]
parser.advance_begin(); parser.advance_begin();
parser.link = link; parser.link = link;
} },
']' if parser.link => { ']' if parser.link => {
parser.link = false; parser.link = false;
match parser.peek() { match parser.peek() {
Some('(') => { Some('(') => {
try!(parser.jump_to(')')); try!(parser.jump_to(')'));
} },
Some('[') => { Some('[') => {
try!(parser.jump_to(']')); try!(parser.jump_to(']'));
} },
Some(_) => continue, Some(_) => continue,
None => return Err(()), None => return Err(()),
} }
} },
c if !is_path_char(c) => { c if !is_path_char(c) => {
parser.advance_begin(); parser.advance_begin();
} },
_ => { _ => {
if let Some((_, c)) = parser.find(|&(_, c)| !is_path_char(c)) { if let Some((_, c)) = parser.find(|&(_, c)| !is_path_char(c)) {
parser.put_back(c); parser.put_back(c);
@ -361,10 +357,10 @@ fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)]
let (word, span) = parser.word(); let (word, span) = parser.word();
check_word(cx, valid_idents, word, span); check_word(cx, valid_idents, word, span);
parser.advance_begin(); parser.advance_begin();
} },
} }
} },
None => break, None => break,
} }
} }
@ -386,8 +382,7 @@ fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span
s s
}; };
s.chars().all(char::is_alphanumeric) && s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 &&
s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 &&
s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
} }

View file

@ -78,7 +78,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint {
} }
} }
fn check_cond<'a, 'tcx, 'b>(cx: &'a LateContext<'a, 'tcx>, check: &'b Expr) -> Option<(&'static str, &'b Expr, &'b Expr)> { fn check_cond<'a, 'tcx, 'b>(cx: &'a LateContext<'a, 'tcx>, check: &'b Expr)
-> Option<(&'static str, &'b Expr, &'b Expr)> {
if_let_chain! {[ if_let_chain! {[
let ExprMethodCall(ref name, _, ref params) = check.node, let ExprMethodCall(ref name, _, ref params) = check.node,
params.len() >= 2, params.len() >= 2,

View file

@ -49,7 +49,7 @@ impl EnumGlobUse {
if let ItemUse(ref path, UseKind::Glob) = item.node { if let ItemUse(ref path, UseKind::Glob) = item.node {
// FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;` // FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;`
// extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an `Enum` // extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an `Enum`
//if let Def::Enum(_) = path.def { // if let Def::Enum(_) = path.def {
if path.segments.last().and_then(|seg| seg.name.as_str().chars().next()).map_or(false, char::is_uppercase) { if path.segments.last().and_then(|seg| seg.name.as_str().chars().next()).map_or(false, char::is_uppercase) {
span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants"); span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
} }

View file

@ -78,7 +78,10 @@ pub struct EnumVariantNames {
impl EnumVariantNames { impl EnumVariantNames {
pub fn new(threshold: u64) -> EnumVariantNames { pub fn new(threshold: u64) -> EnumVariantNames {
EnumVariantNames { modules: Vec::new(), threshold: threshold } EnumVariantNames {
modules: Vec::new(),
threshold: threshold,
}
} }
} }
@ -108,8 +111,8 @@ fn partial_rmatch(post: &str, name: &str) -> usize {
// FIXME: #600 // FIXME: #600
#[allow(while_let_on_iterator)] #[allow(while_let_on_iterator)]
fn check_variant(cx: &EarlyContext, threshold: u64, def: &EnumDef, item_name: &str, fn check_variant(cx: &EarlyContext, threshold: u64, def: &EnumDef, item_name: &str, item_name_chars: usize,
item_name_chars: usize, span: Span) { span: Span) {
if (def.variants.len() as u64) < threshold { if (def.variants.len() as u64) < threshold {
return; return;
} }
@ -200,7 +203,10 @@ impl EarlyLintPass for EnumVariantNames {
if !mod_camel.is_empty() { if !mod_camel.is_empty() {
if mod_name == &item_name { if mod_name == &item_name {
if let ItemKind::Mod(..) = item.node { if let ItemKind::Mod(..) = item.node {
span_lint(cx, MODULE_INCEPTION, item.span, "module has the same name as its containing module"); span_lint(cx,
MODULE_INCEPTION,
item.span,
"module has the same name as its containing module");
} }
} }
if item.vis == Visibility::Public { if item.vis == Visibility::Public {

View file

@ -48,19 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
fn is_valid_operator(op: &BinOp) -> bool { fn is_valid_operator(op: &BinOp) -> bool {
match op.node { match op.node {
BiSub | BiSub | BiDiv | BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr | BiBitXor | BiBitAnd | BiBitOr => true,
BiDiv |
BiEq |
BiLt |
BiLe |
BiGt |
BiGe |
BiNe |
BiAnd |
BiOr |
BiBitXor |
BiBitAnd |
BiBitOr => true,
_ => false, _ => false,
} }
} }

View file

@ -46,7 +46,7 @@ fn is_non_trait_box(ty: ty::Ty) -> bool {
} }
} }
struct EscapeDelegate<'a, 'tcx: 'a+'gcx, 'gcx: 'a> { struct EscapeDelegate<'a, 'tcx: 'a + 'gcx, 'gcx: 'a> {
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
set: NodeSet, set: NodeSet,
infcx: &'a InferCtxt<'a, 'gcx, 'gcx>, infcx: &'a InferCtxt<'a, 'gcx, 'gcx>,
@ -61,15 +61,8 @@ impl LintPass for Pass {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn( fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, _: visit::FnKind<'tcx>, decl: &'tcx FnDecl, body: &'tcx Expr,
&mut self, _: Span, id: NodeId) {
cx: &LateContext<'a, 'tcx>,
_: visit::FnKind<'tcx>,
decl: &'tcx FnDecl,
body: &'tcx Expr,
_: Span,
id: NodeId,
) {
let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id); let param_env = ty::ParameterEnvironment::for_item(cx.tcx, id);
let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env); let infcx = cx.tcx.borrowck_fake_infer_ctxt(param_env);
@ -98,7 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
} }
impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'gcx> { impl<'a, 'tcx: 'a + 'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'gcx> {
fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) {
if let Categorization::Local(lid) = cmt.cat { if let Categorization::Local(lid) = cmt.cat {
if self.set.contains(&lid) { if self.set.contains(&lid) {
@ -157,7 +150,8 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g
if let Categorization::Local(lid) = cmt.cat { if let Categorization::Local(lid) = cmt.cat {
if self.set.contains(&lid) { if self.set.contains(&lid) {
if let Some(&Adjust::DerefRef { autoderefs, .. }) = self.tcx if let Some(&Adjust::DerefRef { autoderefs, .. }) =
self.tcx
.tables .tables
.borrow() .borrow()
.adjustments .adjustments
@ -173,7 +167,8 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g
} }
} else if LoanCause::AddrOf == loan_cause { } else if LoanCause::AddrOf == loan_cause {
// &x // &x
if let Some(&Adjust::DerefRef { autoderefs, .. }) = self.tcx if let Some(&Adjust::DerefRef { autoderefs, .. }) =
self.tcx
.tables .tables
.borrow() .borrow()
.adjustments .adjustments
@ -198,7 +193,7 @@ impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> Delegate<'tcx> for EscapeDelegate<'a, 'tcx, 'g
fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {} fn mutate(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) {}
} }
impl<'a, 'tcx: 'a+'gcx, 'gcx: 'a> EscapeDelegate<'a, 'tcx, 'gcx> { impl<'a, 'tcx: 'a + 'gcx, 'gcx: 'a> EscapeDelegate<'a, 'tcx, 'gcx> {
fn is_large_box(&self, ty: ty::Ty<'gcx>) -> bool { fn is_large_box(&self, ty: ty::Ty<'gcx>) -> bool {
// Large types need to be boxed to avoid stack // Large types need to be boxed to avoid stack
// overflows. // overflows.

View file

@ -41,7 +41,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
for arg in args { for arg in args {
check_closure(cx, arg) check_closure(cx, arg)
} }
} },
_ => (), _ => (),
} }
} }
@ -65,11 +65,10 @@ fn check_closure(cx: &LateContext, expr: &Expr) {
// Is it an unsafe function? They don't implement the closure traits // Is it an unsafe function? They don't implement the closure traits
ty::TyFnDef(_, _, fn_ty) | ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => { ty::TyFnPtr(fn_ty) => {
if fn_ty.unsafety == Unsafety::Unsafe || if fn_ty.unsafety == Unsafety::Unsafe || fn_ty.sig.skip_binder().output().sty == ty::TyNever {
fn_ty.sig.skip_binder().output().sty == ty::TyNever {
return; return;
} }
} },
_ => (), _ => (),
} }
for (a1, a2) in decl.inputs.iter().zip(args) { for (a1, a2) in decl.inputs.iter().zip(args) {

View file

@ -60,7 +60,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// Find a write to a local variable. // Find a write to a local variable.
match expr.node { match expr.node {
ExprAssign(ref lhs, _) | ExprAssignOp(_, ref lhs, _) => { ExprAssign(ref lhs, _) |
ExprAssignOp(_, ref lhs, _) => {
if let ExprPath(ref qpath) = lhs.node { if let ExprPath(ref qpath) = lhs.node {
if let QPath::Resolved(_, ref path) = *qpath { if let QPath::Resolved(_, ref path) = *qpath {
if path.segments.len() == 1 { if path.segments.len() == 1 {
@ -75,13 +76,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
} }
} }
} }
} },
_ => {} _ => {},
} }
} }
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
match stmt.node { match stmt.node {
StmtExpr(ref e, _) | StmtSemi(ref e, _) => DivergenceVisitor { cx: cx }.maybe_walk_expr(e), StmtExpr(ref e, _) |
StmtSemi(ref e, _) => DivergenceVisitor { cx: cx }.maybe_walk_expr(e),
StmtDecl(ref d, _) => { StmtDecl(ref d, _) => {
if let DeclLocal(ref local) = d.node { if let DeclLocal(ref local) = d.node {
if let Local { init: Some(ref e), .. } = **local { if let Local { init: Some(ref e), .. } = **local {
@ -110,32 +112,29 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
// make sure top level arm expressions aren't linted // make sure top level arm expressions aren't linted
self.maybe_walk_expr(&*arm.body); self.maybe_walk_expr(&*arm.body);
} }
} },
_ => walk_expr(self, e), _ => walk_expr(self, e),
} }
} }
fn report_diverging_sub_expr(&mut self, e: &Expr) { fn report_diverging_sub_expr(&mut self, e: &Expr) {
span_lint( span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
self.cx,
DIVERGING_SUB_EXPRESSION,
e.span,
"sub-expression diverges",
);
} }
} }
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'tcx Expr) { fn visit_expr(&mut self, e: &'tcx Expr) {
match e.node { match e.node {
ExprAgain(_) | ExprAgain(_) | ExprBreak(_, _) | ExprRet(_) => self.report_diverging_sub_expr(e),
ExprBreak(_, _) | ExprCall(ref func, _) => {
ExprRet(_) => self.report_diverging_sub_expr(e), match self.cx.tcx.tables().expr_ty(func).sty {
ExprCall(ref func, _) => match self.cx.tcx.tables().expr_ty(func).sty {
ty::TyFnDef(_, _, fn_ty) | ty::TyFnDef(_, _, fn_ty) |
ty::TyFnPtr(fn_ty) => if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&fn_ty.sig).output().sty { ty::TyFnPtr(fn_ty) => {
if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&fn_ty.sig).output().sty {
self.report_diverging_sub_expr(e); self.report_diverging_sub_expr(e);
}
}, },
_ => {}, _ => {},
}
}, },
ExprMethodCall(..) => { ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(e.id); let method_call = ty::MethodCall::expr(e.id);
@ -195,7 +194,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor) {
// We reached the top of the function, stop. // We reached the top of the function, stop.
break; break;
}, },
_ => { StopEarly::KeepGoing } _ => StopEarly::KeepGoing,
}; };
match stop_early { match stop_early {
StopEarly::Stop => break, StopEarly::Stop => break,
@ -214,7 +213,7 @@ enum StopEarly {
Stop, Stop,
} }
fn check_expr<'a, 'tcx>(vis: & mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly { fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly {
if expr.id == vis.last_expr.id { if expr.id == vis.last_expr.id {
return StopEarly::KeepGoing; return StopEarly::KeepGoing;
} }
@ -229,7 +228,7 @@ fn check_expr<'a, 'tcx>(vis: & mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> S
ExprRepeat(_, _) | ExprRepeat(_, _) |
ExprStruct(_, _, _) => { ExprStruct(_, _, _) => {
walk_expr(vis, expr); walk_expr(vis, expr);
} },
ExprBinary(op, _, _) | ExprBinary(op, _, _) |
ExprAssignOp(op, _, _) => { ExprAssignOp(op, _, _) => {
if op.node == BiAnd || op.node == BiOr { if op.node == BiAnd || op.node == BiOr {
@ -238,7 +237,7 @@ fn check_expr<'a, 'tcx>(vis: & mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> S
} else { } else {
walk_expr(vis, expr); walk_expr(vis, expr);
} }
} },
ExprClosure(_, _, _, _) => { ExprClosure(_, _, _, _) => {
// Either // Either
// //
@ -252,10 +251,10 @@ fn check_expr<'a, 'tcx>(vis: & mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> S
// //
// This is also the only place we need to stop early (grrr). // This is also the only place we need to stop early (grrr).
return StopEarly::Stop; return StopEarly::Stop;
} },
// All other expressions either have only one child or strictly // All other expressions either have only one child or strictly
// sequence the evaluation order of their sub-expressions. // sequence the evaluation order of their sub-expressions.
_ => {} _ => {},
} }
vis.last_expr = expr; vis.last_expr = expr;
@ -276,7 +275,7 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> St
}; };
local.and_then(|local| local.init.as_ref()) local.and_then(|local| local.init.as_ref())
.map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)) .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr))
} },
} }
} }

View file

@ -55,7 +55,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
], { ], {
span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
}} }}
} },
// `format!("foo")` expansion contains `match () { () => [], }` // `format!("foo")` expansion contains `match () { () => [], }`
ExprMatch(ref matchee, _, _) => { ExprMatch(ref matchee, _, _) => {
if let ExprTup(ref tup) = matchee.node { if let ExprTup(ref tup) = matchee.node {
@ -63,7 +63,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
} }
} }
} },
_ => (), _ => (),
} }
} }
@ -72,8 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
/// Returns the slice of format string parts in an `Arguments::new_v1` call. /// Returns the slice of format string parts in an `Arguments::new_v1` call.
/// Public because it's shared with a lint in print.rs. /// Public because it's shared with a lint in print.rs.
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) -> Option<Vec<InternedString>> {
-> Option<Vec<InternedString>> {
if_let_chain! {[ if_let_chain! {[
let ExprBlock(ref block) = expr.node, let ExprBlock(ref block) = expr.node,
block.stmts.len() == 1, block.stmts.len() == 1,

View file

@ -62,7 +62,7 @@ impl EarlyLintPass for Formatting {
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => { (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
check_consecutive_ifs(cx, first, second); check_consecutive_ifs(cx, first, second);
} },
_ => (), _ => (),
} }
} }

View file

@ -69,15 +69,8 @@ impl LintPass for Functions {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
fn check_fn( fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, kind: intravisit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
&mut self, expr: &'tcx hir::Expr, span: Span, nodeid: ast::NodeId) {
cx: &LateContext<'a, 'tcx>,
kind: intravisit::FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
expr: &'tcx hir::Expr,
span: Span,
nodeid: ast::NodeId,
) {
use rustc::hir::map::Node::*; use rustc::hir::map::Node::*;
let is_impl = if let Some(NodeItem(item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) { let is_impl = if let Some(NodeItem(item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
@ -131,14 +124,8 @@ impl<'a, 'tcx> Functions {
} }
} }
fn check_raw_ptr( fn check_raw_ptr(&self, cx: &LateContext<'a, 'tcx>, unsafety: hir::Unsafety, decl: &'tcx hir::FnDecl,
&self, expr: &'tcx hir::Expr, nodeid: ast::NodeId) {
cx: &LateContext<'a, 'tcx>,
unsafety: hir::Unsafety,
decl: &'tcx hir::FnDecl,
expr: &'tcx hir::Expr,
nodeid: ast::NodeId,
) {
if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) { if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) {
let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::<HashSet<_>>(); let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::<HashSet<_>>();
@ -178,7 +165,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
self.check_arg(arg); self.check_arg(arg);
} }
} }
} },
hir::ExprMethodCall(_, _, ref args) => { hir::ExprMethodCall(_, _, ref args) => {
let method_call = ty::MethodCall::expr(expr.id); let method_call = ty::MethodCall::expr(expr.id);
let base_type = self.cx.tcx.tables.borrow().method_map[&method_call].ty; let base_type = self.cx.tcx.tables.borrow().method_map[&method_call].ty;
@ -188,7 +175,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
self.check_arg(arg); self.check_arg(arg);
} }
} }
} },
hir::ExprUnary(hir::UnDeref, ref ptr) => self.check_arg(ptr), hir::ExprUnary(hir::UnDeref, ref ptr) => self.check_arg(ptr),
_ => (), _ => (),
} }

View file

@ -41,17 +41,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp {
BiAdd | BiBitOr | BiBitXor => { BiAdd | BiBitOr | BiBitXor => {
check(cx, left, 0, e.span, right.span); check(cx, left, 0, e.span, right.span);
check(cx, right, 0, e.span, left.span); check(cx, right, 0, e.span, left.span);
} },
BiShl | BiShr | BiSub => check(cx, right, 0, e.span, left.span), BiShl | BiShr | BiSub => check(cx, right, 0, e.span, left.span),
BiMul => { BiMul => {
check(cx, left, 1, e.span, right.span); check(cx, left, 1, e.span, right.span);
check(cx, right, 1, e.span, left.span); check(cx, right, 1, e.span, left.span);
} },
BiDiv => check(cx, right, 1, e.span, left.span), BiDiv => check(cx, right, 1, e.span, left.span),
BiBitAnd => { BiBitAnd => {
check(cx, left, -1, e.span, right.span); check(cx, left, -1, e.span, right.span);
check(cx, right, -1, e.span, left.span); check(cx, right, -1, e.span, left.span);
} },
_ => (), _ => (),
} }
} }

View file

@ -45,13 +45,12 @@ impl LintPass for Pass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprMatch(ref op, ref arms, MatchSource::IfLetDesugar{..}) = expr.node { if let ExprMatch(ref op, ref arms, MatchSource::IfLetDesugar { .. }) = expr.node {
if arms[0].pats.len() == 1 { if arms[0].pats.len() == 1 {
let good_method = match arms[0].pats[0].node { let good_method = match arms[0].pats[0].node {
PatKind::TupleStruct(ref path, ref pats, _) if pats.len() == 1 && pats[0].node == PatKind::Wild => { PatKind::TupleStruct(ref path, ref pats, _) if pats.len() == 1 && pats[0].node == PatKind::Wild => {
if match_path(path, &paths::RESULT_OK) { if match_path(path, &paths::RESULT_OK) {
"is_ok()" "is_ok()"
} else if match_path(path, &paths::RESULT_ERR) { } else if match_path(path, &paths::RESULT_ERR) {
@ -59,15 +58,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} else if match_path(path, &paths::OPTION_SOME) { } else if match_path(path, &paths::OPTION_SOME) {
"is_some()" "is_some()"
} else { } else {
return return;
}
} }
},
PatKind::Path(ref path) if match_path(path, &paths::OPTION_NONE) => { PatKind::Path(ref path) if match_path(path, &paths::OPTION_NONE) => "is_none()",
"is_none()"
}
_ => return _ => return,
}; };
span_lint_and_then(cx, span_lint_and_then(cx,
@ -80,9 +77,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
hi: op.span.hi, hi: op.span.hi,
expn_id: expr.span.expn_id, expn_id: expr.span.expn_id,
}; };
db.span_suggestion(span, db.span_suggestion(span, "try this", format!("if {}.{}", snippet(cx, op.span, "_"), good_method));
"try this",
format!("if {}.{}", snippet(cx, op.span, "_"), good_method));
}); });
} }

View file

@ -55,14 +55,14 @@ impl EarlyLintPass for IfNotElse {
item.span, item.span,
"Unnecessary boolean `not` operation", "Unnecessary boolean `not` operation",
"remove the `!` and swap the blocks of the if/else"); "remove the `!` and swap the blocks of the if/else");
} },
ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => { ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
span_help_and_lint(cx, span_help_and_lint(cx,
IF_NOT_ELSE, IF_NOT_ELSE,
item.span, item.span,
"Unnecessary `!=` operation", "Unnecessary `!=` operation",
"change to `==` and swap the blocks of the if/else"); "change to `==` and swap the blocks of the if/else");
} },
_ => (), _ => (),
} }
} }

View file

@ -47,7 +47,8 @@ impl EarlyLintPass for ItemsAfterStatements {
} }
// skip initial items // skip initial items
let stmts = item.stmts.iter() let stmts = item.stmts
.iter()
.map(|stmt| &stmt.node) .map(|stmt| &stmt.node)
.skip_while(|s| matches!(**s, StmtKind::Item(..))); .skip_while(|s| matches!(**s, StmtKind::Item(..)));

View file

@ -107,8 +107,7 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) {
span_lint(cx, span_lint(cx,
LEN_WITHOUT_IS_EMPTY, LEN_WITHOUT_IS_EMPTY,
i.span, i.span,
&format!("trait `{}` has a `len` method but no `is_empty` method", &format!("trait `{}` has a `len` method but no `is_empty` method", item.name));
item.name));
} }
} }
} }
@ -118,7 +117,8 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) {
fn is_named_self(cx: &LateContext, item: &ImplItemRef, name: &str) -> bool { fn is_named_self(cx: &LateContext, item: &ImplItemRef, name: &str) -> bool {
&*item.name.as_str() == name && &*item.name.as_str() == name &&
if let AssociatedItemKind::Method { has_self } = item.kind { if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && { has_self &&
{
let did = cx.tcx.map.local_def_id(item.id.node_id); let did = cx.tcx.map.local_def_id(item.id.node_id);
let impl_ty = cx.tcx.item_type(did); let impl_ty = cx.tcx.item_type(did);
impl_ty.fn_args().skip_binder().len() == 1 impl_ty.fn_args().skip_binder().len() == 1
@ -146,9 +146,7 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) {
span_lint(cx, span_lint(cx,
LEN_WITHOUT_IS_EMPTY, LEN_WITHOUT_IS_EMPTY,
i.span, i.span,
&format!("item `{}` has a public `len` method but {} `is_empty` method", &format!("item `{}` has a public `len` method but {} `is_empty` method", ty, is_empty));
ty,
is_empty));
} }
} }
} }
@ -164,7 +162,7 @@ fn check_cmp(cx: &LateContext, span: Span, left: &Expr, right: &Expr, op: &str)
(&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) | (&ExprLit(ref lit), &ExprMethodCall(ref method, _, ref args)) |
(&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => { (&ExprMethodCall(ref method, _, ref args), &ExprLit(ref lit)) => {
check_len_zero(cx, span, &method.node, args, lit, op) check_len_zero(cx, span, &method.node, args, lit, op)
} },
_ => (), _ => (),
} }
} }
@ -199,11 +197,9 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
/// Check the inherent impl's items for an `is_empty(self)` method. /// Check the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext, id: DefId) -> bool { fn has_is_empty_impl(cx: &LateContext, id: DefId) -> bool {
cx.tcx.inherent_impls.borrow().get(&id).map_or(false, |impls| impls.iter().any(|imp| { cx.tcx.inherent_impls.borrow().get(&id).map_or(false, |impls| {
cx.tcx.associated_items(*imp).any(|item| { impls.iter().any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
is_is_empty(cx, &item)
}) })
}))
} }
let ty = &walk_ptrs_ty(cx.tcx.tables().expr_ty(expr)); let ty = &walk_ptrs_ty(cx.tcx.tables().expr_ty(expr));
@ -212,7 +208,7 @@ fn has_is_empty(cx: &LateContext, expr: &Expr) -> bool {
cx.tcx cx.tcx
.associated_items(ty.ty_to_def_id().expect("trait impl not found")) .associated_items(ty.ty_to_def_id().expect("trait impl not found"))
.any(|item| is_is_empty(cx, &item)) .any(|item| is_is_empty(cx, &item))
} },
ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, id)), ty::TyProjection(_) => ty.ty_to_def_id().map_or(false, |id| has_is_empty_impl(cx, id)),
ty::TyAdt(id, _) => has_is_empty_impl(cx, id.did), ty::TyAdt(id, _) => has_is_empty_impl(cx, id.did),
ty::TyArray(..) | ty::TyStr => true, ty::TyArray(..) | ty::TyStr => true,

View file

@ -149,11 +149,8 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> {
} }
} }
fn check_assign<'a, 'tcx>( fn check_assign<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: hir::def_id::DefId, block: &'tcx hir::Block)
cx: &LateContext<'a, 'tcx>, -> Option<&'tcx hir::Expr> {
decl: hir::def_id::DefId,
block: &'tcx hir::Block,
) -> Option<&'tcx hir::Expr> {
if_let_chain! {[ if_let_chain! {[
block.expr.is_none(), block.expr.is_none(),
let Some(expr) = block.stmts.iter().last(), let Some(expr) = block.stmts.iter().last(),
@ -182,11 +179,7 @@ fn check_assign<'a, 'tcx>(
None None
} }
fn used_in_expr<'a, 'tcx: 'a>( fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: hir::def_id::DefId, expr: &'tcx hir::Expr) -> bool {
cx: &LateContext<'a, 'tcx>,
id: hir::def_id::DefId,
expr: &'tcx hir::Expr,
) -> bool {
let mut v = UsedVisitor { let mut v = UsedVisitor {
cx: cx, cx: cx,
id: id, id: id,

View file

@ -98,12 +98,7 @@ fn bound_lifetimes(bound: &TyParamBound) -> HirVec<&Lifetime> {
} }
} }
fn check_fn_inner<'a, 'tcx>( fn check_fn_inner<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, generics: &'tcx Generics, span: Span) {
cx: &LateContext<'a, 'tcx>,
decl: &'tcx FnDecl,
generics: &'tcx Generics,
span: Span,
) {
if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) { if in_external_macro(cx, span) || has_where_lifetimes(cx, &generics.where_clause) {
return; return;
} }
@ -121,16 +116,10 @@ fn check_fn_inner<'a, 'tcx>(
report_extra_lifetimes(cx, decl, generics); report_extra_lifetimes(cx, decl, generics);
} }
fn could_use_elision< fn could_use_elision<'a, 'tcx: 'a, T: Iterator<Item = &'tcx Lifetime>>(cx: &LateContext<'a, 'tcx>,
'a,
'tcx: 'a,
T: Iterator<Item = &'tcx Lifetime>
>(
cx: &LateContext<'a, 'tcx>,
func: &'tcx FnDecl, func: &'tcx FnDecl,
named_lts: &'tcx [LifetimeDef], named_lts: &'tcx [LifetimeDef], bounds_lts: T)
bounds_lts: T, -> bool {
) -> bool {
// There are two scenarios where elision works: // There are two scenarios where elision works:
// * no output references, all input references have different LT // * no output references, all input references have different LT
// * output references, exactly one input reference with same LT // * output references, exactly one input reference with same LT
@ -262,13 +251,13 @@ impl<'v, 't> RefVisitor<'v, 't> {
for _ in generics.regions.as_slice() { for _ in generics.regions.as_slice() {
self.record(&None); self.record(&None);
} }
} },
Def::Trait(def_id) => { Def::Trait(def_id) => {
let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id]; let trait_def = self.cx.tcx.trait_defs.borrow()[&def_id];
for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions { for _ in &self.cx.tcx.item_generics(trait_def.def_id).regions {
self.record(&None); self.record(&None);
} }
} },
_ => (), _ => (),
} }
} }
@ -286,10 +275,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
match ty.node { match ty.node {
TyRptr(None, _) => { TyRptr(None, _) => {
self.record(&None); self.record(&None);
} },
TyPath(ref path) => { TyPath(ref path) => {
self.collect_anonymous_lifetimes(path, ty); self.collect_anonymous_lifetimes(path, ty);
} },
_ => (), _ => (),
} }
walk_ty(self, ty); walk_ty(self, ty);
@ -325,14 +314,14 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
return true; return true;
} }
} }
} },
WherePredicate::EqPredicate(ref pred) => { WherePredicate::EqPredicate(ref pred) => {
let mut visitor = RefVisitor::new(cx); let mut visitor = RefVisitor::new(cx);
walk_ty(&mut visitor, &pred.ty); walk_ty(&mut visitor, &pred.ty);
if !visitor.lts.is_empty() { if !visitor.lts.is_empty() {
return true; return true;
} }
} },
} }
} }
false false

View file

@ -14,9 +14,9 @@ use std::collections::HashMap;
use syntax::ast; use syntax::ast;
use utils::sugg; use utils::sugg;
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro,
in_external_macro, is_refutable, span_help_and_lint, is_integer_literal, is_refutable, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher,
get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty, last_path_segment}; walk_ptrs_ty, last_path_segment};
use utils::paths; use utils::paths;
/// **What it does:** Checks for looping over the range of `0..len` of some /// **What it does:** Checks for looping over the range of `0..len` of some
@ -334,8 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
match *source { match *source {
MatchSource::Normal | MatchSource::Normal |
MatchSource::IfLetDesugar { .. } => { MatchSource::IfLetDesugar { .. } => {
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() &&
is_break_expr(&arms[1].body) { is_break_expr(&arms[1].body) {
if in_external_macro(cx, expr.span) { if in_external_macro(cx, expr.span) {
@ -358,7 +357,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
db.span_suggestion(expr.span, "try", sug); db.span_suggestion(expr.span, "try", sug);
}); });
} }
} },
_ => (), _ => (),
} }
} }
@ -370,10 +369,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
&ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) { &ExprMethodCall(method_name, _, ref method_args)) = (pat, &match_expr.node) {
let iter_expr = &method_args[0]; let iter_expr = &method_args[0];
let lhs_constructor = last_path_segment(qpath); let lhs_constructor = last_path_segment(qpath);
if &*method_name.node.as_str() == "next" && if &*method_name.node.as_str() == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) &&
match_trait_method(cx, match_expr, &paths::ITERATOR) && &*lhs_constructor.name.as_str() == "Some" && !is_refutable(cx, &pat_args[0]) &&
&*lhs_constructor.name.as_str() == "Some" &&
!is_refutable(cx, &pat_args[0]) &&
!is_iterator_used_after_while_let(cx, iter_expr) { !is_iterator_used_after_while_let(cx, iter_expr) {
let iterator = snippet(cx, method_args[0].span, "_"); let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_"); let loop_var = snippet(cx, pat_args[0].span, "_");
@ -407,13 +404,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
} }
fn check_for_loop<'a, 'tcx>( fn check_for_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, arg: &'tcx Expr, body: &'tcx Expr,
cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
pat: &'tcx Pat,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
check_for_loop_range(cx, pat, arg, body, expr); check_for_loop_range(cx, pat, arg, body, expr);
check_for_loop_reverse_range(cx, arg, expr); check_for_loop_reverse_range(cx, arg, expr);
check_for_loop_arg(cx, pat, arg, expr); check_for_loop_arg(cx, pat, arg, expr);
@ -423,13 +415,8 @@ fn check_for_loop<'a, 'tcx>(
/// Check for looping over a range and then indexing a sequence with it. /// Check for looping over a range and then indexing a sequence with it.
/// The iteratee must be a range literal. /// The iteratee must be a range literal.
fn check_for_loop_range<'a, 'tcx>( fn check_for_loop_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, arg: &'tcx Expr, body: &'tcx Expr,
cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
pat: &'tcx Pat,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::range(arg) { if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::range(arg) {
// the var must be a single name // the var must be a single name
if let PatKind::Binding(_, def_id, ref ident, _) = pat.node { if let PatKind::Binding(_, def_id, ref ident, _) = pat.node {
@ -472,10 +459,8 @@ fn check_for_loop_range<'a, 'tcx>(
ast::RangeLimits::Closed => { ast::RangeLimits::Closed => {
let end = sugg::Sugg::hir(cx, end, "<count>"); let end = sugg::Sugg::hir(cx, end, "<count>");
format!(".take({})", end + sugg::ONE) format!(".take({})", end + sugg::ONE)
} },
ast::RangeLimits::HalfOpen => { ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, end.span, "..")),
format!(".take({})", snippet(cx, end.span, ".."))
}
} }
} }
} else { } else {
@ -544,7 +529,7 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
let (sup, eq) = match (start_idx, end_idx) { let (sup, eq) = match (start_idx, end_idx) {
(ConstVal::Integral(start_idx), ConstVal::Integral(end_idx)) => { (ConstVal::Integral(start_idx), ConstVal::Integral(end_idx)) => {
(start_idx > end_idx, start_idx == end_idx) (start_idx > end_idx, start_idx == end_idx)
} },
_ => (false, false), _ => (false, false),
}; };
@ -563,9 +548,8 @@ fn check_for_loop_reverse_range(cx: &LateContext, arg: &Expr, expr: &Expr) {
"this range is empty so this for loop will never run", "this range is empty so this for loop will never run",
|db| { |db| {
db.span_suggestion(arg.span, db.span_suggestion(arg.span,
"consider using the following if \ "consider using the following if you are attempting to iterate over this \
you are attempting to iterate \ range in reverse",
over this range in reverse",
format!("({end}{dots}{start}).rev()", format!("({end}{dots}{start}).rev()",
end=end_snippet, end=end_snippet,
dots=dots, dots=dots,
@ -658,12 +642,8 @@ fn check_arg_type(cx: &LateContext, pat: &Pat, arg: &Expr) {
} }
} }
fn check_for_loop_explicit_counter<'a, 'tcx>( fn check_for_loop_explicit_counter<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr, body: &'tcx Expr,
cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
// Look for variables that are incremented once per loop iteration. // Look for variables that are incremented once per loop iteration.
let mut visitor = IncrementVisitor { let mut visitor = IncrementVisitor {
cx: cx, cx: cx,
@ -708,13 +688,8 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
} }
/// Check for the `FOR_KV_MAP` lint. /// Check for the `FOR_KV_MAP` lint.
fn check_for_loop_over_map_kv<'a, 'tcx>( fn check_for_loop_over_map_kv<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, arg: &'tcx Expr,
cx: &LateContext<'a, 'tcx>, body: &'tcx Expr, expr: &'tcx Expr) {
pat: &'tcx Pat,
arg: &'tcx Expr,
body: &'tcx Expr,
expr: &'tcx Expr,
) {
let pat_span = pat.span; let pat_span = pat.span;
if let PatKind::Tuple(ref pat, _) = pat.node { if let PatKind::Tuple(ref pat, _) = pat.node {
@ -739,10 +714,10 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
&format!("you seem to want to iterate on a map's {}s", kind), &format!("you seem to want to iterate on a map's {}s", kind),
|db| { |db| {
let map = sugg::Sugg::hir(cx, arg, "map"); let map = sugg::Sugg::hir(cx, arg, "map");
multispan_sugg(db, "use the corresponding method".into(), &[ multispan_sugg(db,
(pat_span, &snippet(cx, new_pat_span, kind)), "use the corresponding method".into(),
(arg_span, &format!("{}.{}s()", map.maybe_par(), kind)), &[(pat_span, &snippet(cx, new_pat_span, kind)),
]); (arg_span, &format!("{}.{}s()", map.maybe_par(), kind))]);
}); });
} }
} }
@ -751,11 +726,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
} }
/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`.
fn pat_is_wild<'a, 'tcx: 'a>( fn pat_is_wild<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, pat: &'tcx PatKind, body: &'tcx Expr) -> bool {
cx: &LateContext<'a, 'tcx>,
pat: &'tcx PatKind,
body: &'tcx Expr,
) -> bool {
match *pat { match *pat {
PatKind::Wild => true, PatKind::Wild => true,
PatKind::Binding(_, _, ident, None) if ident.node.as_str().starts_with('_') => { PatKind::Binding(_, _, ident, None) if ident.node.as_str().starts_with('_') => {
@ -766,7 +737,7 @@ fn pat_is_wild<'a, 'tcx: 'a>(
}; };
walk_expr(&mut visitor, body); walk_expr(&mut visitor, body);
!visitor.used !visitor.used
} },
_ => false, _ => false,
} }
} }
@ -938,10 +909,11 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
Some(ref expr) if block.stmts.is_empty() => Some(expr), Some(ref expr) if block.stmts.is_empty() => Some(expr),
None if !block.stmts.is_empty() => { None if !block.stmts.is_empty() => {
match block.stmts[0].node { match block.stmts[0].node {
StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => Some(expr), StmtExpr(ref expr, _) |
StmtSemi(ref expr, _) => Some(expr),
StmtDecl(..) => None, StmtDecl(..) => None,
} }
} },
_ => None, _ => None,
} }
} }
@ -955,7 +927,7 @@ fn is_break_expr(expr: &Expr) -> bool {
Some(subexpr) => is_break_expr(subexpr), Some(subexpr) => is_break_expr(subexpr),
None => false, None => false,
} }
} },
_ => false, _ => false,
} }
} }
@ -1004,7 +976,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
*state = VarState::DontWarn; *state = VarState::DontWarn;
} }
} }
} },
ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn, ExprAssign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn,
ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn, ExprAddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn,
_ => (), _ => (),
@ -1081,14 +1053,14 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
match parent.node { match parent.node {
ExprAssignOp(_, ref lhs, _) if lhs.id == expr.id => { ExprAssignOp(_, ref lhs, _) if lhs.id == expr.id => {
self.state = VarState::DontWarn; self.state = VarState::DontWarn;
} },
ExprAssign(ref lhs, ref rhs) if lhs.id == expr.id => { ExprAssign(ref lhs, ref rhs) if lhs.id == expr.id => {
self.state = if is_integer_literal(rhs, 0) && self.depth == 0 { self.state = if is_integer_literal(rhs, 0) && self.depth == 0 {
VarState::Warn VarState::Warn
} else { } else {
VarState::DontWarn VarState::DontWarn
} }
} },
ExprAddrOf(mutability, _) if mutability == MutMutable => self.state = VarState::DontWarn, ExprAddrOf(mutability, _) if mutability == MutMutable => self.state = VarState::DontWarn,
_ => (), _ => (),
} }

View file

@ -63,7 +63,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
} }
}} }}
} },
ExprPath(ref path) => { ExprPath(ref path) => {
if match_path(path, &paths::CLONE) { if match_path(path, &paths::CLONE) {
let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_"); let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_");
@ -75,7 +75,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
type_name), type_name),
&format!("try\n{}.cloned()", snippet(cx, args[0].span, ".."))); &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")));
} }
} },
_ => (), _ => (),
} }
} }
@ -91,7 +91,7 @@ fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool {
parameters: PathParameters::none(), parameters: PathParameters::none(),
}]; }];
!path.global && path.segments[..] == arg_segment !path.global && path.segments[..] == arg_segment
} },
_ => false, _ => false,
} }
} }

View file

@ -125,7 +125,11 @@ pub struct MatchPass;
impl LintPass for MatchPass { impl LintPass for MatchPass {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL, SINGLE_MATCH_ELSE, MATCH_OVERLAPPING_ARM) lint_array!(SINGLE_MATCH,
MATCH_REF_PATS,
MATCH_BOOL,
SINGLE_MATCH_ELSE,
MATCH_OVERLAPPING_ARM)
} }
} }
@ -209,7 +213,7 @@ fn check_single_match_opt_like(cx: &LateContext, ex: &Expr, arms: &[Arm], expr:
return; return;
} }
path.to_string() path.to_string()
} },
PatKind::Binding(BindByValue(MutImmutable), _, ident, None) => ident.node.to_string(), PatKind::Binding(BindByValue(MutImmutable), _, ident, None) => ident.node.to_string(),
PatKind::Path(ref path) => path.to_string(), PatKind::Path(ref path) => path.to_string(),
_ => return, _ => return,
@ -272,16 +276,14 @@ fn check_match_bool(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) {
snippet(cx, ex.span, "b"), snippet(cx, ex.span, "b"),
expr_block(cx, true_expr, None, ".."), expr_block(cx, true_expr, None, ".."),
expr_block(cx, false_expr, None, ".."))) expr_block(cx, false_expr, None, "..")))
} },
(false, true) => { (false, true) => {
Some(format!("if {} {}", snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, ".."))) Some(format!("if {} {}", snippet(cx, ex.span, "b"), expr_block(cx, true_expr, None, "..")))
} },
(true, false) => { (true, false) => {
let test = Sugg::hir(cx, ex, ".."); let test = Sugg::hir(cx, ex, "..");
Some(format!("if {} {}", Some(format!("if {} {}", !test, expr_block(cx, false_expr, None, "..")))
!test, },
expr_block(cx, false_expr, None, "..")))
}
(true, true) => None, (true, true) => None,
}; };
@ -349,7 +351,8 @@ fn all_ranges(cx: &LateContext, arms: &[Arm]) -> Vec<SpannedRange<ConstVal>> {
pats.iter() pats.iter()
} else { } else {
[].iter() [].iter()
}.filter_map(|pat| { }
.filter_map(|pat| {
if_let_chain! {[ if_let_chain! {[
let PatKind::Range(ref lhs, ref rhs) = pat.node, let PatKind::Range(ref lhs, ref rhs) = pat.node,
let Ok(lhs) = eval_const_expr_partial(cx.tcx, lhs, ExprTypeChecked, None), let Ok(lhs) = eval_const_expr_partial(cx.tcx, lhs, ExprTypeChecked, None),
@ -481,7 +484,7 @@ pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &
if ra.node != rb.node { if ra.node != rb.node {
return Some((ra, rb)); return Some((ra, rb));
} }
} },
(&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (), (&Kind::End(a, _), &Kind::Start(b, _)) if a != b => (),
_ => return Some((a.range(), b.range())), _ => return Some((a.range(), b.range())),
} }

View file

@ -9,10 +9,10 @@ use rustc_const_eval::eval_const_expr_partial;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use syntax::codemap::Span; use syntax::codemap::Span;
use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path, use utils::{get_trait_def_id, implements_trait, in_external_macro, in_macro, is_copy, match_path, match_trait_method,
match_trait_method, match_type, method_chain_args, return_ty, same_tys, snippet, match_type, method_chain_args, return_ty, same_tys, snippet, span_lint, span_lint_and_then,
span_lint, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, last_path_segment, single_segment_path,
last_path_segment, single_segment_path, match_def_path}; match_def_path};
use utils::paths; use utils::paths;
use utils::sugg; use utils::sugg;
@ -616,15 +616,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
lint_single_char_pattern(cx, expr, &args[pos]); lint_single_char_pattern(cx, expr, &args[pos]);
} }
} }
} },
_ => (), _ => (),
} }
} },
hir::ExprBinary(op, ref lhs, ref rhs) if op.node == hir::BiEq || op.node == hir::BiNe => { hir::ExprBinary(op, ref lhs, ref rhs) if op.node == hir::BiEq || op.node == hir::BiNe => {
if !lint_chars_next(cx, expr, lhs, rhs, op.node == hir::BiEq) { if !lint_chars_next(cx, expr, lhs, rhs, op.node == hir::BiEq) {
lint_chars_next(cx, expr, rhs, lhs, op.node == hir::BiEq); lint_chars_next(cx, expr, rhs, lhs, op.node == hir::BiEq);
} }
} },
_ => (), _ => (),
} }
} }
@ -708,7 +708,8 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
if ["default", "new"].contains(&path) { if ["default", "new"].contains(&path) {
let arg_ty = cx.tcx.tables().expr_ty(arg); let arg_ty = cx.tcx.tables().expr_ty(arg);
let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) { let default_trait_id = if let Some(default_trait_id) =
get_trait_def_id(cx, &paths::DEFAULT_TRAIT) {
default_trait_id default_trait_id
} else { } else {
return false; return false;
@ -720,8 +721,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
span, span,
&format!("use of `{}` followed by a call to `{}`", name, path), &format!("use of `{}` followed by a call to `{}`", name, path),
|db| { |db| {
db.span_suggestion(span, "try this", db.span_suggestion(span,
format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_"))); "try this",
format!("{}.unwrap_or_default()",
snippet(cx, self_expr.span, "_")));
}); });
return true; return true;
} }
@ -733,8 +736,8 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
} }
/// Check for `*or(foo())`. /// Check for `*or(foo())`.
fn check_general_case(cx: &LateContext, name: &str, fun: &hir::Expr, self_expr: &hir::Expr, arg: &hir::Expr, or_has_args: bool, fn check_general_case(cx: &LateContext, name: &str, fun: &hir::Expr, self_expr: &hir::Expr, arg: &hir::Expr,
span: Span) { or_has_args: bool, span: Span) {
// don't lint for constant values // don't lint for constant values
// FIXME: can we `expect` here instead of match? // FIXME: can we `expect` here instead of match?
if let Some(qualif) = cx.tcx.const_qualif_map.borrow().get(&arg.id) { if let Some(qualif) = cx.tcx.const_qualif_map.borrow().get(&arg.id) {
@ -743,12 +746,10 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
} }
} }
// (path, fn_has_argument, methods, suffix) // (path, fn_has_argument, methods, suffix)
let know_types: &[(&[_], _, &[_], _)] = &[(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), let know_types: &[(&[_], _, &[_], _)] =
&[(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
(&paths::OPTION, (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
false,
&["map_or", "ok_or", "or", "unwrap_or"],
"else"),
(&paths::RESULT, true, &["or", "unwrap_or"], "else")]; (&paths::RESULT, true, &["or", "unwrap_or"], "else")];
let self_ty = cx.tcx.tables().expr_ty(self_expr); let self_ty = cx.tcx.tables().expr_ty(self_expr);
@ -770,7 +771,11 @@ fn lint_or_fun_call(cx: &LateContext, expr: &hir::Expr, name: &str, args: &[hir:
(false, true) => snippet(cx, fun.span, ".."), (false, true) => snippet(cx, fun.span, ".."),
}; };
span_lint_and_then(cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a function call", name), |db| { span_lint_and_then(cx,
OR_FUN_CALL,
span,
&format!("use of `{}` followed by a function call", name),
|db| {
db.span_suggestion(span, db.span_suggestion(span,
"try this", "try this",
format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg)); format!("{}.{}_{}({})", snippet(cx, self_expr.span, "_"), name, suffix, sugg));
@ -800,7 +805,9 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t
"using `clone` on a double-reference; \ "using `clone` on a double-reference; \
this will copy the reference instead of cloning the inner type", this will copy the reference instead of cloning the inner type",
|db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { |db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
db.span_suggestion(expr.span, "try dereferencing it", format!("({}).clone()", snip.deref())); db.span_suggestion(expr.span,
"try dereferencing it",
format!("({}).clone()", snip.deref()));
}); });
return; // don't report clone_on_copy return; // don't report clone_on_copy
} }
@ -824,12 +831,14 @@ fn lint_clone_on_copy(cx: &LateContext, expr: &hir::Expr, arg: &hir::Expr, arg_t
fn lint_vec_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) { fn lint_vec_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) {
let arg_ty = cx.tcx.tables().expr_ty(&args[1]); let arg_ty = cx.tcx.tables().expr_ty(&args[1]);
if let Some(slice) = derefs_to_slice(cx, &args[1], arg_ty) { if let Some(slice) = derefs_to_slice(cx, &args[1], arg_ty) {
span_lint_and_then(cx, EXTEND_FROM_SLICE, expr.span, "use of `extend` to extend a Vec by a slice", |db| { span_lint_and_then(cx,
EXTEND_FROM_SLICE,
expr.span,
"use of `extend` to extend a Vec by a slice",
|db| {
db.span_suggestion(expr.span, db.span_suggestion(expr.span,
"try this", "try this",
format!("{}.extend_from_slice({})", format!("{}.extend_from_slice({})", snippet(cx, args[0].span, "_"), slice));
snippet(cx, args[0].span, "_"),
slice));
}); });
} }
} }
@ -847,13 +856,9 @@ fn lint_string_extend(cx: &LateContext, expr: &hir::Expr, args: &[hir::Expr]) {
return; return;
}; };
span_lint_and_then( span_lint_and_then(cx, STRING_EXTEND_CHARS, expr.span, "calling `.extend(_.chars())`", |db| {
cx, db.span_suggestion(expr.span,
STRING_EXTEND_CHARS, "try this",
expr.span,
"calling `.extend(_.chars())`",
|db| {
db.span_suggestion(expr.span, "try this",
format!("{}.push_str({}{})", format!("{}.push_str({}{})",
snippet(cx, args[0].span, "_"), snippet(cx, args[0].span, "_"),
ref_str, ref_str,
@ -888,28 +893,24 @@ fn lint_cstring_as_ptr(cx: &LateContext, expr: &hir::Expr, new: &hir::Expr, unwr
}} }}
} }
fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool){ fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) {
let mut_str = if is_mut { "_mut" } else {""}; let mut_str = if is_mut { "_mut" } else { "" };
let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tcx.tables().expr_ty(&iter_args[0])).is_some() { let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tcx.tables().expr_ty(&iter_args[0])).is_some() {
"slice" "slice"
} } else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC) {
else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC) {
"Vec" "Vec"
} } else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC_DEQUE) {
else if match_type(cx, cx.tcx.tables().expr_ty(&iter_args[0]), &paths::VEC_DEQUE) {
"VecDeque" "VecDeque"
} } else {
else {
return; // caller is not a type that we want to lint return; // caller is not a type that we want to lint
}; };
span_lint( span_lint(cx,
cx,
ITER_NTH, ITER_NTH,
expr.span, expr.span,
&format!("called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable", &format!("called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
mut_str, caller_type) mut_str,
); caller_type));
} }
fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) { fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) {
@ -932,32 +933,29 @@ fn lint_get_unwrap(cx: &LateContext, expr: &hir::Expr, get_args: &[hir::Expr], i
let mut_str = if is_mut { "_mut" } else { "" }; let mut_str = if is_mut { "_mut" } else { "" };
let borrow_str = if is_mut { "&mut " } else { "&" }; let borrow_str = if is_mut { "&mut " } else { "&" };
span_lint_and_then( span_lint_and_then(cx,
cx,
GET_UNWRAP, GET_UNWRAP,
expr.span, expr.span,
&format!("called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", &format!("called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
mut_str, caller_type), mut_str,
caller_type),
|db| { |db| {
db.span_suggestion( db.span_suggestion(expr.span,
expr.span,
"try this", "try this",
format!("{}{}[{}]", borrow_str, snippet(cx, get_args[0].span, "_"), format!("{}{}[{}]",
snippet(cx, get_args[1].span, "_")) borrow_str,
); snippet(cx, get_args[0].span, "_"),
} snippet(cx, get_args[1].span, "_")));
); });
} }
fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr){ fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr) {
// lint if caller of skip is an Iterator // lint if caller of skip is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
span_lint( span_lint(cx,
cx,
ITER_SKIP_NEXT, ITER_SKIP_NEXT,
expr.span, expr.span,
"called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`" "called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`");
);
} }
} }
@ -975,9 +973,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: ty::Ty) -> Option<sug
if let hir::ExprMethodCall(name, _, ref args) = expr.node { if let hir::ExprMethodCall(name, _, ref args) = expr.node {
if &*name.node.as_str() == "iter" && may_slice(cx, cx.tcx.tables().expr_ty(&args[0])) { if &*name.node.as_str() == "iter" && may_slice(cx, cx.tcx.tables().expr_ty(&args[0])) {
sugg::Sugg::hir_opt(cx, &args[0]).map(|sugg| { sugg::Sugg::hir_opt(cx, &args[0]).map(|sugg| sugg.addr())
sugg.addr()
})
} else { } else {
None None
} }
@ -991,7 +987,7 @@ fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: ty::Ty) -> Option<sug
} else { } else {
None None
} }
} },
_ => None, _ => None,
} }
} }
@ -1099,8 +1095,8 @@ fn lint_map_unwrap_or_else(cx: &LateContext, expr: &hir::Expr, map_args: &[hir::
fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &[hir::Expr]) { fn lint_filter_next(cx: &LateContext, expr: &hir::Expr, filter_args: &[hir::Expr]) {
// lint if caller of `.filter().next()` is an Iterator // lint if caller of `.filter().next()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` \ let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
instead."; `.find(p)` instead.";
let filter_snippet = snippet(cx, filter_args[1].span, ".."); let filter_snippet = snippet(cx, filter_args[1].span, "..");
if filter_snippet.lines().count() <= 1 { if filter_snippet.lines().count() <= 1 {
// add note if not multi-line // add note if not multi-line
@ -1163,8 +1159,8 @@ fn lint_search_is_some(cx: &LateContext, expr: &hir::Expr, search_method: &str,
is_some_args: &[hir::Expr]) { is_some_args: &[hir::Expr]) {
// lint if caller of search is an Iterator // lint if caller of search is an Iterator
if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
let msg = format!("called `is_some()` after searching an `Iterator` with {}. This is more succinctly expressed \ let msg = format!("called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
by calling `any()`.", expressed by calling `any()`.",
search_method); search_method);
let search_snippet = snippet(cx, search_args[1].span, ".."); let search_snippet = snippet(cx, search_args[1].span, "..");
if search_snippet.lines().count() <= 1 { if search_snippet.lines().count() <= 1 {

View file

@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass {
(MinMax::Min, Some(Ordering::Greater)) => (), (MinMax::Min, Some(Ordering::Greater)) => (),
_ => { _ => {
span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result"); span_lint(cx, MIN_MAX, expr.span, "this min/max combination leads to constant result");
} },
} }
} }
} }

View file

@ -8,10 +8,8 @@ use rustc_const_eval::EvalHint::ExprTypeChecked;
use rustc_const_eval::eval_const_expr_partial; use rustc_const_eval::eval_const_expr_partial;
use rustc_const_math::ConstFloat; use rustc_const_math::ConstFloat;
use syntax::codemap::{Span, Spanned, ExpnFormat}; use syntax::codemap::{Span, Spanned, ExpnFormat};
use utils::{ use utils::{get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path, snippet,
get_item_name, get_parent_expr, implements_trait, in_macro, is_integer_literal, match_path, span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment};
snippet, span_lint, span_lint_and_then, walk_ptrs_ty, last_path_segment
};
use utils::sugg::Sugg; use utils::sugg::Sugg;
/// **What it does:** Checks for function arguments and let bindings denoted as `ref`. /// **What it does:** Checks for function arguments and let bindings denoted as `ref`.
@ -167,7 +165,8 @@ impl LintPass for Pass {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, k: FnKind<'tcx>, decl: &'tcx FnDecl, _: &'tcx Expr, _: Span, _: NodeId) { fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, k: FnKind<'tcx>, decl: &'tcx FnDecl, _: &'tcx Expr, _: Span,
_: NodeId) {
if let FnKind::Closure(_) = k { if let FnKind::Closure(_) = k {
// Does not apply to closures // Does not apply to closures
return; return;
@ -240,11 +239,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
return; return;
} }
} }
span_lint_and_then(cx, span_lint_and_then(cx, FLOAT_CMP, expr.span, "strict comparison of f32 or f64", |db| {
FLOAT_CMP,
expr.span,
"strict comparison of f32 or f64",
|db| {
let lhs = Sugg::hir(cx, left, ".."); let lhs = Sugg::hir(cx, left, "..");
let rhs = Sugg::hir(cx, right, ".."); let rhs = Sugg::hir(cx, right, "..");
@ -274,7 +269,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} else { } else {
None None
} }
} },
ExprField(_, spanned) => { ExprField(_, spanned) => {
let name = spanned.node.as_str(); let name = spanned.node.as_str();
if name.starts_with('_') && !name.starts_with("__") { if name.starts_with('_') && !name.starts_with("__") {
@ -282,7 +277,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} else { } else {
None None
} }
} },
_ => None, _ => None,
}; };
if let Some(binding) = binding { if let Some(binding) = binding {
@ -339,9 +334,8 @@ fn is_allowed(cx: &LateContext, expr: &Expr) -> bool {
f64: ::std::f64::NEG_INFINITY, f64: ::std::f64::NEG_INFINITY,
}; };
val.try_cmp(zero) == Ok(Ordering::Equal) val.try_cmp(zero) == Ok(Ordering::Equal) || val.try_cmp(infinity) == Ok(Ordering::Equal) ||
|| val.try_cmp(infinity) == Ok(Ordering::Equal) val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
|| val.try_cmp(neg_infinity) == Ok(Ordering::Equal)
} else { } else {
false false
} }
@ -360,7 +354,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S
} else { } else {
return; return;
} }
} },
ExprCall(ref path, ref v) if v.len() == 1 => { ExprCall(ref path, ref v) if v.len() == 1 => {
if let ExprPath(ref path) = path.node { if let ExprPath(ref path) = path.node {
if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) { if match_path(path, &["String", "from_str"]) || match_path(path, &["String", "from"]) {
@ -371,7 +365,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S
} else { } else {
return; return;
} }
} },
_ => return, _ => return,
}; };
@ -408,8 +402,7 @@ fn check_to_owned(cx: &LateContext, expr: &Expr, other: &Expr, left: bool, op: S
} }
fn is_str_arg(cx: &LateContext, args: &[Expr]) -> bool { fn is_str_arg(cx: &LateContext, args: &[Expr]) -> bool {
args.len() == 1 && args.len() == 1 && matches!(walk_ptrs_ty(cx.tcx.tables().expr_ty(&args[0])).sty, ty::TyStr)
matches!(walk_ptrs_ty(cx.tcx.tables().expr_ty(&args[0])).sty, ty::TyStr)
} }
/// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea /// Heuristic to see if an expression is used. Should be compatible with `unused_variables`'s idea
@ -430,22 +423,21 @@ fn is_used(cx: &LateContext, expr: &Expr) -> bool {
/// `#[derive(...)`] or the like). /// `#[derive(...)`] or the like).
fn in_attributes_expansion(cx: &LateContext, expr: &Expr) -> bool { fn in_attributes_expansion(cx: &LateContext, expr: &Expr) -> bool {
cx.sess().codemap().with_expn_info(expr.span.expn_id, |info_opt| { cx.sess().codemap().with_expn_info(expr.span.expn_id, |info_opt| {
info_opt.map_or(false, |info| { info_opt.map_or(false, |info| matches!(info.callee.format, ExpnFormat::MacroAttribute(_)))
matches!(info.callee.format, ExpnFormat::MacroAttribute(_))
})
}) })
} }
/// Test whether `def` is a variable defined outside a macro. /// Test whether `def` is a variable defined outside a macro.
fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool { fn non_macro_local(cx: &LateContext, def: &def::Def) -> bool {
match *def { match *def {
def::Def::Local(id) | def::Def::Upvar(id, _, _) => { def::Def::Local(id) |
def::Def::Upvar(id, _, _) => {
if let Some(span) = cx.tcx.map.span_if_local(id) { if let Some(span) = cx.tcx.map.span_if_local(id) {
!in_macro(cx, span) !in_macro(cx, span)
} else { } else {
true true
} }
} },
_ => false, _ => false,
} }
} }

View file

@ -168,9 +168,14 @@ pub struct MiscEarly;
impl LintPass for MiscEarly { impl LintPass for MiscEarly {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL, lint_array!(UNNEEDED_FIELD_PATTERN,
DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, DUPLICATE_UNDERSCORE_ARGUMENT,
ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW) REDUNDANT_CLOSURE_CALL,
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW)
} }
} }
@ -279,7 +284,7 @@ impl EarlyLintPass for MiscEarly {
}); });
} }
} }
} },
ExprKind::Unary(UnOp::Neg, ref inner) => { ExprKind::Unary(UnOp::Neg, ref inner) => {
if let ExprKind::Unary(UnOp::Neg, _) = inner.node { if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
span_lint(cx, span_lint(cx,
@ -287,7 +292,7 @@ impl EarlyLintPass for MiscEarly {
expr.span, expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op"); "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op");
} }
} },
ExprKind::Lit(ref lit) => { ExprKind::Lit(ref lit) => {
if_let_chain! {[ if_let_chain! {[
let LitKind::Int(value, ..) = lit.node, let LitKind::Int(value, ..) = lit.node,
@ -351,8 +356,8 @@ impl EarlyLintPass for MiscEarly {
prev = ch; prev = ch;
} }
}} }}
} },
_ => () _ => (),
} }
} }

View file

@ -1,21 +1,21 @@
/* This file incorporates work covered by the following copyright and // This file incorporates work covered by the following copyright and
* permission notice: // permission notice:
* Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
* //
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
* except according to those terms. // except according to those terms.
*/ //
/* Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s // Note: More specifically this lint is largely inspired (aka copied) from *rustc*'s
* [`missing_doc`]. // [`missing_doc`].
* //
* [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 // [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246
*/ //
use rustc::hir; use rustc::hir;
use rustc::lint::*; use rustc::lint::*;
@ -51,20 +51,14 @@ impl ::std::default::Default for MissingDoc {
impl MissingDoc { impl MissingDoc {
pub fn new() -> MissingDoc { pub fn new() -> MissingDoc {
MissingDoc { MissingDoc { doc_hidden_stack: vec![false] }
doc_hidden_stack: vec![false],
}
} }
fn doc_hidden(&self) -> bool { fn doc_hidden(&self) -> bool {
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack") *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
} }
fn check_missing_docs_attrs(&self, fn check_missing_docs_attrs(&self, cx: &LateContext, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
cx: &LateContext,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
// If we're building a test harness, then warning about // If we're building a test harness, then warning about
// documentation is probably not really relevant right now. // documentation is probably not really relevant right now.
if cx.sess().opts.test { if cx.sess().opts.test {
@ -82,7 +76,8 @@ impl MissingDoc {
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc { if !has_doc {
cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS, sp, cx.span_lint(MISSING_DOCS_IN_PRIVATE_ITEMS,
sp,
&format!("missing documentation for {}", desc)); &format!("missing documentation for {}", desc));
} }
} }
@ -96,8 +91,10 @@ impl LintPass for MissingDoc {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) { fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { let doc_hidden = self.doc_hidden() ||
attr.check_name("doc") && match attr.meta_item_list() { attrs.iter().any(|attr| {
attr.check_name("doc") &&
match attr.meta_item_list() {
None => false, None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"), Some(l) => attr::list_contains_name(&l[..], "hidden"),
} }
@ -151,9 +148,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
ty::TraitContainer(_) => return, ty::TraitContainer(_) => return,
ty::ImplContainer(cid) => { ty::ImplContainer(cid) => {
if cx.tcx.impl_trait_ref(cid).is_some() { if cx.tcx.impl_trait_ref(cid).is_some() {
return return;
}
} }
},
} }
let desc = match impl_item.node { let desc = match impl_item.node {

View file

@ -64,7 +64,10 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
intravisit::walk_expr(self, body); intravisit::walk_expr(self, body);
} else if let hir::ExprAddrOf(hir::MutMutable, ref e) = expr.node { } else if let hir::ExprAddrOf(hir::MutMutable, ref e) = expr.node {
if let hir::ExprAddrOf(hir::MutMutable, _) = e.node { if let hir::ExprAddrOf(hir::MutMutable, _) = e.node {
span_lint(self.cx, MUT_MUT, expr.span, "generally you want to avoid `&mut &mut _` if possible"); span_lint(self.cx,
MUT_MUT,
expr.span,
"generally you want to avoid `&mut &mut _` if possible");
} else if let TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tcx.tables().expr_ty(e).sty { } else if let TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tcx.tables().expr_ty(e).sty {
span_lint(self.cx, span_lint(self.cx,
MUT_MUT, MUT_MUT,
@ -77,7 +80,10 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty) { fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
if let hir::TyRptr(_, hir::MutTy { ty: ref pty, mutbl: hir::MutMutable }) = ty.node { if let hir::TyRptr(_, hir::MutTy { ty: ref pty, mutbl: hir::MutMutable }) = ty.node {
if let hir::TyRptr(_, hir::MutTy { mutbl: hir::MutMutable, .. }) = pty.node { if let hir::TyRptr(_, hir::MutTy { mutbl: hir::MutMutable, .. }) = pty.node {
span_lint(self.cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible"); span_lint(self.cx,
MUT_MUT,
ty.span,
"generally you want to avoid `&mut &mut _` if possible");
} }
} }

View file

@ -39,18 +39,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
ExprCall(ref fn_expr, ref arguments) => { ExprCall(ref fn_expr, ref arguments) => {
let function_type = borrowed_table.node_types let function_type = borrowed_table.node_types
.get(&fn_expr.id) .get(&fn_expr.id)
.expect("A function with an unknown type is called. \ .expect("A function with an unknown type is called. If this happened, the compiler would have \
If this happened, the compiler would have \
aborted the compilation long ago"); aborted the compilation long ago");
if let ExprPath(ref path) = fn_expr.node { if let ExprPath(ref path) = fn_expr.node {
check_arguments(cx, arguments, function_type, &path.to_string()); check_arguments(cx, arguments, function_type, &path.to_string());
} }
} },
ExprMethodCall(ref name, _, ref arguments) => { ExprMethodCall(ref name, _, ref arguments) => {
let method_call = MethodCall::expr(e.id); let method_call = MethodCall::expr(e.id);
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen."); let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
check_arguments(cx, arguments, method_type.ty, &name.node.as_str()) check_arguments(cx, arguments, method_type.ty, &name.node.as_str())
} },
_ => (), _ => (),
} }
} }
@ -71,11 +70,11 @@ fn check_arguments(cx: &LateContext, arguments: &[Expr], type_definition: &TyS,
argument.span, argument.span,
&format!("The function/method \"{}\" doesn't need a mutable reference", name)); &format!("The function/method \"{}\" doesn't need a mutable reference", name));
} }
} },
_ => (), _ => (),
} }
} }
} },
_ => (), _ => (),
} }
} }

View file

@ -62,11 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node { if let ExprIf(ref pred, ref then_block, Some(ref else_expr)) = e.node {
let reduce = |ret, not| { let reduce = |ret, not| {
let snip = Sugg::hir(cx, pred, "<predicate>"); let snip = Sugg::hir(cx, pred, "<predicate>");
let snip = if not { let snip = if not { !snip } else { snip };
!snip
} else {
snip
};
let hint = if ret { let hint = if ret {
format!("return {}", snip) format!("return {}", snip)
@ -89,14 +85,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
NEEDLESS_BOOL, NEEDLESS_BOOL,
e.span, e.span,
"this if-then-else expression will always return true"); "this if-then-else expression will always return true");
} },
(RetBool(false), RetBool(false)) | (RetBool(false), RetBool(false)) |
(Bool(false), Bool(false)) => { (Bool(false), Bool(false)) => {
span_lint(cx, span_lint(cx,
NEEDLESS_BOOL, NEEDLESS_BOOL,
e.span, e.span,
"this if-then-else expression will always return false"); "this if-then-else expression will always return false");
} },
(RetBool(true), RetBool(false)) => reduce(true, false), (RetBool(true), RetBool(false)) => reduce(true, false),
(Bool(true), Bool(false)) => reduce(false, false), (Bool(true), Bool(false)) => reduce(false, false),
(RetBool(false), RetBool(true)) => reduce(true, true), (RetBool(false), RetBool(true)) => reduce(true, true),
@ -130,7 +126,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
|db| { |db| {
db.span_suggestion(e.span, "try simplifying it as shown:", hint); db.span_suggestion(e.span, "try simplifying it as shown:", hint);
}); });
} },
(Other, Bool(true)) => { (Other, Bool(true)) => {
let hint = snippet(cx, left_side.span, "..").into_owned(); let hint = snippet(cx, left_side.span, "..").into_owned();
span_lint_and_then(cx, span_lint_and_then(cx,
@ -140,7 +136,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
|db| { |db| {
db.span_suggestion(e.span, "try simplifying it as shown:", hint); db.span_suggestion(e.span, "try simplifying it as shown:", hint);
}); });
} },
(Bool(false), Other) => { (Bool(false), Other) => {
let hint = Sugg::hir(cx, right_side, ".."); let hint = Sugg::hir(cx, right_side, "..");
span_lint_and_then(cx, span_lint_and_then(cx,
@ -148,9 +144,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
e.span, e.span,
"equality checks against false can be replaced by a negation", "equality checks against false can be replaced by a negation",
|db| { |db| {
db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string()); db.span_suggestion(e.span,
"try simplifying it as shown:",
(!hint).to_string());
}); });
} },
(Other, Bool(false)) => { (Other, Bool(false)) => {
let hint = Sugg::hir(cx, left_side, ".."); let hint = Sugg::hir(cx, left_side, "..");
span_lint_and_then(cx, span_lint_and_then(cx,
@ -158,9 +156,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
e.span, e.span,
"equality checks against false can be replaced by a negation", "equality checks against false can be replaced by a negation",
|db| { |db| {
db.span_suggestion(e.span, "try simplifying it as shown:", (!hint).to_string()); db.span_suggestion(e.span,
"try simplifying it as shown:",
(!hint).to_string());
}); });
} },
_ => (), _ => (),
} }
} }
@ -186,7 +186,7 @@ fn fetch_bool_block(block: &Block) -> Expression {
} else { } else {
Expression::Other Expression::Other
} }
} },
_ => Expression::Other, _ => Expression::Other,
} }
} }
@ -200,13 +200,13 @@ fn fetch_bool_expr(expr: &Expr) -> Expression {
} else { } else {
Expression::Other Expression::Other
} }
} },
ExprRet(Some(ref expr)) => { ExprRet(Some(ref expr)) => {
match fetch_bool_expr(expr) { match fetch_bool_expr(expr) {
Expression::Bool(value) => Expression::RetBool(value), Expression::Bool(value) => Expression::RetBool(value),
_ => Expression::Other, _ => Expression::Other,
} }
} },
_ => Expression::Other, _ => Expression::Other,
} }
} }

View file

@ -41,7 +41,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
} }
if let ExprAddrOf(MutImmutable, ref inner) = e.node { if let ExprAddrOf(MutImmutable, ref inner) = e.node {
if let ty::TyRef(..) = cx.tcx.tables().expr_ty(inner).sty { if let ty::TyRef(..) = cx.tcx.tables().expr_ty(inner).sty {
if let Some(&ty::adjustment::Adjust::DerefRef { autoderefs, autoref, .. }) = cx.tcx.tables.borrow().adjustments.get(&e.id).map(|a| &a.kind) { if let Some(&ty::adjustment::Adjust::DerefRef { autoderefs, autoref, .. }) =
cx.tcx.tables.borrow().adjustments.get(&e.id).map(|a| &a.kind) {
if autoderefs > 1 && autoref.is_some() { if autoderefs > 1 && autoref.is_some() {
span_lint(cx, span_lint(cx,
NEEDLESS_BORROW, NEEDLESS_BORROW,
@ -61,10 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
if let ty::TyRef(_, ref tam) = cx.tcx.tables().pat_ty(pat).sty { if let ty::TyRef(_, ref tam) = cx.tcx.tables().pat_ty(pat).sty {
if tam.mutbl == MutImmutable { if tam.mutbl == MutImmutable {
if let ty::TyRef(..) = tam.ty.sty { if let ty::TyRef(..) = tam.ty.sty {
span_lint(cx, span_lint(cx, NEEDLESS_BORROW, pat.span, "this pattern creates a reference to a reference")
NEEDLESS_BORROW,
pat.span,
"this pattern creates a reference to a reference")
} }
} }
} }

View file

@ -90,15 +90,8 @@ impl LintPass for NewWithoutDefault {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
fn check_fn( fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, kind: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
&mut self, _: &'tcx hir::Expr, span: Span, id: ast::NodeId) {
cx: &LateContext<'a, 'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
_: &'tcx hir::Expr,
span: Span,
id: ast::NodeId,
) {
if in_external_macro(cx, span) { if in_external_macro(cx, span) {
return; return;
} }
@ -161,7 +154,7 @@ fn can_derive_default<'t, 'c>(ty: ty::Ty<'t>, cx: &LateContext<'c, 't>, default_
} }
} }
true true
} },
_ => false, _ => false,
} }
} }

View file

@ -66,7 +66,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
Some(ref base) => has_no_effect(cx, base), Some(ref base) => has_no_effect(cx, base),
None => true, None => true,
} }
} },
Expr_::ExprCall(ref callee, ref args) => { Expr_::ExprCall(ref callee, ref args) => {
if let Expr_::ExprPath(ref qpath) = callee.node { if let Expr_::ExprPath(ref qpath) = callee.node {
let def = cx.tcx.tables().qpath_def(qpath, callee.id); let def = cx.tcx.tables().qpath_def(qpath, callee.id);
@ -80,7 +80,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
} else { } else {
false false
} }
} },
Expr_::ExprBlock(ref block) => { Expr_::ExprBlock(ref block) => {
block.stmts.is_empty() && block.stmts.is_empty() &&
if let Some(ref expr) = block.expr { if let Some(ref expr) = block.expr {
@ -88,7 +88,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
} else { } else {
false false
} }
} },
_ => false, _ => false,
} }
} }
@ -148,7 +148,7 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp
Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
Expr_::ExprStruct(_, ref fields, ref base) => { Expr_::ExprStruct(_, ref fields, ref base) => {
Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect()) Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
} },
Expr_::ExprCall(ref callee, ref args) => { Expr_::ExprCall(ref callee, ref args) => {
if let Expr_::ExprPath(ref qpath) = callee.node { if let Expr_::ExprPath(ref qpath) = callee.node {
let def = cx.tcx.tables().qpath_def(qpath, callee.id); let def = cx.tcx.tables().qpath_def(qpath, callee.id);
@ -162,7 +162,7 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp
} else { } else {
None None
} }
} },
Expr_::ExprBlock(ref block) => { Expr_::ExprBlock(ref block) => {
if block.stmts.is_empty() { if block.stmts.is_empty() {
block.expr.as_ref().and_then(|e| { block.expr.as_ref().and_then(|e| {
@ -176,7 +176,7 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp
} else { } else {
None None
} }
} },
_ => None, _ => None,
} }
} }

View file

@ -88,7 +88,7 @@ impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
self.visit_pat(&field.node.pat); self.visit_pat(&field.node.pat);
} }
} }
} },
_ => walk_pat(self, pat), _ => walk_pat(self, pat),
} }
} }

View file

@ -15,7 +15,7 @@ use utils::{paths, method_chain_args, span_help_and_lint, match_type, snippet};
/// vec.push(bench) /// vec.push(bench)
/// } /// }
/// } /// }
///``` /// ```
/// Could be written: /// Could be written:
/// ///
/// ```rust /// ```rust

View file

@ -71,36 +71,32 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp
let argument_option = match arguments[1].node { let argument_option = match arguments[1].node {
ExprLit(ref span) => { ExprLit(ref span) => {
if let Spanned { node: LitKind::Bool(lit), .. } = **span { if let Spanned { node: LitKind::Bool(lit), .. } = **span {
if lit { if lit { Argument::True } else { Argument::False }
Argument::True
} else {
Argument::False
}
} else { } else {
return; // The function is called with a literal return; // The function is called with a literal
// which is not a boolean literal. This is theoretically // which is not a boolean literal. This is theoretically
// possible, but not very likely. // possible, but not very likely.
} }
} },
_ => Argument::Unknown, _ => Argument::Unknown,
}; };
match &*name.node.as_str() { match &*name.node.as_str() {
"create" => { "create" => {
options.push((OpenOption::Create, argument_option)); options.push((OpenOption::Create, argument_option));
} },
"append" => { "append" => {
options.push((OpenOption::Append, argument_option)); options.push((OpenOption::Append, argument_option));
} },
"truncate" => { "truncate" => {
options.push((OpenOption::Truncate, argument_option)); options.push((OpenOption::Truncate, argument_option));
} },
"read" => { "read" => {
options.push((OpenOption::Read, argument_option)); options.push((OpenOption::Read, argument_option));
} },
"write" => { "write" => {
options.push((OpenOption::Write, argument_option)); options.push((OpenOption::Write, argument_option));
} },
_ => (), _ => (),
} }
@ -111,11 +107,8 @@ fn get_open_options(cx: &LateContext, argument: &Expr, options: &mut Vec<(OpenOp
fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) { fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span: Span) {
let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false); let (mut create, mut append, mut truncate, mut read, mut write) = (false, false, false, false, false);
let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) = (false, let (mut create_arg, mut append_arg, mut truncate_arg, mut read_arg, mut write_arg) =
false, (false, false, false, false, false);
false,
false,
false);
// This code is almost duplicated (oh, the irony), but I haven't found a way to unify it. // This code is almost duplicated (oh, the irony), but I haven't found a way to unify it.
for option in options { for option in options {
@ -130,7 +123,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span
create = true create = true
} }
create_arg = create_arg || (arg == Argument::True);; create_arg = create_arg || (arg == Argument::True);;
} },
(OpenOption::Append, arg) => { (OpenOption::Append, arg) => {
if append { if append {
span_lint(cx, span_lint(cx,
@ -141,7 +134,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span
append = true append = true
} }
append_arg = append_arg || (arg == Argument::True);; append_arg = append_arg || (arg == Argument::True);;
} },
(OpenOption::Truncate, arg) => { (OpenOption::Truncate, arg) => {
if truncate { if truncate {
span_lint(cx, span_lint(cx,
@ -152,7 +145,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span
truncate = true truncate = true
} }
truncate_arg = truncate_arg || (arg == Argument::True); truncate_arg = truncate_arg || (arg == Argument::True);
} },
(OpenOption::Read, arg) => { (OpenOption::Read, arg) => {
if read { if read {
span_lint(cx, span_lint(cx,
@ -163,7 +156,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span
read = true read = true
} }
read_arg = read_arg || (arg == Argument::True);; read_arg = read_arg || (arg == Argument::True);;
} },
(OpenOption::Write, arg) => { (OpenOption::Write, arg) => {
if write { if write {
span_lint(cx, span_lint(cx,
@ -174,7 +167,7 @@ fn check_open_options(cx: &LateContext, options: &[(OpenOption, Argument)], span
write = true write = true
} }
write_arg = write_arg || (arg == Argument::True);; write_arg = write_arg || (arg == Argument::True);;
} },
} }
} }

View file

@ -49,7 +49,7 @@ impl EarlyLintPass for Precedence {
snippet(cx, left.span, ".."), snippet(cx, left.span, ".."),
op.to_string(), op.to_string(),
snippet(cx, right.span, ".."))); snippet(cx, right.span, "..")));
} },
(true, false) => { (true, false) => {
span_lint(cx, span_lint(cx,
PRECEDENCE, PRECEDENCE,
@ -59,7 +59,7 @@ impl EarlyLintPass for Precedence {
snippet(cx, left.span, ".."), snippet(cx, left.span, ".."),
op.to_string(), op.to_string(),
snippet(cx, right.span, ".."))); snippet(cx, right.span, "..")));
} },
(false, true) => { (false, true) => {
span_lint(cx, span_lint(cx,
PRECEDENCE, PRECEDENCE,
@ -69,7 +69,7 @@ impl EarlyLintPass for Precedence {
snippet(cx, left.span, ".."), snippet(cx, left.span, ".."),
op.to_string(), op.to_string(),
snippet(cx, right.span, ".."))); snippet(cx, right.span, "..")));
} },
_ => (), _ => (),
} }
} }
@ -88,7 +88,7 @@ impl EarlyLintPass for Precedence {
&format!("unary minus has lower precedence than method call. Consider \ &format!("unary minus has lower precedence than method call. Consider \
adding parentheses to clarify your intent: -({})", adding parentheses to clarify your intent: -({})",
snippet(cx, rhs.span, ".."))); snippet(cx, rhs.span, "..")));
} },
_ => (), _ => (),
} }
} }

View file

@ -117,7 +117,7 @@ fn is_null_path(expr: &Expr) -> bool {
if let ExprCall(ref pathexp, ref args) = expr.node { if let ExprCall(ref pathexp, ref args) = expr.node {
if args.is_empty() { if args.is_empty() {
if let ExprPath(ref path) = pathexp.node { if let ExprPath(ref path) = pathexp.node {
return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT) return match_path(path, &paths::PTR_NULL) || match_path(path, &paths::PTR_NULL_MUT);
} }
} }
} }

View file

@ -52,8 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero {
let name = &*name.as_str(); let name = &*name.as_str();
// Range with step_by(0). // Range with step_by(0).
if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) && if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) && is_integer_literal(&args[1], 0) {
is_integer_literal(&args[1], 0) {
span_lint(cx, span_lint(cx,
RANGE_STEP_BY_ZERO, RANGE_STEP_BY_ZERO,
expr.span, expr.span,
@ -94,7 +93,6 @@ fn has_step_by(cx: &LateContext, expr: &Expr) -> bool {
let ty = cx.tcx.tables().expr_ty(expr); let ty = cx.tcx.tables().expr_ty(expr);
// Note: `RangeTo`, `RangeToInclusive` and `RangeFull` don't have step_by // Note: `RangeTo`, `RangeToInclusive` and `RangeFull` don't have step_by
match_type(cx, ty, &paths::RANGE) match_type(cx, ty, &paths::RANGE) || match_type(cx, ty, &paths::RANGE_FROM) ||
|| match_type(cx, ty, &paths::RANGE_FROM) match_type(cx, ty, &paths::RANGE_INCLUSIVE)
|| match_type(cx, ty, &paths::RANGE_INCLUSIVE)
} }

View file

@ -1,4 +1,4 @@
use syntax::ast::{Expr,ExprKind,UnOp}; use syntax::ast::{Expr, ExprKind, UnOp};
use rustc::lint::*; use rustc::lint::*;
use utils::{span_lint_and_then, snippet}; use utils::{span_lint_and_then, snippet};
@ -40,14 +40,8 @@ impl EarlyLintPass for Pass {
fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) { fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) {
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node {
if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node { if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node {
span_lint_and_then( span_lint_and_then(cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference", |db| {
cx, db.span_suggestion(e.span, "try this", format!("{}", snippet(cx, addrof_target.span, "_")));
DEREF_ADDROF,
e.span,
"immediately dereferencing a reference",
|db| {
db.span_suggestion(e.span, "try this",
format!("{}", snippet(cx, addrof_target.span, "_")));
}); });
} }
} }

View file

@ -145,7 +145,7 @@ fn str_span(base: Span, s: &str, c: usize) -> Span {
hi: base.lo + BytePos(h as u32), hi: base.lo + BytePos(h as u32),
..base ..base
} }
} },
_ => base, _ => base,
} }
} }
@ -172,17 +172,18 @@ fn is_trivial_regex(s: &regex_syntax::Expr) -> Option<&'static str> {
(&Expr::Literal { .. }, &Expr::EndText) => Some("consider using `str::ends_with`"), (&Expr::Literal { .. }, &Expr::EndText) => Some("consider using `str::ends_with`"),
_ => None, _ => None,
} }
} },
3 => { 3 => {
if let (&Expr::StartText, &Expr::Literal {..}, &Expr::EndText) = (&exprs[0], &exprs[1], &exprs[2]) { if let (&Expr::StartText, &Expr::Literal { .. }, &Expr::EndText) =
(&exprs[0], &exprs[1], &exprs[2]) {
Some("consider using `==` on `str`s") Some("consider using `==` on `str`s")
} else { } else {
None None
} }
} },
_ => None, _ => None,
} }
} },
_ => None, _ => None,
} }
} }
@ -213,14 +214,14 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) {
"trivial regex", "trivial regex",
&format!("consider using {}", repl)); &format!("consider using {}", repl));
} }
} },
Err(e) => { Err(e) => {
span_lint(cx, span_lint(cx,
INVALID_REGEX, INVALID_REGEX,
str_span(expr.span, r, e.position()), str_span(expr.span, r, e.position()),
&format!("regex syntax error: {}", &format!("regex syntax error: {}",
e.description())); e.description()));
} },
} }
} }
} else if let Some(r) = const_str(cx, expr) { } else if let Some(r) = const_str(cx, expr) {
@ -233,7 +234,7 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) {
"trivial regex", "trivial regex",
&format!("consider using {}", repl)); &format!("consider using {}", repl));
} }
} },
Err(e) => { Err(e) => {
span_lint(cx, span_lint(cx,
INVALID_REGEX, INVALID_REGEX,
@ -241,7 +242,7 @@ fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) {
&format!("regex syntax error on position {}: {}", &format!("regex syntax error on position {}: {}",
e.position(), e.position(),
e.description())); e.description()));
} },
} }
} }
} }

View file

@ -48,9 +48,10 @@ impl ReturnPass {
fn check_block_return(&mut self, cx: &EarlyContext, block: &ast::Block) { fn check_block_return(&mut self, cx: &EarlyContext, block: &ast::Block) {
if let Some(stmt) = block.stmts.last() { if let Some(stmt) = block.stmts.last() {
match stmt.node { match stmt.node {
ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => { ast::StmtKind::Expr(ref expr) |
ast::StmtKind::Semi(ref expr) => {
self.check_final_expr(cx, expr, Some(stmt.span)); self.check_final_expr(cx, expr, Some(stmt.span));
} },
_ => (), _ => (),
} }
} }
@ -65,24 +66,24 @@ impl ReturnPass {
if !expr.attrs.iter().any(attr_is_cfg) { if !expr.attrs.iter().any(attr_is_cfg) {
self.emit_return_lint(cx, span.expect("`else return` is not possible"), inner.span); self.emit_return_lint(cx, span.expect("`else return` is not possible"), inner.span);
} }
} },
// a whole block? check it! // a whole block? check it!
ast::ExprKind::Block(ref block) => { ast::ExprKind::Block(ref block) => {
self.check_block_return(cx, block); self.check_block_return(cx, block);
} },
// an if/if let expr, check both exprs // an if/if let expr, check both exprs
// note, if without else is going to be a type checking error anyways // note, if without else is going to be a type checking error anyways
// (except for unit type functions) so we don't match it // (except for unit type functions) so we don't match it
ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => { ast::ExprKind::If(_, ref ifblock, Some(ref elsexpr)) => {
self.check_block_return(cx, ifblock); self.check_block_return(cx, ifblock);
self.check_final_expr(cx, elsexpr, None); self.check_final_expr(cx, elsexpr, None);
} },
// a match expr, check all arms // a match expr, check all arms
ast::ExprKind::Match(_, ref arms) => { ast::ExprKind::Match(_, ref arms) => {
for arm in arms { for arm in arms {
self.check_final_expr(cx, &arm.body, Some(arm.body.span)); self.check_final_expr(cx, &arm.body, Some(arm.body.span));
} }
} },
_ => (), _ => (),
} }
} }
@ -135,7 +136,8 @@ impl LintPass for ReturnPass {
impl EarlyLintPass for ReturnPass { impl EarlyLintPass for ReturnPass {
fn check_fn(&mut self, cx: &EarlyContext, kind: FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { fn check_fn(&mut self, cx: &EarlyContext, kind: FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) {
match kind { match kind {
FnKind::ItemFn(.., block) | FnKind::Method(.., block) => self.check_block_return(cx, block), FnKind::ItemFn(.., block) |
FnKind::Method(.., block) => self.check_block_return(cx, block),
FnKind::Closure(body) => self.check_final_expr(cx, body, None), FnKind::Closure(body) => self.check_final_expr(cx, body, None),
} }
} }
@ -152,4 +154,3 @@ fn attr_is_cfg(attr: &ast::Attribute) -> bool {
false false
} }
} }

View file

@ -46,8 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde {
span_lint(cx, span_lint(cx,
SERDE_API_MISUSE, SERDE_API_MISUSE,
span, span,
"you should not implement `visit_string` without also implementing `visit_str`", "you should not implement `visit_string` without also implementing `visit_str`");
);
} }
} }
} }

View file

@ -80,15 +80,8 @@ impl LintPass for Pass {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn( fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, _: FnKind<'tcx>, decl: &'tcx FnDecl, expr: &'tcx Expr,
&mut self, _: Span, _: NodeId) {
cx: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
decl: &'tcx FnDecl,
expr: &'tcx Expr,
_: Span,
_: NodeId,
) {
if in_external_macro(cx, expr.span) { if in_external_macro(cx, expr.span) {
return; return;
} }
@ -150,13 +143,8 @@ fn is_binding(cx: &LateContext, pat_id: NodeId) -> bool {
} }
} }
fn check_pat<'a, 'tcx>( fn check_pat<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat, init: Option<&'tcx Expr>, span: Span,
cx: &LateContext<'a, 'tcx>, bindings: &mut Vec<(Name, Span)>) {
pat: &'tcx Pat,
init: Option<&'tcx Expr>,
span: Span,
bindings: &mut Vec<(Name, Span)>,
) {
// TODO: match more stuff / destructuring // TODO: match more stuff / destructuring
match pat.node { match pat.node {
PatKind::Binding(_, _, ref ident, ref inner) => { PatKind::Binding(_, _, ref ident, ref inner) => {
@ -178,7 +166,7 @@ fn check_pat<'a, 'tcx>(
if let Some(ref p) = *inner { if let Some(ref p) = *inner {
check_pat(cx, p, init, span, bindings); check_pat(cx, p, init, span, bindings);
} }
} },
PatKind::Struct(_, ref pfields, _) => { PatKind::Struct(_, ref pfields, _) => {
if let Some(init_struct) = init { if let Some(init_struct) = init {
if let ExprStruct(_, ref efields, _) = init_struct.node { if let ExprStruct(_, ref efields, _) = init_struct.node {
@ -199,7 +187,7 @@ fn check_pat<'a, 'tcx>(
check_pat(cx, &field.node.pat, None, span, bindings); check_pat(cx, &field.node.pat, None, span, bindings);
} }
} }
} },
PatKind::Tuple(ref inner, _) => { PatKind::Tuple(ref inner, _) => {
if let Some(init_tup) = init { if let Some(init_tup) = init {
if let ExprTup(ref tup) = init_tup.node { if let ExprTup(ref tup) = init_tup.node {
@ -216,7 +204,7 @@ fn check_pat<'a, 'tcx>(
check_pat(cx, p, None, span, bindings); check_pat(cx, p, None, span, bindings);
} }
} }
} },
PatKind::Box(ref inner) => { PatKind::Box(ref inner) => {
if let Some(initp) = init { if let Some(initp) = init {
if let ExprBox(ref inner_init) = initp.node { if let ExprBox(ref inner_init) = initp.node {
@ -227,21 +215,15 @@ fn check_pat<'a, 'tcx>(
} else { } else {
check_pat(cx, inner, init, span, bindings); check_pat(cx, inner, init, span, bindings);
} }
} },
PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings), PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings),
// PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>), // PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
_ => (), _ => (),
} }
} }
fn lint_shadow<'a, 'tcx: 'a>( fn lint_shadow<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, span: Span, pattern_span: Span,
cx: &LateContext<'a, 'tcx>, init: Option<&'tcx Expr>, prev_span: Span) {
name: Name,
span: Span,
pattern_span: Span,
init: Option<&'tcx Expr>,
prev_span: Span,
) {
if let Some(expr) = init { if let Some(expr) = init {
if is_self_shadow(name, expr) { if is_self_shadow(name, expr) {
span_lint_and_then(cx, span_lint_and_then(cx,
@ -250,8 +232,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
&format!("`{}` is shadowed by itself in `{}`", &format!("`{}` is shadowed by itself in `{}`",
snippet(cx, pattern_span, "_"), snippet(cx, pattern_span, "_"),
snippet(cx, expr.span, "..")), snippet(cx, expr.span, "..")),
|db| { db.span_note(prev_span, "previous binding is here"); }, |db| {
); db.span_note(prev_span, "previous binding is here");
});
} else if contains_self(cx, name, expr) { } else if contains_self(cx, name, expr) {
span_lint_and_then(cx, span_lint_and_then(cx,
SHADOW_REUSE, SHADOW_REUSE,
@ -281,7 +264,9 @@ fn lint_shadow<'a, 'tcx: 'a>(
SHADOW_UNRELATED, SHADOW_UNRELATED,
span, span,
&format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")), &format!("`{}` shadows a previous declaration", snippet(cx, pattern_span, "_")),
|db| { db.span_note(prev_span, "previous binding is here"); }); |db| {
db.span_note(prev_span, "previous binding is here");
});
} }
} }
@ -303,18 +288,18 @@ fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings:
for e in v { for e in v {
check_expr(cx, e, bindings) check_expr(cx, e, bindings)
} }
} },
ExprIf(ref cond, ref then, ref otherwise) => { ExprIf(ref cond, ref then, ref otherwise) => {
check_expr(cx, cond, bindings); check_expr(cx, cond, bindings);
check_block(cx, then, bindings); check_block(cx, then, bindings);
if let Some(ref o) = *otherwise { if let Some(ref o) = *otherwise {
check_expr(cx, o, bindings); check_expr(cx, o, bindings);
} }
} },
ExprWhile(ref cond, ref block, _) => { ExprWhile(ref cond, ref block, _) => {
check_expr(cx, cond, bindings); check_expr(cx, cond, bindings);
check_block(cx, block, bindings); check_block(cx, block, bindings);
} },
ExprMatch(ref init, ref arms, _) => { ExprMatch(ref init, ref arms, _) => {
check_expr(cx, init, bindings); check_expr(cx, init, bindings);
let len = bindings.len(); let len = bindings.len();
@ -329,7 +314,7 @@ fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings:
bindings.truncate(len); bindings.truncate(len);
} }
} }
} },
_ => (), _ => (),
} }
} }
@ -341,14 +326,14 @@ fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty, bindings: &mut V
TyArray(ref fty, ref expr) => { TyArray(ref fty, ref expr) => {
check_ty(cx, fty, bindings); check_ty(cx, fty, bindings);
check_expr(cx, expr, bindings); check_expr(cx, expr, bindings);
} },
TyPtr(MutTy { ty: ref mty, .. }) | TyPtr(MutTy { ty: ref mty, .. }) |
TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings), TyRptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings),
TyTup(ref tup) => { TyTup(ref tup) => {
for t in tup { for t in tup {
check_ty(cx, t, bindings) check_ty(cx, t, bindings)
} }
} },
TyTypeof(ref expr) => check_expr(cx, expr, bindings), TyTypeof(ref expr) => check_expr(cx, expr, bindings),
_ => (), _ => (),
} }
@ -360,7 +345,7 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool {
ExprAddrOf(_, ref inner) => is_self_shadow(name, inner), ExprAddrOf(_, ref inner) => is_self_shadow(name, inner),
ExprBlock(ref block) => { ExprBlock(ref block) => {
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e)) block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e))
} },
ExprUnary(op, ref inner) => (UnDeref == op) && is_self_shadow(name, inner), ExprUnary(op, ref inner) => (UnDeref == op) && is_self_shadow(name, inner),
ExprPath(QPath::Resolved(_, ref path)) => path_eq_name(name, path), ExprPath(QPath::Resolved(_, ref path)) => path_eq_name(name, path),
_ => false, _ => false,

View file

@ -122,7 +122,7 @@ fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool {
ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left), ExprBinary(Spanned { node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
ExprBlock(ref block) => { ExprBlock(ref block) => {
block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target)) block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
} },
_ => false, _ => false,
} }
} }

View file

@ -46,7 +46,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if is_temporary(base) && !is_adjusted(cx, base) { if is_temporary(base) && !is_adjusted(cx, base) {
span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary"); span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary");
} }
} },
_ => (), _ => (),
} }
} }

View file

@ -95,14 +95,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
let to_ty = cx.tcx.tables().expr_ty(e); let to_ty = cx.tcx.tables().expr_ty(e);
match (&from_ty.sty, &to_ty.sty) { match (&from_ty.sty, &to_ty.sty) {
_ if from_ty == to_ty => span_lint( _ if from_ty == to_ty => {
cx, span_lint(cx,
USELESS_TRANSMUTE, USELESS_TRANSMUTE,
e.span, e.span,
&format!("transmute from a type (`{}`) to itself", from_ty), &format!("transmute from a type (`{}`) to itself", from_ty))
), },
(&TyRef(_, rty), &TyRawPtr(ptr_ty)) => span_lint_and_then( (&TyRef(_, rty), &TyRawPtr(ptr_ty)) => {
cx, span_lint_and_then(cx,
USELESS_TRANSMUTE, USELESS_TRANSMUTE,
e.span, e.span,
"transmute from a reference to a pointer", "transmute from a reference to a pointer",
@ -116,11 +116,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
db.span_suggestion(e.span, "try", sugg.to_string()); db.span_suggestion(e.span, "try", sugg.to_string());
} }
})
}, },
),
(&ty::TyInt(_), &TyRawPtr(_)) | (&ty::TyInt(_), &TyRawPtr(_)) |
(&ty::TyUint(_), &TyRawPtr(_)) => span_lint_and_then( (&ty::TyUint(_), &TyRawPtr(_)) => {
cx, span_lint_and_then(cx,
USELESS_TRANSMUTE, USELESS_TRANSMUTE,
e.span, e.span,
"transmute from an integer to a pointer", "transmute from an integer to a pointer",
@ -128,33 +128,33 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) { if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string()); db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string());
} }
})
}, },
),
(&ty::TyFloat(_), &TyRef(..)) | (&ty::TyFloat(_), &TyRef(..)) |
(&ty::TyFloat(_), &TyRawPtr(_)) | (&ty::TyFloat(_), &TyRawPtr(_)) |
(&ty::TyChar, &TyRef(..)) | (&ty::TyChar, &TyRef(..)) |
(&ty::TyChar, &TyRawPtr(_)) => span_lint( (&ty::TyChar, &TyRawPtr(_)) => {
cx, span_lint(cx,
WRONG_TRANSMUTE, WRONG_TRANSMUTE,
e.span, e.span,
&format!("transmute from a `{}` to a pointer", from_ty), &format!("transmute from a `{}` to a pointer", from_ty))
), },
(&TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint( (&TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => {
cx, span_lint(cx,
CROSSPOINTER_TRANSMUTE, CROSSPOINTER_TRANSMUTE,
e.span, e.span,
&format!("transmute from a type (`{}`) to the type that it points to (`{}`)", &format!("transmute from a type (`{}`) to the type that it points to (`{}`)",
from_ty, from_ty,
to_ty), to_ty))
), },
(_, &TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint( (_, &TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => {
cx, span_lint(cx,
CROSSPOINTER_TRANSMUTE, CROSSPOINTER_TRANSMUTE,
e.span, e.span,
&format!("transmute from a type (`{}`) to a pointer to that type (`{}`)", &format!("transmute from a type (`{}`) to a pointer to that type (`{}`)",
from_ty, from_ty,
to_ty), to_ty))
), },
(&TyRawPtr(from_pty), &TyRef(_, to_rty)) => span_lint_and_then( (&TyRawPtr(from_pty), &TyRef(_, to_rty)) => span_lint_and_then(
cx, cx,
TRANSMUTE_PTR_TO_REF, TRANSMUTE_PTR_TO_REF,

View file

@ -6,8 +6,8 @@ use rustc::ty;
use std::cmp::Ordering; use std::cmp::Ordering;
use syntax::ast::{IntTy, UintTy, FloatTy}; use syntax::ast::{IntTy, UintTy, FloatTy};
use syntax::codemap::Span; use syntax::codemap::Span;
use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, use utils::{comparisons, higher, in_external_macro, in_macro, match_def_path, snippet, span_help_and_lint, span_lint,
span_help_and_lint, span_lint, opt_def_id, last_path_segment}; opt_def_id, last_path_segment};
use utils::paths; use utils::paths;
/// Handles all the linting of funky types /// Handles all the linting of funky types
@ -141,7 +141,7 @@ fn check_let_unit(cx: &LateContext, decl: &Decl) {
decl.span, decl.span,
&format!("this let-binding has unit value. Consider omitting `let {} =`", &format!("this let-binding has unit value. Consider omitting `let {} =`",
snippet(cx, local.pat.span, ".."))); snippet(cx, local.pat.span, "..")));
} },
_ => (), _ => (),
} }
} }
@ -211,8 +211,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
&format!("{}-comparison of unit values detected. This will always be {}", &format!("{}-comparison of unit values detected. This will always be {}",
op.as_str(), op.as_str(),
result)); result));
} },
_ => () _ => (),
} }
} }
} }
@ -336,11 +336,7 @@ fn is_isize_or_usize(typ: &ty::TyS) -> bool {
} }
fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to_f64: bool) { fn span_precision_loss_lint(cx: &LateContext, expr: &Expr, cast_from: &ty::TyS, cast_to_f64: bool) {
let mantissa_nbits = if cast_to_f64 { let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
52
} else {
23
};
let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
let arch_dependent_str = "on targets with 64-bit wide pointers "; let arch_dependent_str = "on targets with 64-bit wide pointers ";
let from_nbits_str = if arch_dependent { let from_nbits_str = if arch_dependent {
@ -388,7 +384,7 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::
ArchSuffix::None, ArchSuffix::None,
to_nbits == from_nbits && cast_unsigned_to_signed, to_nbits == from_nbits && cast_unsigned_to_signed,
ArchSuffix::None) ArchSuffix::None)
} },
(true, false) => { (true, false) => {
(to_nbits <= 32, (to_nbits <= 32,
if to_nbits == 32 { if to_nbits == 32 {
@ -398,7 +394,7 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::
}, },
to_nbits <= 32 && cast_unsigned_to_signed, to_nbits <= 32 && cast_unsigned_to_signed,
ArchSuffix::_32) ArchSuffix::_32)
} },
(false, true) => { (false, true) => {
(from_nbits == 64, (from_nbits == 64,
ArchSuffix::_32, ArchSuffix::_32,
@ -408,7 +404,7 @@ fn check_truncation_and_wrapping(cx: &LateContext, expr: &Expr, cast_from: &ty::
} else { } else {
ArchSuffix::_32 ArchSuffix::_32
}) })
} },
}; };
if span_truncation { if span_truncation {
span_lint(cx, span_lint(cx,
@ -463,7 +459,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
if is_isize_or_usize(cast_from) || from_nbits >= to_nbits { if is_isize_or_usize(cast_from) || from_nbits >= to_nbits {
span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64); span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64);
} }
} },
(false, true) => { (false, true) => {
span_lint(cx, span_lint(cx,
CAST_POSSIBLE_TRUNCATION, CAST_POSSIBLE_TRUNCATION,
@ -475,7 +471,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
expr.span, expr.span,
&format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to));
} }
} },
(true, true) => { (true, true) => {
if cast_from.is_signed() && !cast_to.is_signed() { if cast_from.is_signed() && !cast_to.is_signed() {
span_lint(cx, span_lint(cx,
@ -484,16 +480,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
&format!("casting {} to {} may lose the sign of the value", cast_from, cast_to)); &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to));
} }
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, if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) =
&cast_to.sty) { (&cast_from.sty, &cast_to.sty) {
span_lint(cx, span_lint(cx,
CAST_POSSIBLE_TRUNCATION, CAST_POSSIBLE_TRUNCATION,
expr.span, expr.span,
"casting f64 to f32 may truncate the value"); "casting f64 to f32 may truncate the value");
} }
} },
} }
} }
} }
@ -536,7 +532,8 @@ impl LintPass for TypeComplexityPass {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass {
fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, _: FnKind<'tcx>, decl: &'tcx FnDecl, _: &'tcx Expr, _: Span, _: NodeId) { fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, _: FnKind<'tcx>, decl: &'tcx FnDecl, _: &'tcx Expr, _: Span,
_: NodeId) {
self.check_fndecl(cx, decl); self.check_fndecl(cx, decl);
} }
@ -629,10 +626,7 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for TypeComplexityVisitor<'a, 'tcx> {
TyInfer | TyPtr(..) | TyRptr(..) => (1, 0), TyInfer | TyPtr(..) | TyRptr(..) => (1, 0),
// the "normal" components of a type: named types, arrays/tuples // the "normal" components of a type: named types, arrays/tuples
TyPath(..) | TyPath(..) | TySlice(..) | TyTup(..) | TyArray(..) => (10 * self.nest, 1),
TySlice(..) |
TyTup(..) |
TyArray(..) => (10 * self.nest, 1),
// "Sum" of trait bounds // "Sum" of trait bounds
TyObjectSum(..) => (20 * self.nest, 0), TyObjectSum(..) => (20 * self.nest, 0),
@ -775,7 +769,7 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs
(_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min (_, Some(r @ ExtremeExpr { which: Minimum, .. })) => (r, AlwaysFalse), // x < min
_ => return None, _ => return None,
} }
} },
Rel::Le => { Rel::Le => {
match (lx, rx) { match (lx, rx) {
(Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x (Some(l @ ExtremeExpr { which: Minimum, .. }), _) => (l, AlwaysTrue), // min <= x
@ -784,7 +778,7 @@ fn detect_absurd_comparison<'a>(cx: &LateContext, op: BinOp_, lhs: &'a Expr, rhs
(_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max (_, Some(r @ ExtremeExpr { which: Maximum, .. })) => (r, AlwaysTrue), // x <= max
_ => return None, _ => return None,
} }
} },
Rel::Ne | Rel::Eq => return None, Rel::Ne | Rel::Eq => return None,
}) })
} }
@ -864,7 +858,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons {
instead", instead",
snippet(cx, lhs.span, "lhs"), snippet(cx, lhs.span, "lhs"),
snippet(cx, rhs.span, "rhs")) snippet(cx, rhs.span, "rhs"))
} },
}; };
let help = format!("because {} is the {} value for this type, {}", let help = format!("because {} is the {} value for this type, {}",
@ -967,7 +961,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)), IntTy::I64 => (FullInt::S(i64::min_value() as i64), FullInt::S(i64::max_value() as i64)),
IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)), IntTy::Is => (FullInt::S(isize::min_value() as i64), FullInt::S(isize::max_value() as i64)),
}) })
} },
TyUint(uint_ty) => { TyUint(uint_ty) => {
Some(match uint_ty { Some(match uint_ty {
UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)), UintTy::U8 => (FullInt::U(u8::min_value() as u64), FullInt::U(u8::max_value() as u64)),
@ -976,7 +970,7 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext, expr: &'a Expr) -> Option<(
UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)), UintTy::U64 => (FullInt::U(u64::min_value() as u64), FullInt::U(u64::max_value() as u64)),
UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)), UintTy::Us => (FullInt::U(usize::min_value() as u64), FullInt::U(usize::max_value() as u64)),
}) })
} },
_ => None, _ => None,
} }
} else { } else {
@ -1001,7 +995,7 @@ fn node_as_const_fullint(cx: &LateContext, expr: &Expr) -> Option<FullInt> {
} else { } else {
None None
} }
} },
Err(_) => None, Err(_) => None,
} }
} }
@ -1036,14 +1030,14 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
} else { } else {
ub < norm_rhs_val ub < norm_rhs_val
} }
} },
Rel::Le => { Rel::Le => {
if invert { if invert {
norm_rhs_val <= lb norm_rhs_val <= lb
} else { } else {
ub <= norm_rhs_val ub <= norm_rhs_val
} }
} },
Rel::Eq | Rel::Ne => unreachable!(), Rel::Eq | Rel::Ne => unreachable!(),
} { } {
err_upcast_comparison(cx, span, lhs, true) err_upcast_comparison(cx, span, lhs, true)
@ -1054,14 +1048,14 @@ fn upcast_comparison_bounds_err(cx: &LateContext, span: &Span, rel: comparisons:
} else { } else {
lb >= norm_rhs_val lb >= norm_rhs_val
} }
} },
Rel::Le => { Rel::Le => {
if invert { if invert {
norm_rhs_val > ub norm_rhs_val > ub
} else { } else {
lb > norm_rhs_val lb > norm_rhs_val
} }
} },
Rel::Eq | Rel::Ne => unreachable!(), Rel::Eq | Rel::Ne => unreachable!(),
} { } {
err_upcast_comparison(cx, span, lhs, false) err_upcast_comparison(cx, span, lhs, false)

View file

@ -38,15 +38,14 @@ impl EarlyLintPass for UnsafeNameRemoval {
if let ItemKind::Use(ref item_use) = item.node { if let ItemKind::Use(ref item_use) = item.node {
match item_use.node { match item_use.node {
ViewPath_::ViewPathSimple(ref name, ref path) => { ViewPath_::ViewPathSimple(ref name, ref path) => {
unsafe_to_safe_check( unsafe_to_safe_check(path.segments
path.segments
.last() .last()
.expect("use paths cannot be empty") .expect("use paths cannot be empty")
.identifier, .identifier,
*name, *name,
cx, &item.span cx,
); &item.span);
} },
ViewPath_::ViewPathList(_, ref path_list_items) => { ViewPath_::ViewPathList(_, ref path_list_items) => {
for path_list_item in path_list_items.iter() { for path_list_item in path_list_items.iter() {
let plid = path_list_item.node; let plid = path_list_item.node;
@ -54,8 +53,8 @@ impl EarlyLintPass for UnsafeNameRemoval {
unsafe_to_safe_check(plid.name, rename, cx, &item.span); unsafe_to_safe_check(plid.name, rename, cx, &item.span);
}; };
} }
} },
ViewPath_::ViewPathGlob(_) => {} ViewPath_::ViewPathGlob(_) => {},
} }
} }
} }
@ -68,11 +67,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext, spa
span_lint(cx, span_lint(cx,
UNSAFE_REMOVED_FROM_NAME, UNSAFE_REMOVED_FROM_NAME,
*span, *span,
&format!( &format!("removed \"unsafe\" from the name of `{}` in use as `{}`", old_str, new_str));
"removed \"unsafe\" from the name of `{}` in use as `{}`",
old_str,
new_str
));
} }
} }

View file

@ -41,15 +41,8 @@ impl LintPass for UnusedLabel {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel {
fn check_fn( fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, kind: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
&mut self, body: &'tcx hir::Expr, span: Span, fn_id: ast::NodeId) {
cx: &LateContext<'a, 'tcx>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Expr,
span: Span,
fn_id: ast::NodeId,
) {
if in_macro(cx, span) { if in_macro(cx, span) {
return; return;
} }
@ -72,11 +65,11 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> {
hir::ExprBreak(Some(label), _) | hir::ExprBreak(Some(label), _) |
hir::ExprAgain(Some(label)) => { hir::ExprAgain(Some(label)) => {
self.labels.remove(&label.name.as_str()); self.labels.remove(&label.name.as_str());
} },
hir::ExprLoop(_, Some(label), _) | hir::ExprLoop(_, Some(label), _) |
hir::ExprWhile(_, _, Some(label)) => { hir::ExprWhile(_, _, Some(label)) => {
self.labels.insert(label.node.as_str(), expr.span); self.labels.insert(label.node.as_str(), expr.span);
} },
_ => (), _ => (),
} }

View file

@ -18,8 +18,7 @@ pub enum Rel {
} }
/// Put the expression in the form `lhs < rhs`, `lhs <= rhs`, `lhs == rhs` or `lhs != rhs`. /// Put the expression in the form `lhs < rhs`, `lhs <= rhs`, `lhs == rhs` or `lhs != rhs`.
pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) pub fn normalize_comparison<'a>(op: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(Rel, &'a Expr, &'a Expr)> {
-> Option<(Rel, &'a Expr, &'a Expr)> {
match op { match op {
BinOp_::BiLt => Some((Rel::Lt, lhs, rhs)), BinOp_::BiLt => Some((Rel::Lt, lhs, rhs)),
BinOp_::BiLe => Some((Rel::Le, lhs, rhs)), BinOp_::BiLe => Some((Rel::Le, lhs, rhs)),

View file

@ -8,21 +8,20 @@ use syntax::{ast, codemap};
use toml; use toml;
/// Get the configuration file from arguments. /// Get the configuration file from arguments.
pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> { pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>])
-> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
for arg in args.iter().filter_map(|a| a.meta_item()) { for arg in args.iter().filter_map(|a| a.meta_item()) {
if arg.name() == "conf_file" { if arg.name() == "conf_file" {
return match arg.node { return match arg.node {
ast::MetaItemKind::Word | ast::MetaItemKind::Word |
ast::MetaItemKind::List(_) => { ast::MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)),
Err(("`conf_file` must be a named value", arg.span))
}
ast::MetaItemKind::NameValue(ref value) => { ast::MetaItemKind::NameValue(ref value) => {
if let ast::LitKind::Str(ref file, _) = value.node { if let ast::LitKind::Str(ref file, _) = value.node {
Ok(Some(file.to_string().into())) Ok(Some(file.to_string().into()))
} else { } else {
Err(("`conf_file` value must be a string", value.span)) Err(("`conf_file` value must be a string", value.span))
} }
} },
}; };
} }
} }
@ -38,14 +37,12 @@ pub enum Error {
/// The file is not valid TOML. /// The file is not valid TOML.
Toml(Vec<toml::ParserError>), Toml(Vec<toml::ParserError>),
/// Type error. /// Type error.
Type( Type(/// The name of the key.
/// The name of the key.
&'static str, &'static str,
/// The expected type. /// The expected type.
&'static str, &'static str,
/// The type we got instead. /// The type we got instead.
&'static str &'static str),
),
/// There is an unknown key is the file. /// There is an unknown key is the file.
UnknownKey(String), UnknownKey(String),
} }
@ -66,10 +63,10 @@ impl fmt::Display for Error {
} }
Ok(()) Ok(())
} },
Error::Type(key, expected, got) => { Error::Type(key, expected, got) => {
write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got) write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
} },
Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key), Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
} }
} }
@ -196,7 +193,7 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
if e.kind() != io::ErrorKind::NotFound { if e.kind() != io::ErrorKind::NotFound {
return Err(e); return Err(e);
} }
} },
_ => (), _ => (),
} }
} }
@ -231,11 +228,11 @@ pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
} }
buf buf
} },
Err(err) => { Err(err) => {
errors.push(err.into()); errors.push(err.into());
return (conf, errors); return (conf, errors);
} },
}; };
let mut parser = toml::Parser::new(&file); let mut parser = toml::Parser::new(&file);

View file

@ -7,15 +7,5 @@
/// See also [the reference][reference-types] for a list of such types. /// See also [the reference][reference-types] for a list of such types.
/// ///
/// [reference-types]: https://doc.rust-lang.org/reference.html#types /// [reference-types]: https://doc.rust-lang.org/reference.html#types
pub const BUILTIN_TYPES: &'static [&'static str] = &[ pub const BUILTIN_TYPES: &'static [&'static str] = &["i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", "isize",
"i8", "u8", "usize", "f32", "f64", "bool", "str", "char"];
"i16", "u16",
"i32", "u32",
"i64", "u64",
"isize", "usize",
"f32",
"f64",
"bool",
"str",
"char",
];

View file

@ -68,7 +68,7 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
} else { } else {
None None
} }
} },
hir::ExprStruct(ref path, ref fields, None) => { hir::ExprStruct(ref path, ref fields, None) => {
if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) { if match_path(path, &paths::RANGE_FROM_STD) || match_path(path, &paths::RANGE_FROM) {
Some(Range { Some(Range {
@ -104,7 +104,7 @@ pub fn range(expr: &hir::Expr) -> Option<Range> {
} else { } else {
None None
} }
} },
_ => None, _ => None,
} }
} }

View file

@ -38,12 +38,11 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
match (&left.node, &right.node) { match (&left.node, &right.node) {
(&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) {
both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && 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
} }
} },
(&StmtExpr(ref l, _), &StmtExpr(ref r, _)) | (&StmtExpr(ref l, _), &StmtExpr(ref r, _)) |
(&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r), (&StmtSemi(ref l, _), &StmtSemi(ref r, _)) => self.eq_expr(l, r),
_ => false, _ => false,
@ -73,64 +72,60 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
(&ExprAssign(ref ll, ref lr), &ExprAssign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr), (&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)
} },
(&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r), (&ExprBlock(ref l), &ExprBlock(ref r)) => self.eq_block(l, r),
(&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => { (&ExprBinary(l_op, ref ll, ref lr), &ExprBinary(r_op, ref rl, ref rr)) => {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) || l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) ||
swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| { swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
}) })
} },
(&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => (&ExprBreak(li, ref le), &ExprBreak(ri, ref re)) => {
both(&li, &ri, |l, r| l.name.as_str() == r.name.as_str()) both(&li, &ri, |l, r| l.name.as_str() == r.name.as_str()) && both(le, re, |l, r| self.eq_expr(l, r))
&& both(le, re, |l, r| self.eq_expr(l, r)), },
(&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r), (&ExprBox(ref l), &ExprBox(ref r)) => self.eq_expr(l, r),
(&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => { (&ExprCall(ref l_fun, ref l_args), &ExprCall(ref r_fun, ref r_args)) => {
!self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
} },
(&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) | (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) |
(&ExprType(ref lx, ref lt), &ExprType(ref rx, ref rt)) => { (&ExprType(ref lx, ref lt), &ExprType(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt),
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
}
(&ExprField(ref l_f_exp, ref l_f_ident), &ExprField(ref r_f_exp, ref r_f_ident)) => { (&ExprField(ref l_f_exp, ref l_f_ident), &ExprField(ref r_f_exp, ref r_f_ident)) => {
l_f_ident.node == r_f_ident.node && self.eq_expr(l_f_exp, r_f_exp) l_f_ident.node == r_f_ident.node && self.eq_expr(l_f_exp, r_f_exp)
} },
(&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), (&ExprIndex(ref la, ref li), &ExprIndex(ref ra, ref 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_block(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r)) self.eq_expr(lc, rc) && 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, ref lls), &ExprLoop(ref rb, ref rl, ref rls)) => { (&ExprLoop(ref lb, ref ll, ref lls), &ExprLoop(ref rb, ref rl, ref rls)) => {
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str()) lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.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 && self.eq_expr(le, re) && ls == rs && self.eq_expr(le, re) &&
over(la, ra, |l, r| { over(la, ra, |l, r| {
self.eq_expr(&l.body, &r.body) && self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(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)) over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
}) })
} },
(&ExprMethodCall(ref l_name, ref l_tys, ref l_args), (&ExprMethodCall(ref l_name, ref l_tys, ref l_args),
&ExprMethodCall(ref r_name, ref r_tys, ref r_args)) => { &ExprMethodCall(ref r_name, ref r_tys, ref r_args)) => {
!self.ignore_fn && l_name.node == r_name.node && !self.ignore_fn && l_name.node == r_name.node && over(l_tys, r_tys, |l, r| self.eq_ty(l, r)) &&
over(l_tys, r_tys, |l, r| self.eq_ty(l, r)) &&
self.eq_exprs(l_args, r_args) self.eq_exprs(l_args, r_args)
} },
(&ExprRepeat(ref le, ref ll), &ExprRepeat(ref re, ref rl)) => self.eq_expr(le, re) && self.eq_expr(ll, rl), (&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)), (&ExprRet(ref l), &ExprRet(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r), (&ExprPath(ref l), &ExprPath(ref r)) => self.eq_qpath(l, r),
(&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => { (&ExprStruct(ref l_path, ref lf, ref lo), &ExprStruct(ref r_path, ref rf, ref ro)) => {
self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) && self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) &&
over(lf, rf, |l, r| self.eq_field(l, r)) over(lf, rf, |l, r| self.eq_field(l, r))
} },
(&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup), (&ExprTup(ref l_tup), &ExprTup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
(&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re), (&ExprTupField(ref le, li), &ExprTupField(ref re, ri)) => li.node == ri.node && self.eq_expr(le, re),
(&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re), (&ExprUnary(l_op, ref le), &ExprUnary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
(&ExprArray(ref l), &ExprArray(ref r)) => self.eq_exprs(l, r), (&ExprArray(ref l), &ExprArray(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_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str()) self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.node.as_str() == r.node.as_str())
} },
_ => false, _ => false,
} }
} }
@ -153,23 +148,23 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => { (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
} },
(&PatKind::Binding(ref lb, _, ref li, ref lp), &PatKind::Binding(ref rb, _, ref ri, ref rp)) => { (&PatKind::Binding(ref lb, _, ref li, ref lp), &PatKind::Binding(ref rb, _, ref ri, ref rp)) => {
lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r)) lb == rb && li.node.as_str() == ri.node.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
} },
(&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r), (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(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::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => { (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
ls == rs && over(l, r, |l, r| self.eq_pat(l, r)) ls == rs && 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(le, re) self.eq_expr(ls, rs) && 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::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => { (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |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)) &&
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,
} }
@ -188,8 +183,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
} }
fn eq_path(&self, left: &Path, right: &Path) -> bool { fn eq_path(&self, left: &Path, right: &Path) -> bool {
left.global == right.global && left.global == right.global && over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
} }
fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool { fn eq_path_parameters(&self, left: &PathParameters, right: &PathParameters) -> bool {
@ -198,35 +192,30 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) && over(&left.lifetimes, &right.lifetimes, |l, r| self.eq_lifetime(l, r)) &&
over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) && over(&left.types, &right.types, |l, r| self.eq_ty(l, r)) &&
over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r)) over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
} },
(&ParenthesizedParameters(ref left), &ParenthesizedParameters(ref right)) => { (&ParenthesizedParameters(ref left), &ParenthesizedParameters(ref right)) => {
over(&left.inputs, &right.inputs, |l, r| self.eq_ty(l, r)) && over(&left.inputs, &right.inputs, |l, r| self.eq_ty(l, r)) &&
both(&left.output, &right.output, |l, r| self.eq_ty(l, r)) both(&left.output, &right.output, |l, r| self.eq_ty(l, r))
} },
(&AngleBracketedParameters(_), &ParenthesizedParameters(_)) | (&AngleBracketedParameters(_), &ParenthesizedParameters(_)) |
(&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => { (&ParenthesizedParameters(_), &AngleBracketedParameters(_)) => false,
false
}
} }
} }
fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool { fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool {
// The == of idents doesn't work with different contexts, // The == of idents doesn't work with different contexts,
// we have to be explicit about hygiene // we have to be explicit about hygiene
left.name.as_str() == right.name.as_str() && left.name.as_str() == right.name.as_str() && self.eq_path_parameters(&left.parameters, &right.parameters)
self.eq_path_parameters(&left.parameters, &right.parameters)
} }
fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { fn eq_ty(&self, left: &Ty, right: &Ty) -> bool {
match (&left.node, &right.node) { match (&left.node, &right.node) {
(&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec), (&TySlice(ref l_vec), &TySlice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
(&TyArray(ref lt, ref ll), &TyArray(ref rt, ref rl)) => { (&TyArray(ref lt, ref ll), &TyArray(ref rt, ref rl)) => self.eq_ty(lt, rt) && self.eq_expr(ll, rl),
self.eq_ty(lt, rt) && self.eq_expr(ll, rl)
}
(&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty), (&TyPtr(ref l_mut), &TyPtr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
(&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => { (&TyRptr(_, ref l_rmut), &TyRptr(_, ref r_rmut)) => {
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty) l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
} },
(&TyPath(ref l), &TyPath(ref r)) => self.eq_qpath(l, r), (&TyPath(ref l), &TyPath(ref r)) => self.eq_qpath(l, r),
(&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyTup(ref l), &TyTup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
(&TyInfer, &TyInfer) => true, (&TyInfer, &TyInfer) => true,
@ -241,13 +230,7 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> {
fn swap_binop<'a>(binop: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOp_, &'a Expr, &'a Expr)> { fn swap_binop<'a>(binop: BinOp_, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOp_, &'a Expr, &'a Expr)> {
match binop { match binop {
BiAdd | BiAdd | BiMul | BiBitXor | BiBitAnd | BiEq | BiNe | BiBitOr => Some((binop, rhs, lhs)),
BiMul |
BiBitXor |
BiBitAnd |
BiEq |
BiNe |
BiBitOr => Some((binop, rhs, lhs)),
BiLt => Some((BiGt, rhs, lhs)), BiLt => Some((BiGt, rhs, lhs)),
BiLe => Some((BiGe, rhs, lhs)), BiLe => Some((BiGe, rhs, lhs)),
BiGe => Some((BiLe, rhs, lhs)), BiGe => Some((BiLe, rhs, lhs)),
@ -316,39 +299,39 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
c.hash(&mut self.s); c.hash(&mut self.s);
m.hash(&mut self.s); m.hash(&mut self.s);
self.hash_expr(e); self.hash_expr(e);
} },
ExprAgain(i) => { ExprAgain(i) => {
let c: fn(_) -> _ = ExprAgain; let c: fn(_) -> _ = ExprAgain;
c.hash(&mut self.s); c.hash(&mut self.s);
if let Some(i) = i { if let Some(i) = i {
self.hash_name(&i.name); self.hash_name(&i.name);
} }
} },
ExprAssign(ref l, ref r) => { ExprAssign(ref l, ref r) => {
let c: fn(_, _) -> _ = ExprAssign; let c: fn(_, _) -> _ = ExprAssign;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(l); self.hash_expr(l);
self.hash_expr(r); self.hash_expr(r);
} },
ExprAssignOp(ref o, ref l, ref r) => { ExprAssignOp(ref o, ref l, ref r) => {
let c: fn(_, _, _) -> _ = ExprAssignOp; let c: fn(_, _, _) -> _ = ExprAssignOp;
c.hash(&mut self.s); c.hash(&mut self.s);
o.hash(&mut self.s); o.hash(&mut self.s);
self.hash_expr(l); self.hash_expr(l);
self.hash_expr(r); self.hash_expr(r);
} },
ExprBlock(ref b) => { ExprBlock(ref b) => {
let c: fn(_) -> _ = ExprBlock; let c: fn(_) -> _ = ExprBlock;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_block(b); self.hash_block(b);
} },
ExprBinary(op, ref l, ref r) => { ExprBinary(op, ref l, ref r) => {
let c: fn(_, _, _) -> _ = ExprBinary; let c: fn(_, _, _) -> _ = ExprBinary;
c.hash(&mut self.s); c.hash(&mut self.s);
op.node.hash(&mut self.s); op.node.hash(&mut self.s);
self.hash_expr(l); self.hash_expr(l);
self.hash_expr(r); self.hash_expr(r);
} },
ExprBreak(i, ref j) => { ExprBreak(i, ref j) => {
let c: fn(_, _) -> _ = ExprBreak; let c: fn(_, _) -> _ = ExprBreak;
c.hash(&mut self.s); c.hash(&mut self.s);
@ -358,46 +341,46 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
if let Some(ref j) = *j { if let Some(ref j) = *j {
self.hash_expr(&*j); self.hash_expr(&*j);
} }
} },
ExprBox(ref e) => { ExprBox(ref e) => {
let c: fn(_) -> _ = ExprBox; let c: fn(_) -> _ = ExprBox;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(e); self.hash_expr(e);
} },
ExprCall(ref fun, ref args) => { ExprCall(ref fun, ref args) => {
let c: fn(_, _) -> _ = ExprCall; let c: fn(_, _) -> _ = ExprCall;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(fun); self.hash_expr(fun);
self.hash_exprs(args); self.hash_exprs(args);
} },
ExprCast(ref e, ref _ty) => { ExprCast(ref e, ref _ty) => {
let c: fn(_, _) -> _ = ExprCast; let c: fn(_, _) -> _ = ExprCast;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(e); self.hash_expr(e);
// TODO: _ty // TODO: _ty
} },
ExprClosure(cap, _, eid, _) => { ExprClosure(cap, _, eid, _) => {
let c: fn(_, _, _, _) -> _ = ExprClosure; let c: fn(_, _, _, _) -> _ = ExprClosure;
c.hash(&mut self.s); c.hash(&mut self.s);
cap.hash(&mut self.s); cap.hash(&mut self.s);
self.hash_expr(self.cx.tcx.map.expr(eid)); self.hash_expr(self.cx.tcx.map.expr(eid));
} },
ExprField(ref e, ref f) => { ExprField(ref e, ref f) => {
let c: fn(_, _) -> _ = ExprField; let c: fn(_, _) -> _ = ExprField;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(e); self.hash_expr(e);
self.hash_name(&f.node); self.hash_name(&f.node);
} },
ExprIndex(ref a, ref i) => { ExprIndex(ref a, ref i) => {
let c: fn(_, _) -> _ = ExprIndex; let c: fn(_, _) -> _ = ExprIndex;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(a); self.hash_expr(a);
self.hash_expr(i); self.hash_expr(i);
} },
ExprInlineAsm(..) => { ExprInlineAsm(..) => {
let c: fn(_, _, _) -> _ = ExprInlineAsm; let c: fn(_, _, _) -> _ = ExprInlineAsm;
c.hash(&mut self.s); c.hash(&mut self.s);
} },
ExprIf(ref cond, ref t, ref e) => { ExprIf(ref cond, ref t, ref e) => {
let c: fn(_, _, _) -> _ = ExprIf; let c: fn(_, _, _) -> _ = ExprIf;
c.hash(&mut self.s); c.hash(&mut self.s);
@ -406,12 +389,12 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
if let Some(ref e) = *e { if let Some(ref e) = *e {
self.hash_expr(e); self.hash_expr(e);
} }
} },
ExprLit(ref l) => { ExprLit(ref l) => {
let c: fn(_) -> _ = ExprLit; let c: fn(_) -> _ = ExprLit;
c.hash(&mut self.s); c.hash(&mut self.s);
l.hash(&mut self.s); l.hash(&mut self.s);
} },
ExprLoop(ref b, ref i, _) => { ExprLoop(ref b, ref i, _) => {
let c: fn(_, _, _) -> _ = ExprLoop; let c: fn(_, _, _) -> _ = ExprLoop;
c.hash(&mut self.s); c.hash(&mut self.s);
@ -419,7 +402,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
if let Some(i) = *i { if let Some(i) = *i {
self.hash_name(&i.node); self.hash_name(&i.node);
} }
} },
ExprMatch(ref e, ref arms, ref s) => { ExprMatch(ref e, ref arms, ref s) => {
let c: fn(_, _, _) -> _ = ExprMatch; let c: fn(_, _, _) -> _ = ExprMatch;
c.hash(&mut self.s); c.hash(&mut self.s);
@ -434,31 +417,31 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
} }
s.hash(&mut self.s); s.hash(&mut self.s);
} },
ExprMethodCall(ref name, ref _tys, ref args) => { ExprMethodCall(ref name, ref _tys, ref args) => {
let c: fn(_, _, _) -> _ = ExprMethodCall; let c: fn(_, _, _) -> _ = ExprMethodCall;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_name(&name.node); self.hash_name(&name.node);
self.hash_exprs(args); self.hash_exprs(args);
} },
ExprRepeat(ref e, ref l) => { ExprRepeat(ref e, ref l) => {
let c: fn(_, _) -> _ = ExprRepeat; let c: fn(_, _) -> _ = ExprRepeat;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(e); self.hash_expr(e);
self.hash_expr(l); self.hash_expr(l);
} },
ExprRet(ref e) => { ExprRet(ref e) => {
let c: fn(_) -> _ = ExprRet; let c: fn(_) -> _ = ExprRet;
c.hash(&mut self.s); c.hash(&mut self.s);
if let Some(ref e) = *e { if let Some(ref e) = *e {
self.hash_expr(e); self.hash_expr(e);
} }
} },
ExprPath(ref qpath) => { ExprPath(ref qpath) => {
let c: fn(_) -> _ = ExprPath; let c: fn(_) -> _ = ExprPath;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_qpath(qpath); self.hash_qpath(qpath);
} },
ExprStruct(ref path, ref fields, ref expr) => { ExprStruct(ref path, ref fields, ref expr) => {
let c: fn(_, _, _) -> _ = ExprStruct; let c: fn(_, _, _) -> _ = ExprStruct;
c.hash(&mut self.s); c.hash(&mut self.s);
@ -473,38 +456,38 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
if let Some(ref e) = *expr { if let Some(ref e) = *expr {
self.hash_expr(e); self.hash_expr(e);
} }
} },
ExprTup(ref tup) => { ExprTup(ref tup) => {
let c: fn(_) -> _ = ExprTup; let c: fn(_) -> _ = ExprTup;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_exprs(tup); self.hash_exprs(tup);
} },
ExprTupField(ref le, li) => { ExprTupField(ref le, li) => {
let c: fn(_, _) -> _ = ExprTupField; let c: fn(_, _) -> _ = ExprTupField;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(le); self.hash_expr(le);
li.node.hash(&mut self.s); li.node.hash(&mut self.s);
} },
ExprType(ref e, ref _ty) => { ExprType(ref e, ref _ty) => {
let c: fn(_, _) -> _ = ExprType; let c: fn(_, _) -> _ = ExprType;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(e); self.hash_expr(e);
// TODO: _ty // TODO: _ty
} },
ExprUnary(lop, ref le) => { ExprUnary(lop, ref le) => {
let c: fn(_, _) -> _ = ExprUnary; let c: fn(_, _) -> _ = ExprUnary;
c.hash(&mut self.s); c.hash(&mut self.s);
lop.hash(&mut self.s); lop.hash(&mut self.s);
self.hash_expr(le); self.hash_expr(le);
} },
ExprArray(ref v) => { ExprArray(ref v) => {
let c: fn(_) -> _ = ExprArray; let c: fn(_) -> _ = ExprArray;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_exprs(v); self.hash_exprs(v);
} },
ExprWhile(ref cond, ref b, l) => { ExprWhile(ref cond, ref b, l) => {
let c: fn(_, _, _) -> _ = ExprWhile; let c: fn(_, _, _) -> _ = ExprWhile;
c.hash(&mut self.s); c.hash(&mut self.s);
@ -514,7 +497,7 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
if let Some(l) = l { if let Some(l) = l {
self.hash_name(&l.node); self.hash_name(&l.node);
} }
} },
} }
} }
@ -532,12 +515,12 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
match *p { match *p {
QPath::Resolved(_, ref path) => { QPath::Resolved(_, ref path) => {
self.hash_path(path); self.hash_path(path);
} },
QPath::TypeRelative(_, ref path) => { QPath::TypeRelative(_, ref path) => {
self.hash_name(&path.name); self.hash_name(&path.name);
},
} }
} // self.cx.tcx.tables().qpath_def(p, id).hash(&mut self.s);
//self.cx.tcx.tables().qpath_def(p, id).hash(&mut self.s);
} }
pub fn hash_path(&mut self, p: &Path) { pub fn hash_path(&mut self, p: &Path) {
@ -558,17 +541,17 @@ impl<'a, 'tcx: 'a> SpanlessHash<'a, 'tcx> {
self.hash_expr(init); self.hash_expr(init);
} }
} }
} },
StmtExpr(ref expr, _) => { StmtExpr(ref expr, _) => {
let c: fn(_, _) -> _ = StmtExpr; let c: fn(_, _) -> _ = StmtExpr;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(expr); self.hash_expr(expr);
} },
StmtSemi(ref expr, _) => { StmtSemi(ref expr, _) => {
let c: fn(_, _) -> _ = StmtSemi; let c: fn(_, _) -> _ = StmtSemi;
c.hash(&mut self.s); c.hash(&mut self.s);
self.hash_expr(expr); self.hash_expr(expr);
} },
} }
} }
} }

View file

@ -67,25 +67,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
hir::ImplItemKind::Type(_) => println!("associated type"), hir::ImplItemKind::Type(_) => println!("associated type"),
} }
} }
/* // fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { // if !has_attr(&item.attrs) {
if !has_attr(&item.attrs) { // return;
return; // }
} // }
} //
// fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: &hir::Generics) {
fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, _: &hir::Generics) { // if !has_attr(&var.node.attrs) {
if !has_attr(&var.node.attrs) { // return;
return; // }
} // }
} //
// fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) { // if !has_attr(&field.attrs) {
if !has_attr(&field.attrs) { // return;
return; // }
} // }
} //
*/
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
if !has_attr(&expr.attrs) { if !has_attr(&expr.attrs) {
@ -115,17 +114,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
match stmt.node { match stmt.node {
hir::StmtDecl(ref decl, _) => print_decl(cx, decl), hir::StmtDecl(ref decl, _) => print_decl(cx, decl),
hir::StmtExpr(ref e, _) | hir::StmtSemi(ref e, _) => print_expr(cx, e, 0), hir::StmtExpr(ref e, _) |
hir::StmtSemi(ref e, _) => print_expr(cx, e, 0),
} }
} }
/* // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) {
// if !has_attr(&item.attrs) {
fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) { // return;
if !has_attr(&item.attrs) { // }
return; // }
} //
}
*/
} }
fn has_attr(attrs: &[Attribute]) -> bool { fn has_attr(attrs: &[Attribute]) -> bool {
@ -282,7 +280,7 @@ fn print_expr(cx: &LateContext, expr: &hir::Expr, indent: usize) {
hir::ExprPath(hir::QPath::TypeRelative(ref ty, ref seg)) => { hir::ExprPath(hir::QPath::TypeRelative(ref ty, ref seg)) => {
println!("{}Relative Path, {:?}", ind, ty); println!("{}Relative Path, {:?}", ind, ty);
println!("{}seg: {:?}", ind, seg); println!("{}seg: {:?}", ind, seg);
} },
hir::ExprAddrOf(ref muta, ref e) => { hir::ExprAddrOf(ref muta, ref e) => {
println!("{}AddrOf, {}", ind, ty); println!("{}AddrOf, {}", ind, ty);
println!("mutability: {:?}", muta); println!("mutability: {:?}", muta);
@ -356,7 +354,7 @@ fn print_item(cx: &LateContext, item: &hir::Item) {
} else { } else {
println!("weird extern crate without a crate id"); println!("weird extern crate without a crate id");
} }
} },
hir::ItemUse(ref path, ref kind) => println!("{:?}, {:?}", path, kind), hir::ItemUse(ref path, ref kind) => println!("{:?}, {:?}", path, kind),
hir::ItemStatic(..) => println!("static item of type {:#?}", cx.tcx.item_type(did)), hir::ItemStatic(..) => println!("static item of type {:#?}", cx.tcx.item_type(did)),
hir::ItemConst(..) => println!("const item of type {:#?}", cx.tcx.item_type(did)), hir::ItemConst(..) => println!("const item of type {:#?}", cx.tcx.item_type(did)),

View file

@ -75,8 +75,8 @@ impl EarlyLintPass for Clippy {
span_lint(cx, span_lint(cx,
CLIPPY_LINTS_INTERNAL, CLIPPY_LINTS_INTERNAL,
item.span, item.span,
"this constant should be before the previous constant due to lexical ordering", "this constant should be before the previous constant due to lexical \
); ordering");
} }
} }
last_name = Some(name); last_name = Some(name);
@ -110,7 +110,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
if is_lint_ref_type(ty) { if is_lint_ref_type(ty) {
self.declared_lints.insert(item.name, item.span); self.declared_lints.insert(item.name, item.span);
} else if is_lint_array_type(ty) && item.vis == Visibility::Inherited && item.name == "ARRAY" { } else if is_lint_array_type(ty) && item.vis == Visibility::Inherited && item.name == "ARRAY" {
let mut collector = LintCollector { output: &mut self.registered_lints, cx: cx }; let mut collector = LintCollector {
output: &mut self.registered_lints,
cx: cx,
};
collector.visit_expr(expr); collector.visit_expr(expr);
} }
} }

View file

@ -95,7 +95,8 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
} }
/// Returns true if this `expn_info` was expanded by any macro. /// Returns true if this `expn_info` was expanded by any macro.
pub fn in_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool { pub fn in_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool {
cx.sess().codemap().with_expn_info(span.expn_id, |info| match info { cx.sess().codemap().with_expn_info(span.expn_id, |info| {
match info {
Some(info) => { Some(info) => {
match info.callee.format { match info.callee.format {
// don't treat range expressions desugared to structs as "in_macro" // don't treat range expressions desugared to structs as "in_macro"
@ -104,6 +105,7 @@ pub fn in_macro<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool {
} }
}, },
None => false, None => false,
}
}) })
} }
@ -160,8 +162,7 @@ pub fn match_def_path(cx: &LateContext, def_id: DefId, path: &[&str]) -> bool {
cx.tcx.push_item_path(&mut apb, def_id); cx.tcx.push_item_path(&mut apb, def_id);
apb.names.len() == path.len() && apb.names.len() == path.len() && apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b)
apb.names.iter().zip(path.iter()).all(|(a, &b)| &**a == b)
} }
/// Check if type is struct, enum or union type with given def path. /// Check if type is struct, enum or union type with given def path.
@ -208,9 +209,11 @@ pub fn match_trait_method(cx: &LateContext, expr: &Expr, path: &[&str]) -> bool
pub fn last_path_segment(path: &QPath) -> &PathSegment { pub fn last_path_segment(path: &QPath) -> &PathSegment {
match *path { match *path {
QPath::Resolved(_, ref path) => path.segments QPath::Resolved(_, ref path) => {
path.segments
.last() .last()
.expect("A path must have at least one segment"), .expect("A path must have at least one segment")
},
QPath::TypeRelative(_, ref seg) => seg, QPath::TypeRelative(_, ref seg) => seg,
} }
} }
@ -232,13 +235,14 @@ pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> {
pub fn match_path(path: &QPath, segments: &[&str]) -> bool { pub fn match_path(path: &QPath, segments: &[&str]) -> bool {
match *path { match *path {
QPath::Resolved(_, ref path) => match_path_old(path, segments), QPath::Resolved(_, ref path) => match_path_old(path, segments),
QPath::TypeRelative(ref ty, ref segment) => match ty.node { QPath::TypeRelative(ref ty, ref segment) => {
match ty.node {
TyPath(ref inner_path) => { TyPath(ref inner_path) => {
segments.len() > 0 && segments.len() > 0 && match_path(inner_path, &segments[..(segments.len() - 1)]) &&
match_path(inner_path, &segments[..(segments.len() - 1)]) &&
segment.name == segments[segments.len() - 1] segment.name == segments[segments.len() - 1]
}, },
_ => false, _ => false,
}
}, },
} }
} }
@ -265,7 +269,10 @@ pub fn path_to_def(cx: &LateContext, path: &[&str]) -> Option<def::Def> {
let crates = cstore.crates(); let crates = cstore.crates();
let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]); let krate = crates.iter().find(|&&krate| cstore.crate_name(krate) == path[0]);
if let Some(krate) = krate { if let Some(krate) = krate {
let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let krate = DefId {
krate: *krate,
index: CRATE_DEF_INDEX,
};
let mut items = cstore.item_children(krate); let mut items = cstore.item_children(krate);
let mut path_it = path.iter().skip(1).peekable(); let mut path_it = path.iter().skip(1).peekable();
@ -313,11 +320,7 @@ pub fn implements_trait<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>,
let ty = cx.tcx.erase_regions(&ty); let ty = cx.tcx.erase_regions(&ty);
cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), let obligation = cx.tcx.predicate_for_trait_def(traits::ObligationCause::dummy(), trait_id, 0, ty, &ty_params);
trait_id,
0,
ty,
&ty_params);
traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation) traits::SelectionContext::new(&infcx).evaluate_obligation_conservatively(&obligation)
}) })
@ -395,7 +398,8 @@ pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'
/// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`. /// Like `snippet_block`, but add braces if the expr is not an `ExprBlock`.
/// Also takes an `Option<String>` which can be put inside the braces. /// Also takes an `Option<String>` which can be put inside the braces.
pub fn expr_block<'a, 'b, T: LintContext<'b>>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str) -> Cow<'a, str> { pub fn expr_block<'a, 'b, T: LintContext<'b>>(cx: &T, expr: &Expr, option: Option<String>, default: &'a str)
-> Cow<'a, str> {
let code = snippet_block(cx, expr.span, default); let code = snippet_block(cx, expr.span, default);
let string = option.unwrap_or_default(); let string = option.unwrap_or_default();
if let ExprBlock(_) = expr.node { if let ExprBlock(_) = expr.node {
@ -476,7 +480,7 @@ pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeI
ExprBlock(ref block) => Some(block), ExprBlock(ref block) => Some(block),
_ => None, _ => None,
} }
} },
_ => None, _ => None,
} }
} else { } else {
@ -508,7 +512,8 @@ pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: Span,
} }
} }
pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) { pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str,
help: &str) {
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
if cx.current_level(lint) != Level::Allow { if cx.current_level(lint) != Level::Allow {
db.0.help(help); db.0.help(help);
@ -516,14 +521,8 @@ pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, lint: &
} }
} }
pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>( pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str,
cx: &'a T, note_span: Span, note: &str) {
lint: &'static Lint,
span: Span,
msg: &str,
note_span: Span,
note: &str,
) {
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg)); let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
if cx.current_level(lint) != Level::Allow { if cx.current_level(lint) != Level::Allow {
if note_span == span { if note_span == span {
@ -535,7 +534,8 @@ pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
} }
} }
pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str,
f: F)
where F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>) where F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>)
{ {
let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)); let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
@ -709,11 +709,7 @@ pub fn camel_case_until(s: &str) -> usize {
return i; return i;
} }
} }
if up { if up { last_i } else { s.len() }
last_i
} else {
s.len()
}
} }
/// Return index of the last camel-case component of `s`. /// Return index of the last camel-case component of `s`.
@ -757,7 +753,8 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> ty::T
/// Check if two types are the same. /// Check if two types are the same.
// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for <'b> Foo<'b>` but // FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for <'b> Foo<'b>` but
// not for type parameters. // not for type parameters.
pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>, parameter_item: NodeId) -> bool { pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty<'tcx>, parameter_item: NodeId)
-> bool {
let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item); let parameter_env = ty::ParameterEnvironment::for_item(cx.tcx, parameter_item);
cx.tcx.infer_ctxt(None, Some(parameter_env), Reveal::All).enter(|infcx| { cx.tcx.infer_ctxt(None, Some(parameter_env), Reveal::All).enter(|infcx| {
let new_a = a.subst(infcx.tcx, infcx.parameter_environment.free_substs); let new_a = a.subst(infcx.tcx, infcx.parameter_environment.free_substs);
@ -786,14 +783,17 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
matches!(cx.tcx.tables().qpath_def(qpath, did), def::Def::Variant(..) | def::Def::VariantCtor(..)) matches!(cx.tcx.tables().qpath_def(qpath, did), def::Def::Variant(..) | def::Def::VariantCtor(..))
} }
fn are_refutable<'a, I: Iterator<Item=&'a Pat>>(cx: &LateContext, mut i: I) -> bool { fn are_refutable<'a, I: Iterator<Item = &'a Pat>>(cx: &LateContext, mut i: I) -> bool {
i.any(|pat| is_refutable(cx, pat)) i.any(|pat| is_refutable(cx, pat))
} }
match pat.node { match pat.node {
PatKind::Binding(..) | PatKind::Wild => false, PatKind::Binding(..) |
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat), PatKind::Wild => false,
PatKind::Lit(..) | PatKind::Range(..) => true, PatKind::Box(ref pat) |
PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
PatKind::Lit(..) |
PatKind::Range(..) => true,
PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.id), PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.id),
PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)), PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
PatKind::Struct(ref qpath, ref fields, _) => { PatKind::Struct(ref qpath, ref fields, _) => {
@ -802,17 +802,17 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
} else { } else {
are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
} }
} },
PatKind::TupleStruct(ref qpath, ref pats, _) => { PatKind::TupleStruct(ref qpath, ref pats, _) => {
if is_enum_variant(cx, qpath, pat.id) { if is_enum_variant(cx, qpath, pat.id) {
true true
} else { } else {
are_refutable(cx, pats.iter().map(|pat| &**pat)) are_refutable(cx, pats.iter().map(|pat| &**pat))
} }
} },
PatKind::Slice(ref head, ref middle, ref tail) => { PatKind::Slice(ref head, ref middle, ref tail) => {
are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)) are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
} },
} }
} }
@ -842,17 +842,26 @@ pub fn remove_blocks(expr: &Expr) -> &Expr {
pub fn opt_def_id(def: Def) -> Option<DefId> { pub fn opt_def_id(def: Def) -> Option<DefId> {
match def { match def {
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | Def::Fn(id) |
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::Mod(id) |
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Static(id, _) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::Variant(id) |
Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => { Def::VariantCtor(id, ..) |
Some(id) Def::Enum(id) |
} Def::TyAlias(id) |
Def::AssociatedTy(id) |
Def::TyParam(id) |
Def::Struct(id) |
Def::StructCtor(id, ..) |
Def::Union(id) |
Def::Trait(id) |
Def::Method(id) |
Def::Const(id) |
Def::AssociatedConst(id) |
Def::Local(id) |
Def::Upvar(id, ..) |
Def::Macro(id) => Some(id),
Def::Label(..) | Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
Def::PrimTy(..) |
Def::SelfTy(..) |
Def::Err => None,
} }
} }

View file

@ -29,9 +29,9 @@ pub const ONE: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("1"));
impl<'a> Display for Sugg<'a> { impl<'a> Display for Sugg<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match *self { match *self {
Sugg::NonParen(ref s) | Sugg::MaybeParen(ref s) | Sugg::BinOp(_, ref s) => { Sugg::NonParen(ref s) |
s.fmt(f) Sugg::MaybeParen(ref s) |
} Sugg::BinOp(_, ref s) => s.fmt(f),
} }
} }
} }
@ -168,10 +168,12 @@ impl<'a> Sugg<'a> {
match self { match self {
Sugg::NonParen(..) => self, Sugg::NonParen(..) => self,
// (x) and (x).y() both don't need additional parens // (x) and (x).y() both don't need additional parens
Sugg::MaybeParen(sugg) => if sugg.starts_with('(') && sugg.ends_with(')') { Sugg::MaybeParen(sugg) => {
if sugg.starts_with('(') && sugg.ends_with(')') {
Sugg::MaybeParen(sugg) Sugg::MaybeParen(sugg)
} else { } else {
Sugg::NonParen(format!("({})", sugg).into()) Sugg::NonParen(format!("({})", sugg).into())
}
}, },
Sugg::BinOp(_, sugg) => Sugg::NonParen(format!("({})", sugg).into()), Sugg::BinOp(_, sugg) => Sugg::NonParen(format!("({})", sugg).into()),
} }
@ -255,10 +257,8 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool { fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
other.precedence() < op.precedence() || other.precedence() < op.precedence() ||
(other.precedence() == op.precedence() && (other.precedence() == op.precedence() &&
((op != other && associativity(op) != dir) || ((op != other && associativity(op) != dir) || (op == other && associativity(op) != Associativity::Both))) ||
(op == other && associativity(op) != Associativity::Both))) || is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op)
is_shift(op) && is_arith(other) ||
is_shift(other) && is_arith(op)
} }
let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs { let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
@ -276,24 +276,12 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> {
let lhs = ParenHelper::new(lhs_paren, lhs); let lhs = ParenHelper::new(lhs_paren, lhs);
let rhs = ParenHelper::new(rhs_paren, rhs); let rhs = ParenHelper::new(rhs_paren, rhs);
let sugg = match op { let sugg = match op {
AssocOp::Add | AssocOp::Add | AssocOp::BitAnd | AssocOp::BitOr | AssocOp::BitXor | AssocOp::Divide | AssocOp::Equal |
AssocOp::BitAnd | AssocOp::Greater | AssocOp::GreaterEqual | AssocOp::LAnd | AssocOp::LOr | AssocOp::Less |
AssocOp::BitOr | AssocOp::LessEqual | AssocOp::Modulus | AssocOp::Multiply | AssocOp::NotEqual | AssocOp::ShiftLeft |
AssocOp::BitXor | AssocOp::ShiftRight | AssocOp::Subtract => {
AssocOp::Divide | format!("{} {} {}", lhs, op.to_ast_binop().expect("Those are AST ops").to_string(), rhs)
AssocOp::Equal | },
AssocOp::Greater |
AssocOp::GreaterEqual |
AssocOp::LAnd |
AssocOp::LOr |
AssocOp::Less |
AssocOp::LessEqual |
AssocOp::Modulus |
AssocOp::Multiply |
AssocOp::NotEqual |
AssocOp::ShiftLeft |
AssocOp::ShiftRight |
AssocOp::Subtract => format!("{} {} {}", lhs, op.to_ast_binop().expect("Those are AST ops").to_string(), rhs),
AssocOp::Inplace => format!("in ({}) {}", lhs, rhs), AssocOp::Inplace => format!("in ({}) {}", lhs, rhs),
AssocOp::Assign => format!("{} = {}", lhs, rhs), AssocOp::Assign => format!("{} = {}", lhs, rhs),
AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, binop_to_string(op), rhs), AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, binop_to_string(op), rhs),
@ -335,11 +323,10 @@ fn associativity(op: &AssocOp) -> Associativity {
match *op { match *op {
Inplace | Assign | AssignOp(_) => Associativity::Right, Inplace | Assign | AssignOp(_) => Associativity::Right,
Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
As | Colon => Associativity::Both, Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight |
Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | Subtract => Associativity::Left,
ShiftRight | Subtract => Associativity::Left, DotDot | DotDotDot => Associativity::None,
DotDot | DotDotDot => Associativity::None
} }
} }
@ -413,7 +400,7 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
/// ```rust /// ```rust
/// db.suggest_item_with_attr(cx, item, "#[derive(Default)]"); /// db.suggest_item_with_attr(cx, item, "#[derive(Default)]");
/// ``` /// ```
fn suggest_item_with_attr<D: Display+?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D); fn suggest_item_with_attr<D: Display + ?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D);
/// Suggest to add an item before another. /// Suggest to add an item before another.
/// ///
@ -431,12 +418,9 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
} }
impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> { impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
fn suggest_item_with_attr<D: Display+?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D) { fn suggest_item_with_attr<D: Display + ?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D) {
if let Some(indent) = indentation(cx, item) { if let Some(indent) = indentation(cx, item) {
let span = Span { let span = Span { hi: item.lo, ..item };
hi: item.lo,
..item
};
self.span_suggestion(span, msg, format!("{}\n{}", attr, indent)); self.span_suggestion(span, msg, format!("{}\n{}", attr, indent));
} }
@ -444,20 +428,19 @@ impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_error
fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str) { fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str) {
if let Some(indent) = indentation(cx, item) { if let Some(indent) = indentation(cx, item) {
let span = Span { let span = Span { hi: item.lo, ..item };
hi: item.lo,
..item
};
let mut first = true; let mut first = true;
let new_item = new_item.lines().map(|l| { let new_item = new_item.lines()
.map(|l| {
if first { if first {
first = false; first = false;
format!("{}\n", l) format!("{}\n", l)
} else { } else {
format!("{}{}\n", indent, l) format!("{}{}\n", indent, l)
} }
}).collect::<String>(); })
.collect::<String>();
self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent)); self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent));
} }

View file

@ -65,7 +65,7 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
} else { } else {
return; return;
} }
} },
higher::VecArgs::Vec(args) => { higher::VecArgs::Vec(args) => {
if let Some(last) = args.iter().last() { if let Some(last) = args.iter().last() {
let span = Span { let span = Span {
@ -78,7 +78,7 @@ fn check_vec_macro(cx: &LateContext, vec_args: &higher::VecArgs, span: Span) {
} else { } else {
"&[]".into() "&[]".into()
} }
} },
}; };
span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| { span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| {