Skip to content

Commit 5de367f

Browse files
committed
Don't create additional references when invoking binary operators
1 parent 813daf2 commit 5de367f

File tree

1 file changed

+76
-7
lines changed

1 file changed

+76
-7
lines changed

clippy_lints/src/eq_op.rs

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc::hir::*;
22
use rustc::lint::*;
3-
use utils::{SpanlessEq, span_lint};
3+
use utils::{SpanlessEq, span_lint, span_lint_and_then, multispan_sugg, snippet};
4+
use utils::sugg::Sugg;
45

56
/// **What it does:** Checks for equal operands to comparison, logical and
67
/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
@@ -23,23 +24,91 @@ declare_lint! {
2324
"equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
2425
}
2526

27+
/// **What it does:** Checks for arguments to `==` which have their address taken to satisfy a bound
28+
/// and suggests to dereference the other argument instead
29+
///
30+
/// **Why is this bad?** It is more idiomatic to dereference the other argument.
31+
///
32+
/// **Known problems:** None
33+
///
34+
/// **Example:**
35+
/// ```rust
36+
/// &x == y
37+
/// ```
38+
declare_lint! {
39+
pub OP_REF,
40+
Warn,
41+
"taking a reference to satisfy the type constraints on `==`"
42+
}
43+
2644
#[derive(Copy,Clone)]
2745
pub struct EqOp;
2846

2947
impl LintPass for EqOp {
3048
fn get_lints(&self) -> LintArray {
31-
lint_array!(EQ_OP)
49+
lint_array!(EQ_OP, OP_REF)
3250
}
3351
}
3452

3553
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
3654
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
3755
if let ExprBinary(ref op, ref left, ref right) = e.node {
38-
if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
39-
span_lint(cx,
40-
EQ_OP,
41-
e.span,
42-
&format!("equal expressions as operands to `{}`", op.node.as_str()));
56+
if is_valid_operator(op) {
57+
if SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
58+
span_lint(cx,
59+
EQ_OP,
60+
e.span,
61+
&format!("equal expressions as operands to `{}`", op.node.as_str()));
62+
} else {
63+
match (&left.node, &right.node) {
64+
(&ExprAddrOf(_, ref l), &ExprAddrOf(_, ref r)) => {
65+
span_lint_and_then(cx,
66+
OP_REF,
67+
e.span,
68+
"taken reference of both operands, which is done automatically by the operator anyway",
69+
|db| {
70+
let lsnip = snippet(cx, l.span, "...").to_string();
71+
let rsnip = snippet(cx, r.span, "...").to_string();
72+
multispan_sugg(db,
73+
"use the values directly".to_string(),
74+
vec![(left.span, lsnip),
75+
(right.span, rsnip)]);
76+
}
77+
)
78+
}
79+
(&ExprAddrOf(_, ref l), _) => {
80+
span_lint_and_then(cx,
81+
OP_REF,
82+
e.span,
83+
"taken reference of left operand",
84+
|db| {
85+
let lsnip = snippet(cx, l.span, "...").to_string();
86+
let rsnip = Sugg::hir(cx, right, "...").deref().to_string();
87+
multispan_sugg(db,
88+
"dereference the right operand instead".to_string(),
89+
vec![(left.span, lsnip),
90+
(right.span, rsnip)]);
91+
}
92+
)
93+
}
94+
(_, &ExprAddrOf(_, ref r)) => {
95+
span_lint_and_then(cx,
96+
OP_REF,
97+
e.span,
98+
"taken reference of right operand",
99+
|db| {
100+
let lsnip = Sugg::hir(cx, left, "...").deref().to_string();
101+
let rsnip = snippet(cx, r.span, "...").to_string();
102+
multispan_sugg(db,
103+
"dereference the left operand instead".to_string(),
104+
vec![(left.span, lsnip),
105+
(right.span, rsnip)]);
106+
}
107+
)
108+
}
109+
_ => {}
110+
}
111+
}
43112
}
44113
}
45114
}

0 commit comments

Comments
 (0)