1
1
use clippy_config:: Conf ;
2
2
use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_and_then} ;
3
3
use clippy_utils:: msrvs:: { self , Msrv } ;
4
- use clippy_utils:: source :: snippet_opt ;
4
+ use clippy_utils:: sugg :: { Sugg , make_binop } ;
5
5
use clippy_utils:: {
6
- SpanlessEq , higher, is_in_const_context, is_integer_literal, path_to_local , peel_blocks, peel_blocks_with_stmt,
6
+ SpanlessEq , eq_expr_value , higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt,
7
7
} ;
8
8
use rustc_ast:: ast:: LitKind ;
9
9
use rustc_data_structures:: packed:: Pu128 ;
10
10
use rustc_errors:: Applicability ;
11
- use rustc_hir:: { BinOp , BinOpKind , Expr , ExprKind , HirId , QPath } ;
11
+ use rustc_hir:: { BinOp , BinOpKind , Expr , ExprKind , QPath } ;
12
12
use rustc_lint:: { LateContext , LateLintPass } ;
13
13
use rustc_session:: impl_lint_pass;
14
14
use rustc_span:: Span ;
@@ -174,22 +174,20 @@ fn check_gt(
174
174
cx : & LateContext < ' _ > ,
175
175
condition_span : Span ,
176
176
expr_span : Span ,
177
- big_var : & Expr < ' _ > ,
178
- little_var : & Expr < ' _ > ,
177
+ big_expr : & Expr < ' _ > ,
178
+ little_expr : & Expr < ' _ > ,
179
179
if_block : & Expr < ' _ > ,
180
180
else_block : & Expr < ' _ > ,
181
181
msrv : & Msrv ,
182
182
is_composited : bool ,
183
183
) {
184
- if let Some ( big_var) = Var :: new ( big_var)
185
- && let Some ( little_var) = Var :: new ( little_var)
186
- {
184
+ if is_side_effect_free ( cx, big_expr) && is_side_effect_free ( cx, little_expr) {
187
185
check_subtraction (
188
186
cx,
189
187
condition_span,
190
188
expr_span,
191
- big_var ,
192
- little_var ,
189
+ big_expr ,
190
+ little_expr ,
193
191
if_block,
194
192
else_block,
195
193
msrv,
@@ -198,27 +196,18 @@ fn check_gt(
198
196
}
199
197
}
200
198
201
- struct Var {
202
- span : Span ,
203
- hir_id : HirId ,
204
- }
205
-
206
- impl Var {
207
- fn new ( expr : & Expr < ' _ > ) -> Option < Self > {
208
- path_to_local ( expr) . map ( |hir_id| Self {
209
- span : expr. span ,
210
- hir_id,
211
- } )
212
- }
199
+ /// Return the expression if it is side effect free.
200
+ fn is_side_effect_free ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
201
+ eq_expr_value ( cx, expr, expr)
213
202
}
214
203
215
204
#[ allow( clippy:: too_many_arguments) ]
216
205
fn check_subtraction (
217
206
cx : & LateContext < ' _ > ,
218
207
condition_span : Span ,
219
208
expr_span : Span ,
220
- big_var : Var ,
221
- little_var : Var ,
209
+ big_expr : & Expr < ' _ > ,
210
+ little_expr : & Expr < ' _ > ,
222
211
if_block : & Expr < ' _ > ,
223
212
else_block : & Expr < ' _ > ,
224
213
msrv : & Msrv ,
@@ -238,8 +227,8 @@ fn check_subtraction(
238
227
cx,
239
228
condition_span,
240
229
expr_span,
241
- little_var ,
242
- big_var ,
230
+ little_expr ,
231
+ big_expr ,
243
232
else_block,
244
233
if_block,
245
234
msrv,
@@ -251,17 +240,15 @@ fn check_subtraction(
251
240
&& let ExprKind :: Binary ( op, left, right) = if_block. kind
252
241
&& let BinOpKind :: Sub = op. node
253
242
{
254
- let local_left = path_to_local ( left) ;
255
- let local_right = path_to_local ( right) ;
256
- if Some ( big_var. hir_id ) == local_left && Some ( little_var. hir_id ) == local_right {
243
+ if eq_expr_value ( cx, left, big_expr) && eq_expr_value ( cx, right, little_expr) {
257
244
// This part of the condition is voluntarily split from the one before to ensure that
258
245
// if `snippet_opt` fails, it won't try the next conditions.
259
- if let Some ( big_var_snippet ) = snippet_opt ( cx, big_var . span )
260
- && let Some ( little_var_snippet ) = snippet_opt ( cx, little_var . span )
261
- && ( ! is_in_const_context ( cx ) || msrv . meets ( msrvs :: SATURATING_SUB_CONST ) )
246
+ if ( ! is_in_const_context ( cx) || msrv . meets ( msrvs :: SATURATING_SUB_CONST ) )
247
+ && let Some ( big_expr_sugg ) = Sugg :: hir_opt ( cx, big_expr ) . map ( Sugg :: maybe_par )
248
+ && let Some ( little_expr_sugg ) = Sugg :: hir_opt ( cx , little_expr )
262
249
{
263
250
let sugg = format ! (
264
- "{}{big_var_snippet }.saturating_sub({little_var_snippet }){}" ,
251
+ "{}{big_expr_sugg }.saturating_sub({little_expr_sugg }){}" ,
265
252
if is_composited { "{ " } else { "" } ,
266
253
if is_composited { " }" } else { "" }
267
254
) ;
@@ -275,11 +262,12 @@ fn check_subtraction(
275
262
Applicability :: MachineApplicable ,
276
263
) ;
277
264
}
278
- } else if Some ( little_var . hir_id ) == local_left
279
- && Some ( big_var . hir_id ) == local_right
280
- && let Some ( big_var_snippet ) = snippet_opt ( cx, big_var . span )
281
- && let Some ( little_var_snippet ) = snippet_opt ( cx, little_var . span )
265
+ } else if eq_expr_value ( cx , left , little_expr )
266
+ && eq_expr_value ( cx , right , big_expr )
267
+ && let Some ( big_expr_sugg ) = Sugg :: hir_opt ( cx, big_expr )
268
+ && let Some ( little_expr_sugg ) = Sugg :: hir_opt ( cx, little_expr )
282
269
{
270
+ let sugg = make_binop ( BinOpKind :: Sub , & big_expr_sugg, & little_expr_sugg) ;
283
271
span_lint_and_then (
284
272
cx,
285
273
INVERTED_SATURATING_SUB ,
@@ -288,12 +276,12 @@ fn check_subtraction(
288
276
|diag| {
289
277
diag. span_note (
290
278
if_block. span ,
291
- format ! ( "this subtraction underflows when `{little_var_snippet } < {big_var_snippet }`" ) ,
279
+ format ! ( "this subtraction underflows when `{little_expr_sugg } < {big_expr_sugg }`" ) ,
292
280
) ;
293
281
diag. span_suggestion (
294
282
if_block. span ,
295
283
"try replacing it with" ,
296
- format ! ( "{big_var_snippet} - {little_var_snippet }" ) ,
284
+ format ! ( "{sugg }" ) ,
297
285
Applicability :: MaybeIncorrect ,
298
286
) ;
299
287
} ,
0 commit comments