about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/floating_point_arithmetic.rs69
-rw-r--r--tests/ui/floating_point_powi.fixed10
-rw-r--r--tests/ui/floating_point_powi.rs4
-rw-r--r--tests/ui/floating_point_powi.stderr38
4 files changed, 75 insertions, 46 deletions
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index beb0b234408..11bd0ae23aa 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -294,37 +294,56 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 }
 
 fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    // Check argument
     if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) {
-        // TODO: need more specific check. this is too wide. remember also to include tests
-        if let Some(parent) = get_parent_expr(cx, expr) {
-            if let Some(grandparent) = get_parent_expr(cx, parent) {
-                if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
-                    if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
-                        return;
+        if value == Int(2) {
+            if let Some(parent) = get_parent_expr(cx, expr) {
+                if let Some(grandparent) = get_parent_expr(cx, parent) {
+                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind {
+                        if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+                            return;
+                        }
                     }
                 }
+
+                if let ExprKind::Binary(
+                    Spanned {
+                        node: BinOpKind::Add, ..
+                    },
+                    ref lhs,
+                    ref rhs,
+                ) = parent.kind
+                {
+                    let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
+
+                    span_lint_and_sugg(
+                        cx,
+                        SUBOPTIMAL_FLOPS,
+                        parent.span,
+                        "square can be computed more efficiently",
+                        "consider using",
+                        format!(
+                            "{}.mul_add({}, {})",
+                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, &other_addend, ".."),
+                        ),
+                        Applicability::MachineApplicable,
+                    );
+
+                    return;
+                }
             }
-        }
 
-        let (lint, help, suggestion) = match value {
-            Int(2) => (
-                IMPRECISE_FLOPS,
-                "square can be computed more accurately",
+            span_lint_and_sugg(
+                cx,
+                SUBOPTIMAL_FLOPS,
+                expr.span,
+                "square can be computed more efficiently",
+                "consider using",
                 format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
-            ),
-            _ => return,
-        };
-
-        span_lint_and_sugg(
-            cx,
-            lint,
-            expr.span,
-            help,
-            "consider using",
-            suggestion,
-            Applicability::MachineApplicable,
-        );
+                Applicability::MachineApplicable,
+            );
+        }
     }
 }
 
diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed
index 98766e68aaf..56762400593 100644
--- a/tests/ui/floating_point_powi.fixed
+++ b/tests/ui/floating_point_powi.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![warn(clippy::imprecise_flops)]
+#![warn(clippy::suboptimal_flops)]
 
 fn main() {
     let one = 1;
@@ -8,10 +8,12 @@ fn main() {
     let _ = x * x;
 
     let y = 4f32;
-    let _ = (x * x + y).sqrt();
-    let _ = (x + y * y).sqrt();
+    let _ = x.mul_add(x, y);
+    let _ = y.mul_add(y, x);
+    let _ = x.mul_add(x, y).sqrt();
+    let _ = y.mul_add(y, x).sqrt();
     // Cases where the lint shouldn't be applied
     let _ = x.powi(3);
     let _ = x.powi(one + 1);
-    let _ = x.hypot(y);
+    let _ = (x.powi(2) + y.powi(2)).sqrt();
 }
diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs
index 3c4b636a3d8..1f800e4628d 100644
--- a/tests/ui/floating_point_powi.rs
+++ b/tests/ui/floating_point_powi.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![warn(clippy::imprecise_flops)]
+#![warn(clippy::suboptimal_flops)]
 
 fn main() {
     let one = 1;
@@ -8,6 +8,8 @@ fn main() {
     let _ = x.powi(1 + 1);
 
     let y = 4f32;
+    let _ = x.powi(2) + y;
+    let _ = x + y.powi(2);
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
     // Cases where the lint shouldn't be applied
diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr
index f370e24bf05..d5a5f1bcca1 100644
--- a/tests/ui/floating_point_powi.stderr
+++ b/tests/ui/floating_point_powi.stderr
@@ -1,34 +1,40 @@
-error: square can be computed more accurately
+error: square can be computed more efficiently
   --> $DIR/floating_point_powi.rs:7:13
    |
 LL |     let _ = x.powi(2);
    |             ^^^^^^^^^ help: consider using: `x * x`
    |
-   = note: `-D clippy::imprecise-flops` implied by `-D warnings`
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
 
-error: square can be computed more accurately
+error: square can be computed more efficiently
   --> $DIR/floating_point_powi.rs:8:13
    |
 LL |     let _ = x.powi(1 + 1);
    |             ^^^^^^^^^^^^^ help: consider using: `x * x`
 
-error: square can be computed more accurately
-  --> $DIR/floating_point_powi.rs:11:14
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:11:13
    |
-LL |     let _ = (x.powi(2) + y).sqrt();
-   |              ^^^^^^^^^ help: consider using: `x * x`
+LL |     let _ = x.powi(2) + y;
+   |             ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
 
-error: square can be computed more accurately
-  --> $DIR/floating_point_powi.rs:12:18
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:12:13
    |
-LL |     let _ = (x + y.powi(2)).sqrt();
-   |                  ^^^^^^^^^ help: consider using: `y * y`
+LL |     let _ = x + y.powi(2);
+   |             ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
+
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:13:13
+   |
+LL |     let _ = (x.powi(2) + y).sqrt();
+   |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
 
-error: hypotenuse can be computed more accurately
-  --> $DIR/floating_point_powi.rs:16:13
+error: square can be computed more efficiently
+  --> $DIR/floating_point_powi.rs:14:13
    |
-LL |     let _ = (x.powi(2) + y.powi(2)).sqrt();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)`
+LL |     let _ = (x + y.powi(2)).sqrt();
+   |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors