Skip to content

Commit

Permalink
Lint for x.powi(2) => x * x
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagoarrais committed Apr 9, 2020
1 parent c25f26d commit c0a700e
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 29 deletions.
27 changes: 26 additions & 1 deletion clippy_lints/src/floating_point_arithmetic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::consts::{
constant, constant_simple, Constant,
Constant::{F32, F64},
Constant::{Int, F32, F64},
};
use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
use if_chain::if_chain;
Expand Down Expand Up @@ -295,6 +295,30 @@ 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]) {
let (lint, help, suggestion) = match value {
Int(2) => (
IMPRECISE_FLOPS,
"square can be computed more accurately",
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,
);
}
}

// TODO: Lint expressions of the form `x.exp() - y` where y > 1
// and suggest usage of `x.exp_m1() - (y - 1)` instead
fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
Expand Down Expand Up @@ -491,6 +515,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic {
"ln" => check_ln1p(cx, expr, args),
"log" => check_log_base(cx, expr, args),
"powf" => check_powf(cx, expr, args),
"powi" => check_powi(cx, expr, args),
_ => {},
}
}
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/floating_point_log.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ fn check_ln1p() {
let _ = 2.0f32.ln_1p();
let _ = x.ln_1p();
let _ = (x / 2.0).ln_1p();
let _ = x.powi(2).ln_1p();
let _ = (x.powi(2) / 2.0).ln_1p();
let _ = x.powi(3).ln_1p();
let _ = (x.powi(3) / 2.0).ln_1p();
let _ = ((std::f32::consts::E - 1.0)).ln_1p();
let _ = x.ln_1p();
let _ = x.powi(2).ln_1p();
let _ = x.powi(3).ln_1p();
let _ = (x + 2.0).ln_1p();
let _ = (x / 2.0).ln_1p();
// Cases where the lint shouldn't be applied
Expand All @@ -43,9 +43,9 @@ fn check_ln1p() {
let _ = 2.0f64.ln_1p();
let _ = x.ln_1p();
let _ = (x / 2.0).ln_1p();
let _ = x.powi(2).ln_1p();
let _ = x.powi(3).ln_1p();
let _ = x.ln_1p();
let _ = x.powi(2).ln_1p();
let _ = x.powi(3).ln_1p();
let _ = (x + 2.0).ln_1p();
let _ = (x / 2.0).ln_1p();
// Cases where the lint shouldn't be applied
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/floating_point_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ fn check_ln1p() {
let _ = (1f32 + 2.0).ln();
let _ = (1.0 + x).ln();
let _ = (1.0 + x / 2.0).ln();
let _ = (1.0 + x.powi(2)).ln();
let _ = (1.0 + x.powi(2) / 2.0).ln();
let _ = (1.0 + x.powi(3)).ln();
let _ = (1.0 + x.powi(3) / 2.0).ln();
let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
let _ = (x + 1.0).ln();
let _ = (x.powi(2) + 1.0).ln();
let _ = (x.powi(3) + 1.0).ln();
let _ = (x + 2.0 + 1.0).ln();
let _ = (x / 2.0 + 1.0).ln();
// Cases where the lint shouldn't be applied
Expand All @@ -43,9 +43,9 @@ fn check_ln1p() {
let _ = (1f64 + 2.0).ln();
let _ = (1.0 + x).ln();
let _ = (1.0 + x / 2.0).ln();
let _ = (1.0 + x.powi(2)).ln();
let _ = (1.0 + x.powi(3)).ln();
let _ = (x + 1.0).ln();
let _ = (x.powi(2) + 1.0).ln();
let _ = (x.powi(3) + 1.0).ln();
let _ = (x + 2.0 + 1.0).ln();
let _ = (x / 2.0 + 1.0).ln();
// Cases where the lint shouldn't be applied
Expand Down
20 changes: 10 additions & 10 deletions tests/ui/floating_point_log.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ LL | let _ = (1.0 + x / 2.0).ln();
error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:28:13
|
LL | let _ = (1.0 + x.powi(2)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
LL | let _ = (1.0 + x.powi(3)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`

error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:29:13
|
LL | let _ = (1.0 + x.powi(2) / 2.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()`
LL | let _ = (1.0 + x.powi(3) / 2.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()`

error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:30:13
Expand All @@ -101,8 +101,8 @@ LL | let _ = (x + 1.0).ln();
error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:32:13
|
LL | let _ = (x.powi(2) + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
LL | let _ = (x.powi(3) + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`

error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:33:13
Expand Down Expand Up @@ -143,8 +143,8 @@ LL | let _ = (1.0 + x / 2.0).ln();
error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:46:13
|
LL | let _ = (1.0 + x.powi(2)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
LL | let _ = (1.0 + x.powi(3)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`

error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:47:13
Expand All @@ -155,8 +155,8 @@ LL | let _ = (x + 1.0).ln();
error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:48:13
|
LL | let _ = (x.powi(2) + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
LL | let _ = (x.powi(3) + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`

error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:49:13
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/floating_point_powf.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
let _ = (-3.1f32).exp();
let _ = x.sqrt();
let _ = x.cbrt();
let _ = x.powi(2);
let _ = x.powi(3);
let _ = x.powi(-2);
let _ = x.powi(16_777_215);
let _ = x.powi(-16_777_215);
Expand All @@ -30,7 +30,7 @@ fn main() {
let _ = (-3.1f64).exp();
let _ = x.sqrt();
let _ = x.cbrt();
let _ = x.powi(2);
let _ = x.powi(3);
let _ = x.powi(-2);
let _ = x.powi(-2_147_483_648);
let _ = x.powi(2_147_483_647);
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/floating_point_powf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
let _ = std::f32::consts::E.powf(-3.1);
let _ = x.powf(1.0 / 2.0);
let _ = x.powf(1.0 / 3.0);
let _ = x.powf(2.0);
let _ = x.powf(3.0);
let _ = x.powf(-2.0);
let _ = x.powf(16_777_215.0);
let _ = x.powf(-16_777_215.0);
Expand All @@ -30,7 +30,7 @@ fn main() {
let _ = std::f64::consts::E.powf(-3.1);
let _ = x.powf(1.0 / 2.0);
let _ = x.powf(1.0 / 3.0);
let _ = x.powf(2.0);
let _ = x.powf(3.0);
let _ = x.powf(-2.0);
let _ = x.powf(-2_147_483_648.0);
let _ = x.powf(2_147_483_647.0);
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/floating_point_powf.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ LL | let _ = x.powf(1.0 / 3.0);
error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_powf.rs:14:13
|
LL | let _ = x.powf(2.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(2)`
LL | let _ = x.powf(3.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(3)`

error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_powf.rs:15:13
Expand Down Expand Up @@ -125,8 +125,8 @@ LL | let _ = x.powf(1.0 / 3.0);
error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_powf.rs:33:13
|
LL | let _ = x.powf(2.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(2)`
LL | let _ = x.powf(3.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(3)`

error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_powf.rs:34:13
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/floating_point_powi.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-rustfix
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]

fn main() {
let one = 1;
let x = 3f32;
let _ = x * x;
let _ = x * x;
// Cases where the lint shouldn't be applied
let _ = x.powi(3);
let _ = x.powi(one + 1);
}
12 changes: 12 additions & 0 deletions tests/ui/floating_point_powi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-rustfix
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]

fn main() {
let one = 1;
let x = 3f32;
let _ = x.powi(2);
let _ = x.powi(1 + 1);
// Cases where the lint shouldn't be applied
let _ = x.powi(3);
let _ = x.powi(one + 1);
}
16 changes: 16 additions & 0 deletions tests/ui/floating_point_powi.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: square can be computed more accurately
--> $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`

error: square can be computed more accurately
--> $DIR/floating_point_powi.rs:8:13
|
LL | let _ = x.powi(1 + 1);
| ^^^^^^^^^^^^^ help: consider using: `x * x`

error: aborting due to 2 previous errors

0 comments on commit c0a700e

Please sign in to comment.