Merge pull request #2413 from flip1995/assign_ops
Improved suggestion on misrefactored_assign_op lint
This commit is contained in:
commit
ee8d32850d
3 changed files with 154 additions and 31 deletions
|
|
@ -1,4 +1,5 @@
|
|||
use rustc::hir;
|
||||
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use rustc::lint::*;
|
||||
use syntax::ast;
|
||||
use utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
|
||||
|
|
@ -87,19 +88,29 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
|
|||
});
|
||||
if let hir::ExprBinary(binop, ref l, ref r) = rhs.node {
|
||||
if op.node == binop.node {
|
||||
let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
|
||||
let lint = |assignee: &hir::Expr, rhs_other: &hir::Expr| {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MISREFACTORED_ASSIGN_OP,
|
||||
expr.span,
|
||||
"variable appears on both sides of an assignment operation",
|
||||
|db| if let (Some(snip_a), Some(snip_r)) =
|
||||
(snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
|
||||
(snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span))
|
||||
{
|
||||
let a = &sugg::Sugg::hir(cx, assignee, "..");
|
||||
let r = &sugg::Sugg::hir(cx, rhs, "..");
|
||||
let long = format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r));
|
||||
db.span_suggestion(
|
||||
expr.span,
|
||||
"replace it with",
|
||||
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
|
||||
&format!("Did you mean {} = {} {} {} or {}? Consider replacing it with",
|
||||
snip_a, snip_a, op.node.as_str(), snip_r,
|
||||
long),
|
||||
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)
|
||||
);
|
||||
db.span_suggestion(
|
||||
expr.span,
|
||||
"or",
|
||||
long
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
@ -189,23 +200,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
|
|||
);
|
||||
}
|
||||
};
|
||||
// a = a op b
|
||||
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) {
|
||||
lint(assignee, r);
|
||||
}
|
||||
// a = b commutative_op a
|
||||
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) {
|
||||
match op.node {
|
||||
hir::BiAdd |
|
||||
hir::BiMul |
|
||||
hir::BiAnd |
|
||||
hir::BiOr |
|
||||
hir::BiBitXor |
|
||||
hir::BiBitAnd |
|
||||
hir::BiBitOr => {
|
||||
lint(assignee, l);
|
||||
},
|
||||
_ => {},
|
||||
|
||||
let mut visitor = ExprVisitor {
|
||||
assignee: assignee,
|
||||
counter: 0,
|
||||
cx: cx
|
||||
};
|
||||
|
||||
walk_expr(&mut visitor, e);
|
||||
|
||||
if visitor.counter == 1 {
|
||||
// a = a op b
|
||||
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) {
|
||||
lint(assignee, r);
|
||||
}
|
||||
// a = b commutative_op a
|
||||
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) {
|
||||
match op.node {
|
||||
hir::BiAdd |
|
||||
hir::BiMul |
|
||||
hir::BiAnd |
|
||||
hir::BiOr |
|
||||
hir::BiBitXor |
|
||||
hir::BiBitAnd |
|
||||
hir::BiBitOr => {
|
||||
lint(assignee, l);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -222,3 +244,22 @@ fn is_commutative(op: hir::BinOp_) -> bool {
|
|||
BiSub | BiDiv | BiRem | BiShl | BiShr | BiLt | BiLe | BiGe | BiGt => false,
|
||||
}
|
||||
}
|
||||
|
||||
struct ExprVisitor<'a, 'tcx: 'a> {
|
||||
assignee: &'a hir::Expr,
|
||||
counter: u8,
|
||||
cx: &'a LateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||
if SpanlessEq::new(self.cx).ignore_fn().eq_expr(self.assignee, &expr) {
|
||||
self.counter += 1;
|
||||
}
|
||||
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue