@@ -7,14 +7,13 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
77use rustc_lint:: { LateContext , LateLintPass } ;
88use rustc_middle:: ty:: { self , Ty } ;
99use rustc_session:: impl_lint_pass;
10- use rustc_span:: source_map:: Spanned ;
1110use rustc_span:: symbol:: sym;
1211use rustc_span:: { Span , Symbol } ;
1312use { rustc_ast as ast, rustc_hir as hir} ;
1413
1514const HARD_CODED_ALLOWED_BINARY : & [ [ & str ; 2 ] ] = & [ [ "f32" , "f32" ] , [ "f64" , "f64" ] , [ "std::string::String" , "str" ] ] ;
1615const HARD_CODED_ALLOWED_UNARY : & [ & str ] = & [ "f32" , "f64" , "std::num::Saturating" , "std::num::Wrapping" ] ;
17- const INTEGER_METHODS : & [ Symbol ] = & [
16+ const DISALLOWED_INT_METHODS : & [ Symbol ] = & [
1817 sym:: saturating_div,
1918 sym:: wrapping_div,
2019 sym:: wrapping_rem,
@@ -27,8 +26,8 @@ pub struct ArithmeticSideEffects {
2726 allowed_unary : FxHashSet < String > ,
2827 // Used to check whether expressions are constants, such as in enum discriminants and consts
2928 const_span : Option < Span > ,
29+ disallowed_int_methods : FxHashSet < Symbol > ,
3030 expr_span : Option < Span > ,
31- integer_methods : FxHashSet < Symbol > ,
3231}
3332
3433impl_lint_pass ! ( ArithmeticSideEffects => [ ARITHMETIC_SIDE_EFFECTS ] ) ;
@@ -53,8 +52,8 @@ impl ArithmeticSideEffects {
5352 allowed_binary,
5453 allowed_unary,
5554 const_span : None ,
55+ disallowed_int_methods : DISALLOWED_INT_METHODS . iter ( ) . copied ( ) . collect ( ) ,
5656 expr_span : None ,
57- integer_methods : INTEGER_METHODS . iter ( ) . copied ( ) . collect ( ) ,
5857 }
5958 }
6059
@@ -91,10 +90,10 @@ impl ArithmeticSideEffects {
9190 fn has_specific_allowed_type_and_operation < ' tcx > (
9291 cx : & LateContext < ' tcx > ,
9392 lhs_ty : Ty < ' tcx > ,
94- op : & Spanned < hir:: BinOpKind > ,
93+ op : hir:: BinOpKind ,
9594 rhs_ty : Ty < ' tcx > ,
9695 ) -> 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 ) ;
9897 let is_non_zero_u = |cx : & LateContext < ' tcx > , ty : Ty < ' tcx > | {
9998 let tcx = cx. tcx ;
10099
@@ -166,21 +165,43 @@ impl ArithmeticSideEffects {
166165 None
167166 }
168167
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+
169190 /// 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.
171192 fn manage_bin_ops < ' tcx > (
172193 & mut self ,
173194 cx : & LateContext < ' tcx > ,
174195 expr : & ' tcx hir:: Expr < ' _ > ,
175- op : & Spanned < hir:: BinOpKind > ,
196+ op : hir:: BinOpKind ,
176197 lhs : & ' tcx hir:: Expr < ' _ > ,
177198 rhs : & ' tcx hir:: Expr < ' _ > ,
178199 ) {
179200 if constant_simple ( cx, cx. typeck_results ( ) , expr) . is_some ( ) {
180201 return ;
181202 }
182203 if !matches ! (
183- op. node ,
204+ op,
184205 hir:: BinOpKind :: Add
185206 | hir:: BinOpKind :: Div
186207 | hir:: BinOpKind :: Mul
@@ -204,7 +225,7 @@ impl ArithmeticSideEffects {
204225 return ;
205226 }
206227 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 {
208229 // At least for integers, shifts are already handled by the CTFE
209230 return ;
210231 }
@@ -213,7 +234,7 @@ impl ArithmeticSideEffects {
213234 Self :: literal_integer ( cx, actual_rhs) ,
214235 ) {
215236 ( None , None ) => false ,
216- ( None , Some ( n) ) => match ( & op. node , n) {
237+ ( None , Some ( n) ) => match ( & op, n) {
217238 // Division and module are always valid if applied to non-zero integers
218239 ( hir:: BinOpKind :: Div | hir:: BinOpKind :: Rem , local_n) if local_n != 0 => true ,
219240 // Adding or subtracting zeros is always a no-op
@@ -223,7 +244,7 @@ impl ArithmeticSideEffects {
223244 => true ,
224245 _ => false ,
225246 } ,
226- ( Some ( n) , None ) => match ( & op. node , n) {
247+ ( Some ( n) , None ) => match ( & op, n) {
227248 // Adding or subtracting zeros is always a no-op
228249 ( hir:: BinOpKind :: Add | hir:: BinOpKind :: Sub , 0 )
229250 // Multiplication by 1 or 0 will never overflow
@@ -249,6 +270,7 @@ impl ArithmeticSideEffects {
249270 & mut self ,
250271 args : & ' tcx [ hir:: Expr < ' _ > ] ,
251272 cx : & LateContext < ' tcx > ,
273+ expr : & ' tcx hir:: Expr < ' _ > ,
252274 ps : & ' tcx hir:: PathSegment < ' _ > ,
253275 receiver : & ' tcx hir:: Expr < ' _ > ,
254276 ) {
@@ -262,7 +284,8 @@ impl ArithmeticSideEffects {
262284 if !Self :: is_integral ( instance_ty) {
263285 return ;
264286 }
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 ) {
266289 return ;
267290 }
268291 let ( actual_arg, _) = peel_hir_expr_refs ( arg) ;
@@ -310,10 +333,10 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
310333 }
311334 match & expr. kind {
312335 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) ;
314337 } ,
315338 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) ;
317340 } ,
318341 hir:: ExprKind :: Unary ( un_op, un_expr) => {
319342 self . manage_unary_ops ( cx, expr, un_expr, * un_op) ;
0 commit comments