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 ;
@@ -170,22 +170,20 @@ fn check_gt(
170
170
cx : & LateContext < ' _ > ,
171
171
condition_span : Span ,
172
172
expr_span : Span ,
173
- big_var : & Expr < ' _ > ,
174
- little_var : & Expr < ' _ > ,
173
+ big_expr : & Expr < ' _ > ,
174
+ little_expr : & Expr < ' _ > ,
175
175
if_block : & Expr < ' _ > ,
176
176
else_block : & Expr < ' _ > ,
177
177
msrv : Msrv ,
178
178
is_composited : bool ,
179
179
) {
180
- if let Some ( big_var) = Var :: new ( big_var)
181
- && let Some ( little_var) = Var :: new ( little_var)
182
- {
180
+ if is_side_effect_free ( cx, big_expr) && is_side_effect_free ( cx, little_expr) {
183
181
check_subtraction (
184
182
cx,
185
183
condition_span,
186
184
expr_span,
187
- big_var ,
188
- little_var ,
185
+ big_expr ,
186
+ little_expr ,
189
187
if_block,
190
188
else_block,
191
189
msrv,
@@ -194,27 +192,17 @@ fn check_gt(
194
192
}
195
193
}
196
194
197
- struct Var {
198
- span : Span ,
199
- hir_id : HirId ,
200
- }
201
-
202
- impl Var {
203
- fn new ( expr : & Expr < ' _ > ) -> Option < Self > {
204
- path_to_local ( expr) . map ( |hir_id| Self {
205
- span : expr. span ,
206
- hir_id,
207
- } )
208
- }
195
+ fn is_side_effect_free ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
196
+ eq_expr_value ( cx, expr, expr)
209
197
}
210
198
211
199
#[ allow( clippy:: too_many_arguments) ]
212
200
fn check_subtraction (
213
201
cx : & LateContext < ' _ > ,
214
202
condition_span : Span ,
215
203
expr_span : Span ,
216
- big_var : Var ,
217
- little_var : Var ,
204
+ big_expr : & Expr < ' _ > ,
205
+ little_expr : & Expr < ' _ > ,
218
206
if_block : & Expr < ' _ > ,
219
207
else_block : & Expr < ' _ > ,
220
208
msrv : Msrv ,
@@ -234,8 +222,8 @@ fn check_subtraction(
234
222
cx,
235
223
condition_span,
236
224
expr_span,
237
- little_var ,
238
- big_var ,
225
+ little_expr ,
226
+ big_expr ,
239
227
else_block,
240
228
if_block,
241
229
msrv,
@@ -247,17 +235,15 @@ fn check_subtraction(
247
235
&& let ExprKind :: Binary ( op, left, right) = if_block. kind
248
236
&& let BinOpKind :: Sub = op. node
249
237
{
250
- let local_left = path_to_local ( left) ;
251
- let local_right = path_to_local ( right) ;
252
- if Some ( big_var. hir_id ) == local_left && Some ( little_var. hir_id ) == local_right {
238
+ if eq_expr_value ( cx, left, big_expr) && eq_expr_value ( cx, right, little_expr) {
253
239
// This part of the condition is voluntarily split from the one before to ensure that
254
240
// if `snippet_opt` fails, it won't try the next conditions.
255
- if let Some ( big_var_snippet ) = snippet_opt ( cx, big_var . span )
256
- && let Some ( little_var_snippet ) = snippet_opt ( cx, little_var . span )
257
- && ( ! is_in_const_context ( cx ) || msrv . meets ( cx, msrvs :: SATURATING_SUB_CONST ) )
241
+ if ( ! is_in_const_context ( cx ) || msrv . meets ( cx, msrvs :: SATURATING_SUB_CONST ) )
242
+ && let Some ( big_expr_sugg ) = Sugg :: hir_opt ( cx, big_expr ) . map ( Sugg :: maybe_par )
243
+ && let Some ( little_expr_sugg ) = Sugg :: hir_opt ( cx, little_expr )
258
244
{
259
245
let sugg = format ! (
260
- "{}{big_var_snippet }.saturating_sub({little_var_snippet }){}" ,
246
+ "{}{big_expr_sugg }.saturating_sub({little_expr_sugg }){}" ,
261
247
if is_composited { "{ " } else { "" } ,
262
248
if is_composited { " }" } else { "" }
263
249
) ;
@@ -271,11 +257,12 @@ fn check_subtraction(
271
257
Applicability :: MachineApplicable ,
272
258
) ;
273
259
}
274
- } else if Some ( little_var . hir_id ) == local_left
275
- && Some ( big_var . hir_id ) == local_right
276
- && let Some ( big_var_snippet ) = snippet_opt ( cx, big_var . span )
277
- && let Some ( little_var_snippet ) = snippet_opt ( cx, little_var . span )
260
+ } else if eq_expr_value ( cx , left , little_expr )
261
+ && eq_expr_value ( cx , right , big_expr )
262
+ && let Some ( big_expr_sugg ) = Sugg :: hir_opt ( cx, big_expr )
263
+ && let Some ( little_expr_sugg ) = Sugg :: hir_opt ( cx, little_expr )
278
264
{
265
+ let sugg = make_binop ( BinOpKind :: Sub , & big_expr_sugg, & little_expr_sugg) ;
279
266
span_lint_and_then (
280
267
cx,
281
268
INVERTED_SATURATING_SUB ,
@@ -284,12 +271,12 @@ fn check_subtraction(
284
271
|diag| {
285
272
diag. span_note (
286
273
if_block. span ,
287
- format ! ( "this subtraction underflows when `{little_var_snippet } < {big_var_snippet }`" ) ,
274
+ format ! ( "this subtraction underflows when `{little_expr_sugg } < {big_expr_sugg }`" ) ,
288
275
) ;
289
276
diag. span_suggestion (
290
277
if_block. span ,
291
278
"try replacing it with" ,
292
- format ! ( "{big_var_snippet} - {little_var_snippet }" ) ,
279
+ format ! ( "{sugg }" ) ,
293
280
Applicability :: MaybeIncorrect ,
294
281
) ;
295
282
} ,
0 commit comments