2 use rustc_front::hir::*;
3 use rustc_front::util as ast_util;
9 /// **What it does:** This lint checks for equal operands to comparisons and bitwise binary operators (`&`, `|` and `^`). It is `Warn` by default.
11 /// **Why is this bad?** This is usually just a typo.
13 /// **Known problems:** False negatives: We had some false positives regarding calls (notably [racer](https://github.com/phildawes/racer) had one instance of `x.pop() && x.pop()`), so we removed matching any function or method calls. We may introduce a whitelist of known pure functions in the future.
15 /// **Example:** `x + 1 == x + 1`
19 "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
25 impl LintPass for EqOp {
26 fn get_lints(&self) -> LintArray {
31 impl LateLintPass for EqOp {
32 fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
33 if let ExprBinary(ref op, ref left, ref right) = e.node {
34 if is_cmp_or_bit(op) && is_exp_equal(cx, left, right) {
35 span_lint(cx, EQ_OP, e.span, &format!(
36 "equal expressions as operands to {}",
37 ast_util::binop_to_string(op.node)));
43 pub fn is_exp_equal(cx: &LateContext, left : &Expr, right : &Expr) -> bool {
44 if let (Some(l), Some(r)) = (constant(cx, left), constant(cx, right)) {
49 match (&left.node, &right.node) {
50 (&ExprField(ref lfexp, ref lfident),
51 &ExprField(ref rfexp, ref rfident)) =>
52 lfident.node == rfident.node && is_exp_equal(cx, lfexp, rfexp),
53 (&ExprLit(ref l), &ExprLit(ref r)) => l.node == r.node,
54 (&ExprPath(ref lqself, ref lsubpath),
55 &ExprPath(ref rqself, ref rsubpath)) =>
56 both(lqself, rqself, is_qself_equal) &&
57 is_path_equal(lsubpath, rsubpath),
58 (&ExprTup(ref ltup), &ExprTup(ref rtup)) =>
59 is_exps_equal(cx, ltup, rtup),
60 (&ExprVec(ref l), &ExprVec(ref r)) => is_exps_equal(cx, l, r),
61 (&ExprCast(ref lx, ref lt), &ExprCast(ref rx, ref rt)) =>
62 is_exp_equal(cx, lx, rx) && is_cast_ty_equal(lt, rt),
67 fn is_exps_equal(cx: &LateContext, left : &[P<Expr>], right : &[P<Expr>]) -> bool {
68 over(left, right, |l, r| is_exp_equal(cx, l, r))
71 fn is_path_equal(left : &Path, right : &Path) -> bool {
72 // The == of idents doesn't work with different contexts,
73 // we have to be explicit about hygiene
74 left.global == right.global && over(&left.segments, &right.segments,
75 |l, r| l.identifier.name == r.identifier.name
76 && l.parameters == r.parameters)
79 fn is_qself_equal(left : &QSelf, right : &QSelf) -> bool {
80 left.ty.node == right.ty.node && left.position == right.position
83 fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
84 where F: FnMut(&X, &X) -> bool {
85 left.len() == right.len() && left.iter().zip(right).all(|(x, y)|
89 fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn : F) -> bool
90 where F: FnMut(&X, &X) -> bool {
91 l.as_ref().map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false,
95 fn is_cmp_or_bit(op : &BinOp) -> bool {
97 BiEq | BiLt | BiLe | BiGt | BiGe | BiNe | BiAnd | BiOr |
98 BiBitXor | BiBitAnd | BiBitOr => true,
103 fn is_cast_ty_equal(left: &Ty, right: &Ty) -> bool {
104 match (&left.node, &right.node) {
105 (&TyVec(ref lvec), &TyVec(ref rvec)) => is_cast_ty_equal(lvec, rvec),
106 (&TyPtr(ref lmut), &TyPtr(ref rmut)) =>
107 lmut.mutbl == rmut.mutbl &&
108 is_cast_ty_equal(&*lmut.ty, &*rmut.ty),
109 (&TyRptr(_, ref lrmut), &TyRptr(_, ref rrmut)) =>
110 lrmut.mutbl == rrmut.mutbl &&
111 is_cast_ty_equal(&*lrmut.ty, &*rrmut.ty),
112 (&TyPath(ref lq, ref lpath), &TyPath(ref rq, ref rpath)) =>
113 both(lq, rq, is_qself_equal) && is_path_equal(lpath, rpath),
114 (&TyInfer, &TyInfer) => true,