1
1
use rustc:: hir:: * ;
2
2
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 ;
4
5
5
6
/// **What it does:** Checks for equal operands to comparison, logical and
6
7
/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
@@ -23,23 +24,91 @@ declare_lint! {
23
24
"equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
24
25
}
25
26
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
+
26
44
#[ derive( Copy , Clone ) ]
27
45
pub struct EqOp ;
28
46
29
47
impl LintPass for EqOp {
30
48
fn get_lints ( & self ) -> LintArray {
31
- lint_array ! ( EQ_OP )
49
+ lint_array ! ( EQ_OP , OP_REF )
32
50
}
33
51
}
34
52
35
53
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for EqOp {
36
54
fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , e : & ' tcx Expr ) {
37
55
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
+ }
43
112
}
44
113
}
45
114
}
0 commit comments