@@ -2,19 +2,19 @@ use crate::consts::{
2
2
constant, Constant ,
3
3
Constant :: { F32 , F64 } ,
4
4
} ;
5
- use crate :: utils:: { span_lint_and_sugg, sugg} ;
5
+ use crate :: utils:: { higher , span_lint_and_sugg, sugg, SpanlessEq } ;
6
6
use if_chain:: if_chain;
7
7
use rustc:: ty;
8
8
use rustc_errors:: Applicability ;
9
- use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
9
+ use rustc_hir:: { BinOpKind , Expr , ExprKind , Lit , UnOp } ;
10
10
use rustc_lint:: { LateContext , LateLintPass } ;
11
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
12
use rustc_span:: source_map:: Spanned ;
13
13
14
14
use std:: f32:: consts as f32_consts;
15
15
use std:: f64:: consts as f64_consts;
16
16
use sugg:: { format_numeric_literal, Sugg } ;
17
- use syntax:: ast;
17
+ use syntax:: ast:: { self , FloatTy , LitFloatType , LitKind } ;
18
18
19
19
declare_clippy_lint ! {
20
20
/// **What it does:** Looks for floating-point expressions that
@@ -72,6 +72,16 @@ declare_clippy_lint! {
72
72
/// let _ = a.log(E);
73
73
/// let _ = a.powf(2.0);
74
74
/// let _ = a * 2.0 + 4.0;
75
+ /// let _ = if a < 0.0 {
76
+ /// -a
77
+ /// } else {
78
+ /// a
79
+ /// }
80
+ /// let _ = if a < 0.0 {
81
+ /// a
82
+ /// } else {
83
+ /// -a
84
+ /// }
75
85
/// ```
76
86
///
77
87
/// is better expressed as
@@ -88,6 +98,8 @@ declare_clippy_lint! {
88
98
/// let _ = a.ln();
89
99
/// let _ = a.powi(2);
90
100
/// let _ = a.mul_add(2.0, 4.0);
101
+ /// let _ = a.abs();
102
+ /// let _ = -a.abs();
91
103
/// ```
92
104
pub SUBOPTIMAL_FLOPS ,
93
105
nursery,
@@ -359,6 +371,62 @@ fn check_mul_add(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
359
371
}
360
372
}
361
373
374
+ /// Returns true iff expr is an expression which tests whether or not
375
+ /// test is positive or an expression which tests whether or not test
376
+ /// is nonnegative.
377
+ /// Used for check-custom-abs function below
378
+ fn is_testing_positive ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , test : & Expr < ' _ > ) -> bool {
379
+ if let ExprKind :: Binary ( Spanned { node : op, .. } , left, right) = expr. kind {
380
+ match op {
381
+ BinOpKind :: Gt | BinOpKind :: Ge => is_zero ( right) && are_exprs_equal ( cx, left, test) ,
382
+ BinOpKind :: Lt | BinOpKind :: Le => is_zero ( left) && are_exprs_equal ( cx, right, test) ,
383
+ _ => false ,
384
+ }
385
+ } else {
386
+ false
387
+ }
388
+ }
389
+
390
+ fn are_exprs_equal ( cx : & LateContext < ' _ , ' _ > , expr1 : & Expr < ' _ > , expr2 : & Expr < ' _ > ) -> bool {
391
+ SpanlessEq :: new ( cx) . ignore_fn ( ) . eq_expr ( expr1, expr2)
392
+ }
393
+
394
+ /// Returns true iff expr is some zero literal
395
+ fn is_zero ( expr : & Expr < ' _ > ) -> bool {
396
+ if let ExprKind :: Lit ( Lit { node : lit, .. } ) = & expr. kind {
397
+ match lit {
398
+ LitKind :: Int ( 0 , _) => true ,
399
+ LitKind :: Float ( symb, LitFloatType :: Unsuffixed )
400
+ | LitKind :: Float ( symb, LitFloatType :: Suffixed ( FloatTy :: F64 ) ) => {
401
+ symb. as_str ( ) . parse :: < f64 > ( ) . unwrap ( ) == 0.0
402
+ } ,
403
+ LitKind :: Float ( symb, LitFloatType :: Suffixed ( FloatTy :: F32 ) ) => symb. as_str ( ) . parse :: < f32 > ( ) . unwrap ( ) == 0.0 ,
404
+ _ => false ,
405
+ }
406
+ } else {
407
+ false
408
+ }
409
+ }
410
+
411
+ fn check_custom_abs ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) {
412
+ // if let Some((cond, body, Some(else_body))) = higher::if_block(&expr) {
413
+ // Check for the positive-first variant
414
+ // if let ExprKind::Unary(UnOp::UnNeg, expr) = else_body.kind {
415
+ // if are_exprs_equal(cx, expr, body) && is_testing_positive(cx, cond, body) {
416
+ span_lint_and_sugg (
417
+ cx,
418
+ SUBOPTIMAL_FLOPS ,
419
+ expr. span ,
420
+ "This looks like you've implemented your own absolute value function" ,
421
+ "try" ,
422
+ "a.abs()" . to_string ( ) , //format!("{:?}.abs()", body),
423
+ Applicability :: MachineApplicable ,
424
+ ) ;
425
+ // }
426
+ // }
427
+ // }
428
+ }
429
+
362
430
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for FloatingPointArithmetic {
363
431
fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr < ' _ > ) {
364
432
if let ExprKind :: MethodCall ( ref path, _, args) = & expr. kind {
@@ -375,6 +443,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic {
375
443
} else {
376
444
check_expm1 ( cx, expr) ;
377
445
check_mul_add ( cx, expr) ;
446
+ check_custom_abs ( cx, expr) ;
378
447
}
379
448
}
380
449
}
0 commit comments