11use rustc:: hir:: * ;
22use 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 ) ]
2745pub struct EqOp ;
2846
2947impl LintPass for EqOp {
3048 fn get_lints ( & self ) -> LintArray {
31- lint_array ! ( EQ_OP )
49+ lint_array ! ( EQ_OP , OP_REF )
3250 }
3351}
3452
3553impl < ' 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