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};
{
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,
- &format!("Did you mean {} = {} {} {} or {} = {}? Consider replacing it with",
+ &format!("Did you mean {} = {} {} {} or {}? Consider replacing it with",
snip_a, snip_a, op.node.as_str(), snip_r,
- snip_a, sugg::make_binop(higher::binop(op.node), a, r)),
+ long),
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r)
);
+ db.span_suggestion(
+ expr.span,
+ "or",
+ long
+ );
},
);
};
);
}
};
- // 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);
+ },
+ _ => {},
+ }
}
}
}
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
+ }
+}
|
8 | a += 1;
| ^^^^^^
+help: or
+ |
+8 | a = a + a + 1;
+ | ^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:9:5
|
9 | a += 1;
| ^^^^^^
+help: or
+ |
+9 | a = a + 1 + a;
+ | ^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:10:5
|
10 | a -= 1;
| ^^^^^^
+help: or
+ |
+10 | a = a - (a - 1);
+ | ^^^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:11:5
|
11 | a *= 99;
| ^^^^^^^
+help: or
+ |
+11 | a = a * a * 99;
+ | ^^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:12:5
|
12 | a *= 42;
| ^^^^^^^
+help: or
+ |
+12 | a = a * 42 * a;
+ | ^^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:13:5
|
13 | a /= 2;
| ^^^^^^
+help: or
+ |
+13 | a = a / (a / 2);
+ | ^^^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:14:5
|
14 | a %= 5;
| ^^^^^^
+help: or
+ |
+14 | a = a % (a % 5);
+ | ^^^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:15:5
|
15 | a &= 1;
| ^^^^^^
+help: or
+ |
+15 | a = a & a & 1;
+ | ^^^^^^^^^^^^^
error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:16:5
|
16 | a *= a;
| ^^^^^^
+help: or
+ |
+16 | a = a * a * a;
+ | ^^^^^^^^^^^^^
error: aborting due to 9 previous errors