3
3
use rustc:: lint:: * ;
4
4
use syntax:: ast:: * ;
5
5
6
- use utils:: span_help_and_lint ;
6
+ use utils:: { span_lint_and_then , snippet_opt } ;
7
7
8
8
/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
9
9
///
@@ -45,6 +45,11 @@ impl LintPass for IntPlusOne {
45
45
// x + 1 <= y
46
46
// x <= y - 1
47
47
48
+ enum Side {
49
+ LHS ,
50
+ RHS ,
51
+ }
52
+
48
53
impl IntPlusOne {
49
54
#[ allow( cast_sign_loss) ]
50
55
fn check_lit ( & self , lit : & Lit , target_value : i128 ) -> bool {
@@ -54,62 +59,125 @@ impl IntPlusOne {
54
59
false
55
60
}
56
61
57
- fn check_binop ( & self , binop : BinOpKind , lhs : & Expr , rhs : & Expr ) -> bool {
62
+ fn check_binop ( & self , cx : & EarlyContext , block : & Expr , binop : BinOpKind , lhs : & Expr , rhs : & Expr ) -> Option < ( bool , Option < String > ) > {
58
63
match ( binop, & lhs. node , & rhs. node ) {
59
64
// case where `x - 1 >= ...` or `-1 + x >= ...`
60
65
( BinOpKind :: Ge , & ExprKind :: Binary ( ref lhskind, ref lhslhs, ref lhsrhs) , _) => {
61
66
match ( lhskind. node , & lhslhs. node , & lhsrhs. node ) {
62
67
// `-1 + x`
63
- ( BinOpKind :: Add , & ExprKind :: Lit ( ref lit) , _) => self . check_lit ( lit, -1 ) ,
68
+ ( BinOpKind :: Add , & ExprKind :: Lit ( ref lit) , _) => {
69
+ let recommendation = self . generate_recommendation ( cx, binop, lhsrhs, rhs, Side :: LHS ) ;
70
+ if self . check_lit ( lit, -1 ) {
71
+ self . emit_warning ( cx, block, recommendation)
72
+ }
73
+ } ,
64
74
// `x - 1`
65
- ( BinOpKind :: Sub , _, & ExprKind :: Lit ( ref lit) ) => self . check_lit ( lit, 1 ) ,
66
- _ => false
75
+ ( BinOpKind :: Sub , _, & ExprKind :: Lit ( ref lit) ) => {
76
+ let recommendation = self . generate_recommendation ( cx, binop, lhslhs, rhs, Side :: LHS ) ;
77
+ if self . check_lit ( lit, 1 ) {
78
+ self . emit_warning ( cx, block, recommendation)
79
+ }
80
+ }
81
+ _ => ( )
67
82
}
68
83
} ,
69
84
// case where `... >= y + 1` or `... >= 1 + y`
70
85
( BinOpKind :: Ge , _, & ExprKind :: Binary ( ref rhskind, ref rhslhs, ref rhsrhs) ) if rhskind. node == BinOpKind :: Add => {
71
86
match ( & rhslhs. node , & rhsrhs. node ) {
72
87
// `y + 1` and `1 + y`
73
- ( & ExprKind :: Lit ( ref lit) , _) |( _, & ExprKind :: Lit ( ref lit) ) => self . check_lit ( lit, 1 ) ,
74
- _ => false
88
+ ( & ExprKind :: Lit ( ref lit) , _) => {
89
+ let recommendation = self . generate_recommendation ( cx, binop, rhsrhs, lhs, Side :: RHS ) ;
90
+ if self . check_lit ( lit, 1 ) {
91
+ self . emit_warning ( cx, block, recommendation)
92
+ }
93
+ } ,
94
+ ( _, & ExprKind :: Lit ( ref lit) ) => {
95
+ let recommendation = self . generate_recommendation ( cx, binop, rhslhs, lhs, Side :: RHS ) ;
96
+ if self . check_lit ( lit, 1 ) {
97
+ self . emit_warning ( cx, block, recommendation)
98
+ }
99
+ } ,
100
+ _ => ( )
75
101
}
76
102
} ,
77
103
// case where `x + 1 <= ...` or `1 + x <= ...`
78
104
( BinOpKind :: Le , & ExprKind :: Binary ( ref lhskind, ref lhslhs, ref lhsrhs) , _) if lhskind. node == BinOpKind :: Add => {
79
105
match ( & lhslhs. node , & lhsrhs. node ) {
80
106
// `1 + x` and `x + 1`
81
- ( & ExprKind :: Lit ( ref lit) , _) |( _, & ExprKind :: Lit ( ref lit) ) => self . check_lit ( lit, 1 ) ,
82
- _ => false
107
+ ( & ExprKind :: Lit ( ref lit) , _) => {
108
+ let recommendation = self . generate_recommendation ( cx, binop, lhsrhs, rhs, Side :: LHS ) ;
109
+ if self . check_lit ( lit, 1 ) {
110
+ self . emit_warning ( cx, block, recommendation)
111
+ }
112
+ } ,
113
+ ( _, & ExprKind :: Lit ( ref lit) ) => {
114
+ let recommendation = self . generate_recommendation ( cx, binop, lhslhs, rhs, Side :: LHS ) ;
115
+ if self . check_lit ( lit, 1 ) {
116
+ self . emit_warning ( cx, block, recommendation)
117
+ }
118
+ } ,
119
+ _ => ( )
83
120
}
84
121
} ,
85
122
// case where `... >= y - 1` or `... >= -1 + y`
86
123
( BinOpKind :: Le , _, & ExprKind :: Binary ( ref rhskind, ref rhslhs, ref rhsrhs) ) => {
87
124
match ( rhskind. node , & rhslhs. node , & rhsrhs. node ) {
88
125
// `-1 + y`
89
- ( BinOpKind :: Add , & ExprKind :: Lit ( ref lit) , _) => self . check_lit ( lit, -1 ) ,
126
+ ( BinOpKind :: Add , & ExprKind :: Lit ( ref lit) , _) => {
127
+ let recommendation = self . generate_recommendation ( cx, binop, rhsrhs, lhs, Side :: RHS ) ;
128
+ if self . check_lit ( lit, -1 ) {
129
+ self . emit_warning ( cx, block, recommendation)
130
+ }
131
+ } ,
90
132
// `y - 1`
91
- ( BinOpKind :: Sub , _, & ExprKind :: Lit ( ref lit) ) => self . check_lit ( lit, 1 ) ,
92
- _ => false
133
+ ( BinOpKind :: Sub , _, & ExprKind :: Lit ( ref lit) ) => {
134
+ let recommendation = self . generate_recommendation ( cx, binop, rhslhs, lhs, Side :: RHS ) ;
135
+ if self . check_lit ( lit, 1 ) {
136
+ self . emit_warning ( cx, block, recommendation)
137
+ }
138
+ } ,
139
+ _ => ( )
93
140
}
94
141
} ,
95
- _ => false
142
+ _ => ( )
96
143
}
97
144
}
98
145
146
+ fn generate_recommendation ( & self , cx : & EarlyContext , binop : BinOpKind , node : & Expr , other_side : & Expr , side : Side ) -> Option < String > {
147
+ let binop_string = match binop {
148
+ BinOpKind :: Ge => ">" ,
149
+ BinOpKind :: Le => "<" ,
150
+ _ => return None
151
+ } ;
152
+ if let Some ( snippet) = snippet_opt ( cx, node. span ) {
153
+ if let Some ( other_side_snippet) = snippet_opt ( cx, other_side. span ) {
154
+ let rec = match side {
155
+ Side :: LHS => Some ( format ! ( "{} {} {}" , snippet, binop_string, other_side_snippet) ) ,
156
+ Side :: RHS => Some ( format ! ( "{} {} {}" , other_side_snippet, binop_string, snippet) ) ,
157
+ } ;
158
+ return rec;
159
+ }
160
+ }
161
+ None
162
+ }
163
+
164
+ fn emit_warning ( & self , cx : & EarlyContext , block : & Expr , recommendation : Option < String > ) {
165
+ if let Some ( rec) = recommendation {
166
+ span_lint_and_then ( cx,
167
+ INT_PLUS_ONE ,
168
+ block. span ,
169
+ "Unnecessary `>= y + 1` or `x - 1 >=`" ,
170
+ |db| {
171
+ db. span_suggestion ( block. span , "change `>= y + 1` to `> y` as shown" , rec) ;
172
+ } ) ;
173
+ }
174
+ }
99
175
}
100
176
101
177
impl EarlyLintPass for IntPlusOne {
102
178
fn check_expr ( & mut self , cx : & EarlyContext , item : & Expr ) {
103
179
if let ExprKind :: Binary ( ref kind, ref lhs, ref rhs) = item. node {
104
- if self . check_binop ( kind. node , lhs, rhs) {
105
- span_help_and_lint (
106
- cx,
107
- INT_PLUS_ONE ,
108
- item. span ,
109
- "Unnecessary `>= y + 1` or `x - 1 >=`" ,
110
- "Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y`" ,
111
- ) ;
112
- }
180
+ self . check_binop ( cx, item, kind. node , lhs, rhs) ;
113
181
}
114
182
}
115
183
}
0 commit comments