11use clippy_config:: Conf ;
22use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_and_then} ;
33use clippy_utils:: msrvs:: { self , Msrv } ;
4- use clippy_utils:: source :: snippet_opt ;
4+ use clippy_utils:: sugg :: { Sugg , make_binop } ;
55use 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,
77} ;
88use rustc_ast:: ast:: LitKind ;
99use rustc_data_structures:: packed:: Pu128 ;
1010use rustc_errors:: Applicability ;
11- use rustc_hir:: { BinOp , BinOpKind , Expr , ExprKind , HirId , QPath } ;
11+ use rustc_hir:: { BinOp , BinOpKind , Expr , ExprKind , QPath } ;
1212use rustc_lint:: { LateContext , LateLintPass } ;
1313use rustc_session:: impl_lint_pass;
1414use rustc_span:: Span ;
@@ -170,22 +170,20 @@ fn check_gt(
170170 cx : & LateContext < ' _ > ,
171171 condition_span : Span ,
172172 expr_span : Span ,
173- big_var : & Expr < ' _ > ,
174- little_var : & Expr < ' _ > ,
173+ big_expr : & Expr < ' _ > ,
174+ little_expr : & Expr < ' _ > ,
175175 if_block : & Expr < ' _ > ,
176176 else_block : & Expr < ' _ > ,
177177 msrv : Msrv ,
178178 is_composited : bool ,
179179) {
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) {
183181 check_subtraction (
184182 cx,
185183 condition_span,
186184 expr_span,
187- big_var ,
188- little_var ,
185+ big_expr ,
186+ little_expr ,
189187 if_block,
190188 else_block,
191189 msrv,
@@ -194,27 +192,17 @@ fn check_gt(
194192 }
195193}
196194
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)
209197}
210198
211199#[ allow( clippy:: too_many_arguments) ]
212200fn check_subtraction (
213201 cx : & LateContext < ' _ > ,
214202 condition_span : Span ,
215203 expr_span : Span ,
216- big_var : Var ,
217- little_var : Var ,
204+ big_expr : & Expr < ' _ > ,
205+ little_expr : & Expr < ' _ > ,
218206 if_block : & Expr < ' _ > ,
219207 else_block : & Expr < ' _ > ,
220208 msrv : Msrv ,
@@ -234,8 +222,8 @@ fn check_subtraction(
234222 cx,
235223 condition_span,
236224 expr_span,
237- little_var ,
238- big_var ,
225+ little_expr ,
226+ big_expr ,
239227 else_block,
240228 if_block,
241229 msrv,
@@ -247,17 +235,15 @@ fn check_subtraction(
247235 && let ExprKind :: Binary ( op, left, right) = if_block. kind
248236 && let BinOpKind :: Sub = op. node
249237 {
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) {
253239 // This part of the condition is voluntarily split from the one before to ensure that
254240 // 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 )
258244 {
259245 let sugg = format ! (
260- "{}{big_var_snippet }.saturating_sub({little_var_snippet }){}" ,
246+ "{}{big_expr_sugg }.saturating_sub({little_expr_sugg }){}" ,
261247 if is_composited { "{ " } else { "" } ,
262248 if is_composited { " }" } else { "" }
263249 ) ;
@@ -271,11 +257,12 @@ fn check_subtraction(
271257 Applicability :: MachineApplicable ,
272258 ) ;
273259 }
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 )
278264 {
265+ let sugg = make_binop ( BinOpKind :: Sub , & big_expr_sugg, & little_expr_sugg) ;
279266 span_lint_and_then (
280267 cx,
281268 INVERTED_SATURATING_SUB ,
@@ -284,12 +271,12 @@ fn check_subtraction(
284271 |diag| {
285272 diag. span_note (
286273 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 }`" ) ,
288275 ) ;
289276 diag. span_suggestion (
290277 if_block. span ,
291278 "try replacing it with" ,
292- format ! ( "{big_var_snippet} - {little_var_snippet }" ) ,
279+ format ! ( "{sugg }" ) ,
293280 Applicability :: MaybeIncorrect ,
294281 ) ;
295282 } ,
0 commit comments