@@ -3,12 +3,11 @@ use clippy_config::Conf;
3
3
use clippy_utils:: consts:: { ConstEvalCtxt , Constant } ;
4
4
use clippy_utils:: diagnostics:: span_lint;
5
5
use clippy_utils:: ty:: is_type_diagnostic_item;
6
- use clippy_utils:: { expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary} ;
6
+ use clippy_utils:: { expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, sym } ;
7
7
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
8
8
use rustc_lint:: { LateContext , LateLintPass } ;
9
9
use rustc_middle:: ty:: { self , Ty } ;
10
10
use rustc_session:: impl_lint_pass;
11
- 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
@@ -89,6 +88,18 @@ impl ArithmeticSideEffects {
89
88
self . allowed_unary . contains ( ty_string_elem)
90
89
}
91
90
91
+ fn is_non_zero_u ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> bool {
92
+ if let ty:: Adt ( adt, substs) = ty. kind ( )
93
+ && cx. tcx . is_diagnostic_item ( sym:: NonZero , adt. did ( ) )
94
+ && let int_type = substs. type_at ( 0 )
95
+ && matches ! ( int_type. kind( ) , ty:: Uint ( _) )
96
+ {
97
+ true
98
+ } else {
99
+ false
100
+ }
101
+ }
102
+
92
103
/// Verifies built-in types that have specific allowed operations
93
104
fn has_specific_allowed_type_and_operation < ' tcx > (
94
105
cx : & LateContext < ' tcx > ,
@@ -97,33 +108,12 @@ impl ArithmeticSideEffects {
97
108
rhs_ty : Ty < ' tcx > ,
98
109
) -> bool {
99
110
let is_div_or_rem = matches ! ( op, hir:: BinOpKind :: Div | hir:: BinOpKind :: Rem ) ;
100
- let is_non_zero_u = |cx : & LateContext < ' tcx > , ty : Ty < ' tcx > | {
101
- let tcx = cx. tcx ;
102
-
103
- let ty:: Adt ( adt, substs) = ty. kind ( ) else { return false } ;
104
-
105
- if !tcx. is_diagnostic_item ( sym:: NonZero , adt. did ( ) ) {
106
- return false ;
107
- }
108
-
109
- let int_type = substs. type_at ( 0 ) ;
110
- let unsigned_int_types = [
111
- tcx. types . u8 ,
112
- tcx. types . u16 ,
113
- tcx. types . u32 ,
114
- tcx. types . u64 ,
115
- tcx. types . u128 ,
116
- tcx. types . usize ,
117
- ] ;
118
-
119
- unsigned_int_types. contains ( & int_type)
120
- } ;
121
111
let is_sat_or_wrap = |ty : Ty < ' _ > | {
122
112
is_type_diagnostic_item ( cx, ty, sym:: Saturating ) || is_type_diagnostic_item ( cx, ty, sym:: Wrapping )
123
113
} ;
124
114
125
115
// If the RHS is `NonZero<u*>`, then division or module by zero will never occur.
126
- if is_non_zero_u ( cx, rhs_ty) && is_div_or_rem {
116
+ if Self :: is_non_zero_u ( cx, rhs_ty) && is_div_or_rem {
127
117
return true ;
128
118
}
129
119
@@ -219,6 +209,18 @@ impl ArithmeticSideEffects {
219
209
let ( mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs ( rhs) ;
220
210
actual_lhs = expr_or_init ( cx, actual_lhs) ;
221
211
actual_rhs = expr_or_init ( cx, actual_rhs) ;
212
+
213
+ // `NonZeroU*.get() - 1`, will never overflow
214
+ if let hir:: BinOpKind :: Sub = op
215
+ && let hir:: ExprKind :: MethodCall ( method, receiver, [ ] , _) = actual_lhs. kind
216
+ && method. ident . name == sym:: get
217
+ && let receiver_ty = cx. typeck_results ( ) . expr_ty ( receiver) . peel_refs ( )
218
+ && Self :: is_non_zero_u ( cx, receiver_ty)
219
+ && let Some ( 1 ) = Self :: literal_integer ( cx, actual_rhs)
220
+ {
221
+ return ;
222
+ }
223
+
222
224
let lhs_ty = cx. typeck_results ( ) . expr_ty ( actual_lhs) . peel_refs ( ) ;
223
225
let rhs_ty = cx. typeck_results ( ) . expr_ty_adjusted ( actual_rhs) . peel_refs ( ) ;
224
226
if self . has_allowed_binary ( lhs_ty, rhs_ty) {
@@ -227,6 +229,7 @@ impl ArithmeticSideEffects {
227
229
if Self :: has_specific_allowed_type_and_operation ( cx, lhs_ty, op, rhs_ty) {
228
230
return ;
229
231
}
232
+
230
233
let has_valid_op = if Self :: is_integral ( lhs_ty) && Self :: is_integral ( rhs_ty) {
231
234
if let hir:: BinOpKind :: Shl | hir:: BinOpKind :: Shr = op {
232
235
// At least for integers, shifts are already handled by the CTFE
0 commit comments