@@ -7,14 +7,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7
7
use rustc_lint:: { LateContext , LateLintPass } ;
8
8
use rustc_middle:: ty:: { self , Ty } ;
9
9
use rustc_session:: impl_lint_pass;
10
- use rustc_span:: source_map:: Spanned ;
11
10
use rustc_span:: symbol:: sym;
12
11
use rustc_span:: { Span , Symbol } ;
13
12
use { rustc_ast as ast, rustc_hir as hir} ;
14
13
15
14
const HARD_CODED_ALLOWED_BINARY : & [ [ & str ; 2 ] ] = & [ [ "f32" , "f32" ] , [ "f64" , "f64" ] , [ "std::string::String" , "str" ] ] ;
16
15
const HARD_CODED_ALLOWED_UNARY : & [ & str ] = & [ "f32" , "f64" , "std::num::Saturating" , "std::num::Wrapping" ] ;
17
- const INTEGER_METHODS : & [ Symbol ] = & [
16
+ const DISALLOWED_INT_METHODS : & [ Symbol ] = & [
18
17
sym:: saturating_div,
19
18
sym:: wrapping_div,
20
19
sym:: wrapping_rem,
@@ -27,8 +26,8 @@ pub struct ArithmeticSideEffects {
27
26
allowed_unary : FxHashSet < String > ,
28
27
// Used to check whether expressions are constants, such as in enum discriminants and consts
29
28
const_span : Option < Span > ,
29
+ disallowed_int_methods : FxHashSet < Symbol > ,
30
30
expr_span : Option < Span > ,
31
- integer_methods : FxHashSet < Symbol > ,
32
31
}
33
32
34
33
impl_lint_pass ! ( ArithmeticSideEffects => [ ARITHMETIC_SIDE_EFFECTS ] ) ;
@@ -53,8 +52,8 @@ impl ArithmeticSideEffects {
53
52
allowed_binary,
54
53
allowed_unary,
55
54
const_span : None ,
55
+ disallowed_int_methods : DISALLOWED_INT_METHODS . iter ( ) . copied ( ) . collect ( ) ,
56
56
expr_span : None ,
57
- integer_methods : INTEGER_METHODS . iter ( ) . copied ( ) . collect ( ) ,
58
57
}
59
58
}
60
59
@@ -91,10 +90,10 @@ impl ArithmeticSideEffects {
91
90
fn has_specific_allowed_type_and_operation < ' tcx > (
92
91
cx : & LateContext < ' tcx > ,
93
92
lhs_ty : Ty < ' tcx > ,
94
- op : & Spanned < hir:: BinOpKind > ,
93
+ op : hir:: BinOpKind ,
95
94
rhs_ty : Ty < ' tcx > ,
96
95
) -> bool {
97
- let is_div_or_rem = matches ! ( op. node , hir:: BinOpKind :: Div | hir:: BinOpKind :: Rem ) ;
96
+ let is_div_or_rem = matches ! ( op, hir:: BinOpKind :: Div | hir:: BinOpKind :: Rem ) ;
98
97
let is_non_zero_u = |cx : & LateContext < ' tcx > , ty : Ty < ' tcx > | {
99
98
let tcx = cx. tcx ;
100
99
@@ -166,21 +165,43 @@ impl ArithmeticSideEffects {
166
165
None
167
166
}
168
167
168
+ /// Methods like `add_assign` are send to their `BinOps` references.
169
+ fn manage_sugar_methods < ' tcx > (
170
+ & mut self ,
171
+ cx : & LateContext < ' tcx > ,
172
+ expr : & ' tcx hir:: Expr < ' _ > ,
173
+ lhs : & ' tcx hir:: Expr < ' _ > ,
174
+ ps : & hir:: PathSegment < ' _ > ,
175
+ rhs : & ' tcx hir:: Expr < ' _ > ,
176
+ ) {
177
+ if ps. ident . name == sym:: add || ps. ident . name == sym:: add_assign {
178
+ self . manage_bin_ops ( cx, expr, hir:: BinOpKind :: Add , lhs, rhs) ;
179
+ } else if ps. ident . name == sym:: div || ps. ident . name == sym:: div_assign {
180
+ self . manage_bin_ops ( cx, expr, hir:: BinOpKind :: Div , lhs, rhs) ;
181
+ } else if ps. ident . name == sym:: mul || ps. ident . name == sym:: mul_assign {
182
+ self . manage_bin_ops ( cx, expr, hir:: BinOpKind :: Mul , lhs, rhs) ;
183
+ } else if ps. ident . name == sym:: rem || ps. ident . name == sym:: rem_assign {
184
+ self . manage_bin_ops ( cx, expr, hir:: BinOpKind :: Rem , lhs, rhs) ;
185
+ } else if ps. ident . name == sym:: sub || ps. ident . name == sym:: sub_assign {
186
+ self . manage_bin_ops ( cx, expr, hir:: BinOpKind :: Sub , lhs, rhs) ;
187
+ }
188
+ }
189
+
169
190
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
170
- /// types, custom allowed types and non-constant operations that won 't overflow are ignored.
191
+ /// types, custom allowed types and non-constant operations that don 't overflow are ignored.
171
192
fn manage_bin_ops < ' tcx > (
172
193
& mut self ,
173
194
cx : & LateContext < ' tcx > ,
174
195
expr : & ' tcx hir:: Expr < ' _ > ,
175
- op : & Spanned < hir:: BinOpKind > ,
196
+ op : hir:: BinOpKind ,
176
197
lhs : & ' tcx hir:: Expr < ' _ > ,
177
198
rhs : & ' tcx hir:: Expr < ' _ > ,
178
199
) {
179
200
if constant_simple ( cx, cx. typeck_results ( ) , expr) . is_some ( ) {
180
201
return ;
181
202
}
182
203
if !matches ! (
183
- op. node ,
204
+ op,
184
205
hir:: BinOpKind :: Add
185
206
| hir:: BinOpKind :: Div
186
207
| hir:: BinOpKind :: Mul
@@ -204,7 +225,7 @@ impl ArithmeticSideEffects {
204
225
return ;
205
226
}
206
227
let has_valid_op = if Self :: is_integral ( lhs_ty) && Self :: is_integral ( rhs_ty) {
207
- if let hir:: BinOpKind :: Shl | hir:: BinOpKind :: Shr = op. node {
228
+ if let hir:: BinOpKind :: Shl | hir:: BinOpKind :: Shr = op {
208
229
// At least for integers, shifts are already handled by the CTFE
209
230
return ;
210
231
}
@@ -213,7 +234,7 @@ impl ArithmeticSideEffects {
213
234
Self :: literal_integer ( cx, actual_rhs) ,
214
235
) {
215
236
( None , None ) => false ,
216
- ( None , Some ( n) ) => match ( & op. node , n) {
237
+ ( None , Some ( n) ) => match ( & op, n) {
217
238
// Division and module are always valid if applied to non-zero integers
218
239
( hir:: BinOpKind :: Div | hir:: BinOpKind :: Rem , local_n) if local_n != 0 => true ,
219
240
// Adding or subtracting zeros is always a no-op
@@ -223,7 +244,7 @@ impl ArithmeticSideEffects {
223
244
=> true ,
224
245
_ => false ,
225
246
} ,
226
- ( Some ( n) , None ) => match ( & op. node , n) {
247
+ ( Some ( n) , None ) => match ( & op, n) {
227
248
// Adding or subtracting zeros is always a no-op
228
249
( hir:: BinOpKind :: Add | hir:: BinOpKind :: Sub , 0 )
229
250
// Multiplication by 1 or 0 will never overflow
@@ -249,6 +270,7 @@ impl ArithmeticSideEffects {
249
270
& mut self ,
250
271
args : & ' tcx [ hir:: Expr < ' _ > ] ,
251
272
cx : & LateContext < ' tcx > ,
273
+ expr : & ' tcx hir:: Expr < ' _ > ,
252
274
ps : & ' tcx hir:: PathSegment < ' _ > ,
253
275
receiver : & ' tcx hir:: Expr < ' _ > ,
254
276
) {
@@ -262,7 +284,8 @@ impl ArithmeticSideEffects {
262
284
if !Self :: is_integral ( instance_ty) {
263
285
return ;
264
286
}
265
- if !self . integer_methods . contains ( & ps. ident . name ) {
287
+ self . manage_sugar_methods ( cx, expr, receiver, ps, arg) ;
288
+ if !self . disallowed_int_methods . contains ( & ps. ident . name ) {
266
289
return ;
267
290
}
268
291
let ( actual_arg, _) = peel_hir_expr_refs ( arg) ;
@@ -310,10 +333,10 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
310
333
}
311
334
match & expr. kind {
312
335
hir:: ExprKind :: AssignOp ( op, lhs, rhs) | hir:: ExprKind :: Binary ( op, lhs, rhs) => {
313
- self . manage_bin_ops ( cx, expr, op, lhs, rhs) ;
336
+ self . manage_bin_ops ( cx, expr, op. node , lhs, rhs) ;
314
337
} ,
315
338
hir:: ExprKind :: MethodCall ( ps, receiver, args, _) => {
316
- self . manage_method_call ( args, cx, ps, receiver) ;
339
+ self . manage_method_call ( args, cx, expr , ps, receiver) ;
317
340
} ,
318
341
hir:: ExprKind :: Unary ( un_op, un_expr) => {
319
342
self . manage_unary_ops ( cx, expr, un_expr, * un_op) ;
0 commit comments