From c636c6a55b92daef5af4e1c459c0eaf3f5787945 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Sat, 14 Dec 2019 09:28:11 -0800 Subject: [PATCH 01/14] Add lints to detect inaccurate and inefficient FP operations Add lints to detect floating point computations that are either inaccurate or inefficient and suggest better alternatives. --- CHANGELOG.md | 1 + clippy_lints/src/floating_point_arithmetic.rs | 228 ++++++++++++++++++ clippy_lints/src/lib.rs | 3 + src/lintlist/mod.rs | 7 + tests/ui/floating_point_arithmetic.rs | 76 ++++++ tests/ui/floating_point_arithmetic.stderr | 174 +++++++++++++ 6 files changed, 489 insertions(+) create mode 100644 clippy_lints/src/floating_point_arithmetic.rs create mode 100644 tests/ui/floating_point_arithmetic.rs create mode 100644 tests/ui/floating_point_arithmetic.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e99342e4a42..55e46bf6d20e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1169,6 +1169,7 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return +[`inaccurate_floating_point_computation`]: https://rust-lang.github.io/rust-clippy/master/index.html#inaccurate_floating_point_computation [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs new file mode 100644 index 000000000000..935d8b581466 --- /dev/null +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -0,0 +1,228 @@ +use crate::consts::{ + constant, + Constant::{F32, F64}, +}; +use crate::utils::*; +use if_chain::if_chain; +use rustc::declare_lint_pass; +use rustc::hir::*; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc_errors::Applicability; +use rustc_session::declare_tool_lint; +use std::f32::consts as f32_consts; +use std::f64::consts as f64_consts; + +declare_clippy_lint! { + /// **What it does:** Looks for numerically unstable floating point + /// computations and suggests better alternatives. + /// + /// **Why is this bad?** Numerically unstable floating point computations + /// cause rounding errors to magnify and distorts the results strongly. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// use std::f32::consts::E; + /// + /// let a = 1f32.log(2.0); + /// let b = 1f32.log(10.0); + /// let c = 1f32.log(E); + /// ``` + /// + /// is better expressed as + /// + /// ```rust + /// let a = 1f32.log2(); + /// let b = 1f32.log10(); + /// let c = 1f32.ln(); + /// ``` + pub INACCURATE_FLOATING_POINT_COMPUTATION, + nursery, + "checks for numerically unstable floating point computations" +} + +declare_clippy_lint! { + /// **What it does:** Looks for inefficient floating point computations + /// and suggests faster alternatives. + /// + /// **Why is this bad?** Lower performance. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// use std::f32::consts::E; + /// + /// let a = (2f32).powf(3.0); + /// let c = E.powf(3.0); + /// ``` + /// + /// is better expressed as + /// + /// ```rust + /// let a = (3f32).exp2(); + /// let b = (3f32).exp(); + /// ``` + pub SLOW_FLOATING_POINT_COMPUTATION, + nursery, + "checks for inefficient floating point computations" +} + +declare_lint_pass!(FloatingPointArithmetic => [ + INACCURATE_FLOATING_POINT_COMPUTATION, + SLOW_FLOATING_POINT_COMPUTATION +]); + +fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { + let recv = &args[0]; + let arg = sugg::Sugg::hir(cx, recv, "..").maybe_par(); + + if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { + let method; + + if F32(2.0) == value || F64(2.0) == value { + method = "log2"; + } else if F32(10.0) == value || F64(10.0) == value { + method = "log10"; + } else if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + method = "ln"; + } else { + return; + } + + span_lint_and_sugg( + cx, + INACCURATE_FLOATING_POINT_COMPUTATION, + expr.span, + "logarithm for bases 2, 10 and e can be computed more accurately", + "consider using", + format!("{}.{}()", arg, method), + Applicability::MachineApplicable, + ); + } +} + +// TODO: Lint expressions of the form `(x + 1).ln()` and `(x + y).ln()` +// where y > 1 and suggest usage of `(x + (y - 1)).ln_1p()` instead +fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = &args[0].kind; + if op.node == BinOpKind::Add; + if let Some((value, _)) = constant(cx, cx.tables, lhs); + if F32(1.0) == value || F64(1.0) == value; + then { + let arg = sugg::Sugg::hir(cx, rhs, "..").maybe_par(); + + span_lint_and_sugg( + cx, + INACCURATE_FLOATING_POINT_COMPUTATION, + expr.span, + "ln(1 + x) can be computed more accurately", + "consider using", + format!("{}.ln_1p()", arg), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { + // Check receiver + if let Some((value, _)) = constant(cx, cx.tables, &args[0]) { + let method; + + if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + method = "exp"; + } else if F32(2.0) == value || F64(2.0) == value { + method = "exp2"; + } else { + return; + } + + span_lint_and_sugg( + cx, + SLOW_FLOATING_POINT_COMPUTATION, + expr.span, + "exponent for bases 2 and e can be computed more efficiently", + "consider using", + format!("{}.{}()", sugg::Sugg::hir(cx, &args[1], "..").maybe_par(), method), + Applicability::MachineApplicable, + ); + } + + // Check argument + if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { + let help; + let method; + + if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { + help = "square-root of a number can be computer more efficiently"; + method = "sqrt"; + } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { + help = "cube-root of a number can be computer more efficiently"; + method = "cbrt"; + } else { + return; + } + + span_lint_and_sugg( + cx, + SLOW_FLOATING_POINT_COMPUTATION, + expr.span, + help, + "consider using", + format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method), + 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) { + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; + if op.node == BinOpKind::Sub; + if cx.tables.expr_ty(lhs).is_floating_point(); + if let Some((value, _)) = constant(cx, cx.tables, rhs); + if F32(1.0) == value || F64(1.0) == value; + if let ExprKind::MethodCall(ref path, _, ref method_args) = lhs.kind; + if path.ident.name.as_str() == "exp"; + then { + span_lint_and_sugg( + cx, + INACCURATE_FLOATING_POINT_COMPUTATION, + expr.span, + "(e.pow(x) - 1) can be computed more accurately", + "consider using", + format!( + "{}.exp_m1()", + sugg::Sugg::hir(cx, &method_args[0], "..") + ), + Applicability::MachineApplicable, + ); + } + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { + let recv_ty = cx.tables.expr_ty(&args[0]); + + if recv_ty.is_floating_point() { + match &*path.ident.name.as_str() { + "ln" => check_ln1p(cx, expr, args), + "log" => check_log_base(cx, expr, args), + "powf" => check_powf(cx, expr, args), + _ => {}, + } + } + } else { + check_expm1(cx, expr); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2b5691f92555..9a904141fcf4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1000,6 +1000,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); + store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); @@ -1648,6 +1649,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(&floating_point_arithmetic::INACCURATE_FLOATING_POINT_COMPUTATION), + LintId::of(&floating_point_arithmetic::SLOW_FLOATING_POINT_COMPUTATION), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 29b5a7ba08a2..fee595074547 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -749,6 +749,13 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "implicit_return", }, + Lint { + name: "inaccurate_floating_point_computation", + group: "nursery", + desc: "checks for numerically unstable floating point computations", + deprecation: None, + module: "floating_point_arithmetic", + }, Lint { name: "inconsistent_digit_grouping", group: "style", diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_arithmetic.rs new file mode 100644 index 000000000000..5291e5cf0226 --- /dev/null +++ b/tests/ui/floating_point_arithmetic.rs @@ -0,0 +1,76 @@ +#![allow(dead_code)] +#![warn( + clippy::inaccurate_floating_point_computation, + clippy::slow_floating_point_computation +)] + +const TWO: f32 = 2.0; +const E: f32 = std::f32::consts::E; + +fn check_log_base() { + let x = 1f32; + let _ = x.log(2f32); + let _ = x.log(10f32); + let _ = x.log(std::f32::consts::E); + let _ = x.log(TWO); + let _ = x.log(E); + + let x = 1f64; + let _ = x.log(2f64); + let _ = x.log(10f64); + let _ = x.log(std::f64::consts::E); +} + +fn check_ln1p() { + let x = 1f32; + 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 + (std::f32::consts::E - 1.0)).ln(); + // Cases where the lint shouldn't be applied + let _ = (x + 1.0).ln(); + let _ = (1.0 + x + 2.0).ln(); + let _ = (1.0 + x - 2.0).ln(); + + let x = 1f64; + let _ = (1.0 + x).ln(); + let _ = (1.0 + x * 2.0).ln(); + let _ = (1.0 + x.powi(2)).ln(); + // Cases where the lint shouldn't be applied + let _ = (x + 1.0).ln(); + let _ = (1.0 + x + 2.0).ln(); + let _ = (1.0 + x - 2.0).ln(); +} + +fn check_powf() { + let x = 3f32; + let _ = 2f32.powf(x); + let _ = std::f32::consts::E.powf(x); + let _ = x.powf(1.0 / 2.0); + let _ = x.powf(1.0 / 3.0); + + let x = 3f64; + let _ = 2f64.powf(x); + let _ = std::f64::consts::E.powf(x); + let _ = x.powf(1.0 / 2.0); + let _ = x.powf(1.0 / 3.0); +} + +fn check_expm1() { + let x = 2f32; + let _ = x.exp() - 1.0; + let _ = x.exp() - 1.0 + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; + + let x = 2f64; + let _ = x.exp() - 1.0; + let _ = x.exp() - 1.0 + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; +} + +fn main() {} diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr new file mode 100644 index 000000000000..a0663e488354 --- /dev/null +++ b/tests/ui/floating_point_arithmetic.stderr @@ -0,0 +1,174 @@ +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:12:13 + | +LL | let _ = x.log(2f32); + | ^^^^^^^^^^^ help: consider using: `x.log2()` + | + = note: `-D clippy::inaccurate-floating-point-computation` implied by `-D warnings` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:13:13 + | +LL | let _ = x.log(10f32); + | ^^^^^^^^^^^^ help: consider using: `x.log10()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:14:13 + | +LL | let _ = x.log(std::f32::consts::E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:15:13 + | +LL | let _ = x.log(TWO); + | ^^^^^^^^^^ help: consider using: `x.log2()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:16:13 + | +LL | let _ = x.log(E); + | ^^^^^^^^ help: consider using: `x.ln()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:19:13 + | +LL | let _ = x.log(2f64); + | ^^^^^^^^^^^ help: consider using: `x.log2()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:20:13 + | +LL | let _ = x.log(10f64); + | ^^^^^^^^^^^^ help: consider using: `x.log10()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:21:13 + | +LL | let _ = x.log(std::f64::consts::E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:26:13 + | +LL | let _ = (1.0 + x).ln(); + | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:27:13 + | +LL | let _ = (1.0 + x * 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:28:13 + | +LL | let _ = (1.0 + x.powi(2)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:29:13 + | +LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:30:13 + | +LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:37:13 + | +LL | let _ = (1.0 + x).ln(); + | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:38:13 + | +LL | let _ = (1.0 + x * 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:39:13 + | +LL | let _ = (1.0 + x.powi(2)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:48:13 + | +LL | let _ = 2f32.powf(x); + | ^^^^^^^^^^^^ help: consider using: `x.exp2()` + | + = note: `-D clippy::slow-floating-point-computation` implied by `-D warnings` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:49:13 + | +LL | let _ = std::f32::consts::E.powf(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` + +error: square-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:50:13 + | +LL | let _ = x.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` + +error: cube-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:51:13 + | +LL | let _ = x.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:54:13 + | +LL | let _ = 2f64.powf(x); + | ^^^^^^^^^^^^ help: consider using: `x.exp2()` + +error: exponent for bases 2 and e can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:55:13 + | +LL | let _ = std::f64::consts::E.powf(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` + +error: square-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:56:13 + | +LL | let _ = x.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` + +error: cube-root of a number can be computer more efficiently + --> $DIR/floating_point_arithmetic.rs:57:13 + | +LL | let _ = x.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:62:13 + | +LL | let _ = x.exp() - 1.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:63:13 + | +LL | let _ = x.exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:69:13 + | +LL | let _ = x.exp() - 1.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:70:13 + | +LL | let _ = x.exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: aborting due to 28 previous errors + From 1f4f357bf540f63ece5d11d5ab6cae9a8fb63a21 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Sat, 14 Dec 2019 20:10:23 -0800 Subject: [PATCH 02/14] Consolidate the accuracy and efficiency lints Merge the accuracy and efficiency lints into a single lint that checks for improvements to accuracy, efficiency and readability of floating-point expressions. --- CHANGELOG.md | 1 - clippy_lints/src/floating_point_arithmetic.rs | 89 ++++++++----------- clippy_lints/src/lib.rs | 3 +- src/lintlist/mod.rs | 7 -- tests/ui/floating_point_arithmetic.rs | 5 +- tests/ui/floating_point_arithmetic.stderr | 76 ++++++++-------- 6 files changed, 76 insertions(+), 105 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55e46bf6d20e..4e99342e4a42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1169,7 +1169,6 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return -[`inaccurate_floating_point_computation`]: https://rust-lang.github.io/rust-clippy/master/index.html#inaccurate_floating_point_computation [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 935d8b581466..da55f1e5f4e3 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -13,11 +13,12 @@ use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; declare_clippy_lint! { - /// **What it does:** Looks for numerically unstable floating point - /// computations and suggests better alternatives. + /// **What it does:** Looks for floating-point expressions that + /// can be expressed using built-in methods to improve accuracy, + /// performance and/or succinctness. /// - /// **Why is this bad?** Numerically unstable floating point computations - /// cause rounding errors to magnify and distorts the results strongly. + /// **Why is this bad?** Negatively affects accuracy, performance + /// and/or readability. /// /// **Known problems:** None /// @@ -26,59 +27,43 @@ declare_clippy_lint! { /// ```rust /// use std::f32::consts::E; /// - /// let a = 1f32.log(2.0); - /// let b = 1f32.log(10.0); - /// let c = 1f32.log(E); + /// let a = 3f32; + /// let _ = (2f32).powf(a); + /// let _ = E.powf(a); + /// let _ = a.powf(1.0 / 2.0); + /// let _ = a.powf(1.0 / 3.0); + /// let _ = a.log(2.0); + /// let _ = a.log(10.0); + /// let _ = a.log(E); + /// let _ = (1.0 + a).ln(); + /// let _ = a.exp() - 1.0; /// ``` /// /// is better expressed as /// /// ```rust - /// let a = 1f32.log2(); - /// let b = 1f32.log10(); - /// let c = 1f32.ln(); - /// ``` - pub INACCURATE_FLOATING_POINT_COMPUTATION, - nursery, - "checks for numerically unstable floating point computations" -} - -declare_clippy_lint! { - /// **What it does:** Looks for inefficient floating point computations - /// and suggests faster alternatives. - /// - /// **Why is this bad?** Lower performance. - /// - /// **Known problems:** None - /// - /// **Example:** - /// - /// ```rust /// use std::f32::consts::E; /// - /// let a = (2f32).powf(3.0); - /// let c = E.powf(3.0); - /// ``` - /// - /// is better expressed as - /// - /// ```rust - /// let a = (3f32).exp2(); - /// let b = (3f32).exp(); + /// let a = 3f32; + /// let _ = a.exp2(); + /// let _ = a.exp(); + /// let _ = a.sqrt(); + /// let _ = a.cbrt(); + /// let _ = a.log2(); + /// let _ = a.log10(); + /// let _ = a.ln(); + /// let _ = a.ln_1p(); + /// let _ = a.exp_m1(); /// ``` - pub SLOW_FLOATING_POINT_COMPUTATION, + pub FLOATING_POINT_IMPROVEMENTS, nursery, - "checks for inefficient floating point computations" + "looks for improvements to floating-point expressions" } -declare_lint_pass!(FloatingPointArithmetic => [ - INACCURATE_FLOATING_POINT_COMPUTATION, - SLOW_FLOATING_POINT_COMPUTATION -]); +declare_lint_pass!(FloatingPointArithmetic => [FLOATING_POINT_IMPROVEMENTS]); fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { - let recv = &args[0]; - let arg = sugg::Sugg::hir(cx, recv, "..").maybe_par(); + let arg = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { let method; @@ -95,7 +80,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - INACCURATE_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", @@ -118,7 +103,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - INACCURATE_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, "ln(1 + x) can be computed more accurately", "consider using", @@ -144,9 +129,9 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - SLOW_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, - "exponent for bases 2 and e can be computed more efficiently", + "exponent for bases 2 and e can be computed more accurately", "consider using", format!("{}.{}()", sugg::Sugg::hir(cx, &args[1], "..").maybe_par(), method), Applicability::MachineApplicable, @@ -159,10 +144,10 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { let method; if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { - help = "square-root of a number can be computer more efficiently"; + help = "square-root of a number can be computed more efficiently and accurately"; method = "sqrt"; } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { - help = "cube-root of a number can be computer more efficiently"; + help = "cube-root of a number can be computed more accurately"; method = "cbrt"; } else { return; @@ -170,7 +155,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - SLOW_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, help, "consider using", @@ -194,7 +179,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { then { span_lint_and_sugg( cx, - INACCURATE_FLOATING_POINT_COMPUTATION, + FLOATING_POINT_IMPROVEMENTS, expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9a904141fcf4..9154a0dc3fff 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1649,8 +1649,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(&floating_point_arithmetic::INACCURATE_FLOATING_POINT_COMPUTATION), - LintId::of(&floating_point_arithmetic::SLOW_FLOATING_POINT_COMPUTATION), + LintId::of(&floating_point_arithmetic::FLOATING_POINT_IMPROVEMENTS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index fee595074547..29b5a7ba08a2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -749,13 +749,6 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "implicit_return", }, - Lint { - name: "inaccurate_floating_point_computation", - group: "nursery", - desc: "checks for numerically unstable floating point computations", - deprecation: None, - module: "floating_point_arithmetic", - }, Lint { name: "inconsistent_digit_grouping", group: "style", diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_arithmetic.rs index 5291e5cf0226..1feeb827621a 100644 --- a/tests/ui/floating_point_arithmetic.rs +++ b/tests/ui/floating_point_arithmetic.rs @@ -1,8 +1,5 @@ #![allow(dead_code)] -#![warn( - clippy::inaccurate_floating_point_computation, - clippy::slow_floating_point_computation -)] +#![warn(clippy::floating_point_improvements)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr index a0663e488354..a7db1669745a 100644 --- a/tests/ui/floating_point_arithmetic.stderr +++ b/tests/ui/floating_point_arithmetic.stderr @@ -1,171 +1,169 @@ error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:12:13 + --> $DIR/floating_point_arithmetic.rs:9:13 | LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` | - = note: `-D clippy::inaccurate-floating-point-computation` implied by `-D warnings` + = note: `-D clippy::floating-point-improvements` implied by `-D warnings` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:13:13 + --> $DIR/floating_point_arithmetic.rs:10:13 | LL | let _ = x.log(10f32); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:14:13 + --> $DIR/floating_point_arithmetic.rs:11:13 | LL | let _ = x.log(std::f32::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:15:13 + --> $DIR/floating_point_arithmetic.rs:12:13 | LL | let _ = x.log(TWO); | ^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:16:13 + --> $DIR/floating_point_arithmetic.rs:13:13 | LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:19:13 + --> $DIR/floating_point_arithmetic.rs:16:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:20:13 + --> $DIR/floating_point_arithmetic.rs:17:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:21:13 + --> $DIR/floating_point_arithmetic.rs:18:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:26:13 + --> $DIR/floating_point_arithmetic.rs:23:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:27:13 + --> $DIR/floating_point_arithmetic.rs:24:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:28:13 + --> $DIR/floating_point_arithmetic.rs:25:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:29:13 + --> $DIR/floating_point_arithmetic.rs:26:13 | LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:30:13 + --> $DIR/floating_point_arithmetic.rs:27:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:37:13 + --> $DIR/floating_point_arithmetic.rs:34:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:38:13 + --> $DIR/floating_point_arithmetic.rs:35:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:39:13 + --> $DIR/floating_point_arithmetic.rs:36:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:48:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:45:13 | LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` - | - = note: `-D clippy::slow-floating-point-computation` implied by `-D warnings` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:49:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:46:13 | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` -error: square-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:50:13 +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_arithmetic.rs:47:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` -error: cube-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:51:13 +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:48:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:54:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:51:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` -error: exponent for bases 2 and e can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:55:13 +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:52:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` -error: square-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:56:13 +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_arithmetic.rs:53:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` -error: cube-root of a number can be computer more efficiently - --> $DIR/floating_point_arithmetic.rs:57:13 +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_arithmetic.rs:54:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:62:13 + --> $DIR/floating_point_arithmetic.rs:59:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:63:13 + --> $DIR/floating_point_arithmetic.rs:60:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:69:13 + --> $DIR/floating_point_arithmetic.rs:66:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:70:13 + --> $DIR/floating_point_arithmetic.rs:67:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` From 9520d3dfa4d3213ef07894dd99d201aeab255fa3 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Sun, 15 Dec 2019 19:26:44 -0800 Subject: [PATCH 03/14] Suggest usage of `powi` method when applicable --- clippy_lints/src/floating_point_arithmetic.rs | 41 +++++++++++++++++- tests/ui/floating_point_arithmetic.rs | 12 ++++++ tests/ui/floating_point_arithmetic.stderr | 42 +++++++++++++++---- 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index da55f1e5f4e3..84a9cac5b634 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,5 +1,5 @@ use crate::consts::{ - constant, + constant, Constant, Constant::{F32, F64}, }; use crate::utils::*; @@ -37,6 +37,7 @@ declare_clippy_lint! { /// let _ = a.log(E); /// let _ = (1.0 + a).ln(); /// let _ = a.exp() - 1.0; + /// let _ = a.powf(2.0); /// ``` /// /// is better expressed as @@ -54,6 +55,7 @@ declare_clippy_lint! { /// let _ = a.ln(); /// let _ = a.ln_1p(); /// let _ = a.exp_m1(); + /// let _ = a.powi(2); /// ``` pub FLOATING_POINT_IMPROVEMENTS, nursery, @@ -114,6 +116,31 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { } } +// Returns an integer if the float constant is a whole number and it +// can be converted to an integer without loss +// TODO: Add a better check to determine whether the float can be +// casted without loss +#[allow(clippy::cast_possible_truncation)] +fn get_integer_from_float_constant(value: &Constant) -> Option { + match value { + F32(num) if (num.trunc() - num).abs() <= std::f32::EPSILON => { + if *num > -16_777_217.0 && *num < 16_777_217.0 { + Some(num.round() as i64) + } else { + None + } + }, + F64(num) if (num.trunc() - num).abs() <= std::f64::EPSILON => { + if *num > -9_007_199_254_740_993.0 && *num < 9_007_199_254_740_993.0 { + Some(num.round() as i64) + } else { + None + } + }, + _ => None, + } +} + fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { // Check receiver if let Some((value, _)) = constant(cx, cx.tables, &args[0]) { @@ -149,6 +176,18 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { help = "cube-root of a number can be computed more accurately"; method = "cbrt"; + } else if let Some(exponent) = get_integer_from_float_constant(&value) { + span_lint_and_sugg( + cx, + FLOATING_POINT_IMPROVEMENTS, + expr.span, + "exponentiation with integer powers can be computed more efficiently", + "consider using", + format!("{}.powi({})", sugg::Sugg::hir(cx, &args[0], ".."), exponent), + Applicability::MachineApplicable, + ); + + return; } else { return; } diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_arithmetic.rs index 1feeb827621a..77a14a7a6668 100644 --- a/tests/ui/floating_point_arithmetic.rs +++ b/tests/ui/floating_point_arithmetic.rs @@ -46,12 +46,24 @@ fn check_powf() { let _ = std::f32::consts::E.powf(x); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); + let _ = x.powf(2.0); + let _ = x.powf(-2.0); + let _ = x.powf(2.1); + let _ = x.powf(-2.1); + let _ = x.powf(16_777_217.0); + let _ = x.powf(-16_777_217.0); let x = 3f64; let _ = 2f64.powf(x); let _ = std::f64::consts::E.powf(x); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); + let _ = x.powf(2.0); + let _ = x.powf(-2.0); + let _ = x.powf(2.1); + let _ = x.powf(-2.1); + let _ = x.powf(9_007_199_254_740_993.0); + let _ = x.powf(-9_007_199_254_740_993.0); } fn check_expm1() { diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr index a7db1669745a..0fc05bce2528 100644 --- a/tests/ui/floating_point_arithmetic.stderr +++ b/tests/ui/floating_point_arithmetic.stderr @@ -120,53 +120,77 @@ error: cube-root of a number can be computed more accurately LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:49:13 + | +LL | let _ = x.powf(2.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(2)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:50:13 + | +LL | let _ = x.powf(-2.0); + | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` + error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:51:13 + --> $DIR/floating_point_arithmetic.rs:57:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:52:13 + --> $DIR/floating_point_arithmetic.rs:58:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_arithmetic.rs:53:13 + --> $DIR/floating_point_arithmetic.rs:59:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:54:13 + --> $DIR/floating_point_arithmetic.rs:60:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:61:13 + | +LL | let _ = x.powf(2.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(2)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_arithmetic.rs:62:13 + | +LL | let _ = x.powf(-2.0); + | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` + error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:59:13 + --> $DIR/floating_point_arithmetic.rs:71:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:60:13 + --> $DIR/floating_point_arithmetic.rs:72:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:66:13 + --> $DIR/floating_point_arithmetic.rs:78:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:67:13 + --> $DIR/floating_point_arithmetic.rs:79:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` -error: aborting due to 28 previous errors +error: aborting due to 32 previous errors From de7973392402cd34a98c3d7ca2e0c39d60fcada0 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Mon, 16 Dec 2019 18:03:51 -0800 Subject: [PATCH 04/14] Lint expressions of the form `x.log(b) / y.log(b)` --- clippy_lints/src/floating_point_arithmetic.rs | 103 ++++++++++++++++-- tests/ui/floating_point_arithmetic.rs | 26 +++++ tests/ui/floating_point_arithmetic.stderr | 74 ++++++++++++- 3 files changed, 190 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 84a9cac5b634..7f6dac87d04a 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -64,29 +64,31 @@ declare_clippy_lint! { declare_lint_pass!(FloatingPointArithmetic => [FLOATING_POINT_IMPROVEMENTS]); -fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { - let arg = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); - - if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { - let method; - +// Returns the specialized log method for a given base if base is constant +// and is one of 2, 10 and e +fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr) -> Option<&'static str> { + if let Some((value, _)) = constant(cx, cx.tables, base) { if F32(2.0) == value || F64(2.0) == value { - method = "log2"; + return Some("log2"); } else if F32(10.0) == value || F64(10.0) == value { - method = "log10"; + return Some("log10"); } else if F32(f32_consts::E) == value || F64(f64_consts::E) == value { - method = "ln"; - } else { - return; + return Some("ln"); } + } + + None +} +fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { + if let Some(method) = get_specialized_log_method(cx, &args[1]) { span_lint_and_sugg( cx, FLOATING_POINT_IMPROVEMENTS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", arg, method), + format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method), Applicability::MachineApplicable, ); } @@ -232,6 +234,82 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { } } +// Checks whether two expressions evaluate to the same value +fn are_exprs_equivalent(cx: &LateContext<'_, '_>, left: &Expr, right: &Expr) -> bool { + // Checks whether the values are constant and equal + if_chain! { + if let Some((left_value, _)) = constant(cx, cx.tables, left); + if let Some((right_value, _)) = constant(cx, cx.tables, right); + if left_value == right_value; + then { + return true; + } + } + + // Checks whether the expressions resolve to the same variable + if_chain! { + if let ExprKind::Path(ref left_qpath) = left.kind; + if let QPath::Resolved(_, ref left_path) = *left_qpath; + if left_path.segments.len() == 1; + if let def::Res::Local(left_local_id) = qpath_res(cx, left_qpath, left.hir_id); + if let ExprKind::Path(ref right_qpath) = right.kind; + if let QPath::Resolved(_, ref right_path) = *right_qpath; + if right_path.segments.len() == 1; + if let def::Res::Local(right_local_id) = qpath_res(cx, right_qpath, right.hir_id); + if left_local_id == right_local_id; + then { + return true; + } + } + + false +} + +fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { + let log_methods = ["log", "log2", "log10", "ln"]; + + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; + if op.node == BinOpKind::Div; + if cx.tables.expr_ty(lhs).is_floating_point(); + if let ExprKind::MethodCall(left_path, _, left_args) = &lhs.kind; + if let ExprKind::MethodCall(right_path, _, right_args) = &rhs.kind; + let left_method = left_path.ident.name.as_str(); + if left_method == right_path.ident.name.as_str(); + if log_methods.iter().any(|&method| left_method == method); + then { + let left_recv = &left_args[0]; + let right_recv = &right_args[0]; + + // Return early when bases are not equal + if left_method == "log" && !are_exprs_equivalent(cx, &left_args[1], &right_args[1]) { + return; + } + + // Reduce the expression further for bases 2, 10 and e + let suggestion = if let Some(method) = get_specialized_log_method(cx, right_recv) { + format!("{}.{}()", sugg::Sugg::hir(cx, left_recv, ".."), method) + } else { + format!( + "{}.log({})", + sugg::Sugg::hir(cx, left_recv, ".."), + sugg::Sugg::hir(cx, right_recv, "..") + ) + }; + + span_lint_and_sugg( + cx, + FLOATING_POINT_IMPROVEMENTS, + expr.span, + "x.log(b) / y.log(b) can be reduced to x.log(y)", + "consider using", + suggestion, + Applicability::MachineApplicable, + ); + } + } +} + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { @@ -247,6 +325,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { } } else { check_expm1(cx, expr); + check_log_division(cx, expr); } } } diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_arithmetic.rs index 77a14a7a6668..ff5949415461 100644 --- a/tests/ui/floating_point_arithmetic.rs +++ b/tests/ui/floating_point_arithmetic.rs @@ -82,4 +82,30 @@ fn check_expm1() { let _ = x.exp() - 1.0 * 2.0; } +fn check_log_division() { + let x = 3f32; + let y = 2f32; + let b = 4f32; + + let _ = x.log2() / y.log2(); + let _ = x.log10() / y.log10(); + let _ = x.ln() / y.ln(); + let _ = x.log(4.0) / y.log(4.0); + let _ = x.log(b) / y.log(b); + let _ = x.log(b) / y.log(x); + let _ = x.log(b) / 2f32.log(b); + + let x = 3f64; + let y = 2f64; + let b = 4f64; + + let _ = x.log2() / y.log2(); + let _ = x.log10() / y.log10(); + let _ = x.ln() / y.ln(); + let _ = x.log(4.0) / y.log(4.0); + let _ = x.log(b) / y.log(b); + let _ = x.log(b) / y.log(x); + let _ = x.log(b) / 2f64.log(b); +} + fn main() {} diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_arithmetic.stderr index 0fc05bce2528..076b8d4fefe6 100644 --- a/tests/ui/floating_point_arithmetic.stderr +++ b/tests/ui/floating_point_arithmetic.stderr @@ -192,5 +192,77 @@ error: (e.pow(x) - 1) can be computed more accurately LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` -error: aborting due to 32 previous errors +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:90:13 + | +LL | let _ = x.log2() / y.log2(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:91:13 + | +LL | let _ = x.log10() / y.log10(); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:92:13 + | +LL | let _ = x.ln() / y.ln(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:93:13 + | +LL | let _ = x.log(4.0) / y.log(4.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:94:13 + | +LL | let _ = x.log(b) / y.log(b); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:96:13 + | +LL | let _ = x.log(b) / 2f32.log(b); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:102:13 + | +LL | let _ = x.log2() / y.log2(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:103:13 + | +LL | let _ = x.log10() / y.log10(); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:104:13 + | +LL | let _ = x.ln() / y.ln(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:105:13 + | +LL | let _ = x.log(4.0) / y.log(4.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:106:13 + | +LL | let _ = x.log(b) / y.log(b); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: x.log(b) / y.log(b) can be reduced to x.log(y) + --> $DIR/floating_point_arithmetic.rs:108:13 + | +LL | let _ = x.log(b) / 2f64.log(b); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` + +error: aborting due to 44 previous errors From a60ae5d31cea7dff1a5b02b958d3295b474a7c9f Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Fri, 20 Dec 2019 17:57:47 -0800 Subject: [PATCH 05/14] Split test cases into separate files --- tests/ui/floating_point_exp.rs | 17 ++ tests/ui/floating_point_exp.stderr | 28 ++++ ...nt_arithmetic.rs => floating_point_log.rs} | 42 ----- ...metic.stderr => floating_point_log.stderr} | 154 ++++-------------- tests/ui/floating_point_powf.rs | 27 +++ tests/ui/floating_point_powf.stderr | 76 +++++++++ 6 files changed, 177 insertions(+), 167 deletions(-) create mode 100644 tests/ui/floating_point_exp.rs create mode 100644 tests/ui/floating_point_exp.stderr rename tests/ui/{floating_point_arithmetic.rs => floating_point_log.rs} (60%) rename tests/ui/{floating_point_arithmetic.stderr => floating_point_log.stderr} (50%) create mode 100644 tests/ui/floating_point_powf.rs create mode 100644 tests/ui/floating_point_powf.stderr diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs new file mode 100644 index 000000000000..303c6124775c --- /dev/null +++ b/tests/ui/floating_point_exp.rs @@ -0,0 +1,17 @@ +#![warn(clippy::floating_point_improvements)] + +fn main() { + let x = 2f32; + let _ = x.exp() - 1.0; + let _ = x.exp() - 1.0 + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; + + let x = 2f64; + let _ = x.exp() - 1.0; + let _ = x.exp() - 1.0 + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; +} diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr new file mode 100644 index 000000000000..783218999458 --- /dev/null +++ b/tests/ui/floating_point_exp.stderr @@ -0,0 +1,28 @@ +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_exp.rs:5:13 + | +LL | let _ = x.exp() - 1.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + | + = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_exp.rs:6:13 + | +LL | let _ = x.exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_exp.rs:12:13 + | +LL | let _ = x.exp() - 1.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_exp.rs:13:13 + | +LL | let _ = x.exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/floating_point_arithmetic.rs b/tests/ui/floating_point_log.rs similarity index 60% rename from tests/ui/floating_point_arithmetic.rs rename to tests/ui/floating_point_log.rs index ff5949415461..4c01d5e716b0 100644 --- a/tests/ui/floating_point_arithmetic.rs +++ b/tests/ui/floating_point_log.rs @@ -40,48 +40,6 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); } -fn check_powf() { - let x = 3f32; - let _ = 2f32.powf(x); - let _ = std::f32::consts::E.powf(x); - let _ = x.powf(1.0 / 2.0); - let _ = x.powf(1.0 / 3.0); - let _ = x.powf(2.0); - let _ = x.powf(-2.0); - let _ = x.powf(2.1); - let _ = x.powf(-2.1); - let _ = x.powf(16_777_217.0); - let _ = x.powf(-16_777_217.0); - - let x = 3f64; - let _ = 2f64.powf(x); - let _ = std::f64::consts::E.powf(x); - let _ = x.powf(1.0 / 2.0); - let _ = x.powf(1.0 / 3.0); - let _ = x.powf(2.0); - let _ = x.powf(-2.0); - let _ = x.powf(2.1); - let _ = x.powf(-2.1); - let _ = x.powf(9_007_199_254_740_993.0); - let _ = x.powf(-9_007_199_254_740_993.0); -} - -fn check_expm1() { - let x = 2f32; - let _ = x.exp() - 1.0; - let _ = x.exp() - 1.0 + 2.0; - // Cases where the lint shouldn't be applied - let _ = x.exp() - 2.0; - let _ = x.exp() - 1.0 * 2.0; - - let x = 2f64; - let _ = x.exp() - 1.0; - let _ = x.exp() - 1.0 + 2.0; - // Cases where the lint shouldn't be applied - let _ = x.exp() - 2.0; - let _ = x.exp() - 1.0 * 2.0; -} - fn check_log_division() { let x = 3f32; let y = 2f32; diff --git a/tests/ui/floating_point_arithmetic.stderr b/tests/ui/floating_point_log.stderr similarity index 50% rename from tests/ui/floating_point_arithmetic.stderr rename to tests/ui/floating_point_log.stderr index 076b8d4fefe6..0a36f8fc69fd 100644 --- a/tests/ui/floating_point_arithmetic.stderr +++ b/tests/ui/floating_point_log.stderr @@ -1,5 +1,5 @@ error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:9:13 + --> $DIR/floating_point_log.rs:9:13 | LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` @@ -7,262 +7,166 @@ LL | let _ = x.log(2f32); = note: `-D clippy::floating-point-improvements` implied by `-D warnings` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:10:13 + --> $DIR/floating_point_log.rs:10:13 | LL | let _ = x.log(10f32); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:11:13 + --> $DIR/floating_point_log.rs:11:13 | LL | let _ = x.log(std::f32::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:12:13 + --> $DIR/floating_point_log.rs:12:13 | LL | let _ = x.log(TWO); | ^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:13:13 + --> $DIR/floating_point_log.rs:13:13 | LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:16:13 + --> $DIR/floating_point_log.rs:16:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:17:13 + --> $DIR/floating_point_log.rs:17:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:18:13 + --> $DIR/floating_point_log.rs:18:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:23:13 + --> $DIR/floating_point_log.rs:23:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:24:13 + --> $DIR/floating_point_log.rs:24:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:25:13 + --> $DIR/floating_point_log.rs:25:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:26:13 + --> $DIR/floating_point_log.rs:26:13 | LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:27:13 + --> $DIR/floating_point_log.rs:27:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:34:13 + --> $DIR/floating_point_log.rs:34:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:35:13 + --> $DIR/floating_point_log.rs:35:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:36:13 + --> $DIR/floating_point_log.rs:36:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` -error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:45:13 - | -LL | let _ = 2f32.powf(x); - | ^^^^^^^^^^^^ help: consider using: `x.exp2()` - -error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:46:13 - | -LL | let _ = std::f32::consts::E.powf(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` - -error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_arithmetic.rs:47:13 - | -LL | let _ = x.powf(1.0 / 2.0); - | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` - -error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:48:13 - | -LL | let _ = x.powf(1.0 / 3.0); - | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` - -error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:49:13 - | -LL | let _ = x.powf(2.0); - | ^^^^^^^^^^^ help: consider using: `x.powi(2)` - -error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:50:13 - | -LL | let _ = x.powf(-2.0); - | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` - -error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:57:13 - | -LL | let _ = 2f64.powf(x); - | ^^^^^^^^^^^^ help: consider using: `x.exp2()` - -error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:58:13 - | -LL | let _ = std::f64::consts::E.powf(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` - -error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_arithmetic.rs:59:13 - | -LL | let _ = x.powf(1.0 / 2.0); - | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` - -error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:60:13 - | -LL | let _ = x.powf(1.0 / 3.0); - | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` - -error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:61:13 - | -LL | let _ = x.powf(2.0); - | ^^^^^^^^^^^ help: consider using: `x.powi(2)` - -error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_arithmetic.rs:62:13 - | -LL | let _ = x.powf(-2.0); - | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` - -error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:71:13 - | -LL | let _ = x.exp() - 1.0; - | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` - -error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:72:13 - | -LL | let _ = x.exp() - 1.0 + 2.0; - | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` - -error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:78:13 - | -LL | let _ = x.exp() - 1.0; - | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` - -error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_arithmetic.rs:79:13 - | -LL | let _ = x.exp() - 1.0 + 2.0; - | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` - error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:90:13 + --> $DIR/floating_point_log.rs:48:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:91:13 + --> $DIR/floating_point_log.rs:49:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:92:13 + --> $DIR/floating_point_log.rs:50:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:93:13 + --> $DIR/floating_point_log.rs:51:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:94:13 + --> $DIR/floating_point_log.rs:52:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:96:13 + --> $DIR/floating_point_log.rs:54:13 | LL | let _ = x.log(b) / 2f32.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:102:13 + --> $DIR/floating_point_log.rs:60:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:103:13 + --> $DIR/floating_point_log.rs:61:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:104:13 + --> $DIR/floating_point_log.rs:62:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:105:13 + --> $DIR/floating_point_log.rs:63:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:106:13 + --> $DIR/floating_point_log.rs:64:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_arithmetic.rs:108:13 + --> $DIR/floating_point_log.rs:66:13 | LL | let _ = x.log(b) / 2f64.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` -error: aborting due to 44 previous errors +error: aborting due to 28 previous errors diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs new file mode 100644 index 000000000000..14f1f531f0f8 --- /dev/null +++ b/tests/ui/floating_point_powf.rs @@ -0,0 +1,27 @@ +#![warn(clippy::floating_point_improvements)] + +fn main() { + let x = 3f32; + let _ = 2f32.powf(x); + let _ = std::f32::consts::E.powf(x); + let _ = x.powf(1.0 / 2.0); + let _ = x.powf(1.0 / 3.0); + let _ = x.powf(2.0); + let _ = x.powf(-2.0); + let _ = x.powf(2.1); + let _ = x.powf(-2.1); + let _ = x.powf(16_777_217.0); + let _ = x.powf(-16_777_217.0); + + let x = 3f64; + let _ = 2f64.powf(x); + let _ = std::f64::consts::E.powf(x); + let _ = x.powf(1.0 / 2.0); + let _ = x.powf(1.0 / 3.0); + let _ = x.powf(2.0); + let _ = x.powf(-2.0); + let _ = x.powf(2.1); + let _ = x.powf(-2.1); + let _ = x.powf(9_007_199_254_740_993.0); + let _ = x.powf(-9_007_199_254_740_993.0); +} diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr new file mode 100644 index 000000000000..2be54af96c6b --- /dev/null +++ b/tests/ui/floating_point_powf.stderr @@ -0,0 +1,76 @@ +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:5:13 + | +LL | let _ = 2f32.powf(x); + | ^^^^^^^^^^^^ help: consider using: `x.exp2()` + | + = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:6:13 + | +LL | let _ = std::f32::consts::E.powf(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` + +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_powf.rs:7:13 + | +LL | let _ = x.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` + +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_powf.rs:8:13 + | +LL | let _ = x.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:9:13 + | +LL | let _ = x.powf(2.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(2)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:10:13 + | +LL | let _ = x.powf(-2.0); + | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:17:13 + | +LL | let _ = 2f64.powf(x); + | ^^^^^^^^^^^^ help: consider using: `x.exp2()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:18:13 + | +LL | let _ = std::f64::consts::E.powf(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` + +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_powf.rs:19:13 + | +LL | let _ = x.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` + +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_powf.rs:20:13 + | +LL | let _ = x.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:21:13 + | +LL | let _ = x.powf(2.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(2)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:22:13 + | +LL | let _ = x.powf(-2.0); + | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` + +error: aborting due to 12 previous errors + From de07c8490332c17deafa89d29724a6483a1765b3 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Fri, 20 Dec 2019 20:07:03 -0800 Subject: [PATCH 06/14] Detect usage of `(x + 1).ln()` and suggest `x.ln_1p()` instead --- clippy_lints/src/floating_point_arithmetic.rs | 14 ++-- tests/ui/floating_point_log.rs | 14 +++- tests/ui/floating_point_log.stderr | 80 +++++++++++++++---- 3 files changed, 84 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 7f6dac87d04a..6a1351260783 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -94,16 +94,18 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { } } -// TODO: Lint expressions of the form `(x + 1).ln()` and `(x + y).ln()` -// where y > 1 and suggest usage of `(x + (y - 1)).ln_1p()` instead +// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and +// suggest usage of `(x + (y - 1)).ln_1p()` instead fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { if_chain! { if let ExprKind::Binary(op, ref lhs, ref rhs) = &args[0].kind; if op.node == BinOpKind::Add; - if let Some((value, _)) = constant(cx, cx.tables, lhs); - if F32(1.0) == value || F64(1.0) == value; then { - let arg = sugg::Sugg::hir(cx, rhs, "..").maybe_par(); + let recv = match (constant(cx, cx.tables, lhs), constant(cx, cx.tables, rhs)) { + (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, + _ => return, + }; span_lint_and_sugg( cx, @@ -111,7 +113,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { expr.span, "ln(1 + x) can be computed more accurately", "consider using", - format!("{}.ln_1p()", arg), + format!("{}.ln_1p()", sugg::Sugg::hir(cx, recv, "..").maybe_par()), Applicability::MachineApplicable, ); } diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 4c01d5e716b0..9a46d2803be3 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -25,18 +25,28 @@ fn check_ln1p() { let _ = (1.0 + x.powi(2)).ln(); let _ = (1.0 + x.powi(2) * 2.0).ln(); let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); - // Cases where the lint shouldn't be applied let _ = (x + 1.0).ln(); + let _ = (x.powi(2) + 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 let _ = (1.0 + x + 2.0).ln(); + let _ = (x + 1.0 + 2.0).ln(); + let _ = (x + 1.0 * 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); let x = 1f64; let _ = (1.0 + x).ln(); let _ = (1.0 + x * 2.0).ln(); let _ = (1.0 + x.powi(2)).ln(); - // Cases where the lint shouldn't be applied let _ = (x + 1.0).ln(); + let _ = (x.powi(2) + 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 let _ = (1.0 + x + 2.0).ln(); + let _ = (x + 1.0 + 2.0).ln(); + let _ = (x + 1.0 * 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); } diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index 0a36f8fc69fd..6ae9de02f2ca 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -79,94 +79,142 @@ LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:34:13 + --> $DIR/floating_point_log.rs:28:13 + | +LL | let _ = (x + 1.0).ln(); + | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:29:13 + | +LL | let _ = (x.powi(2) + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:30:13 + | +LL | let _ = (x + 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:31:13 + | +LL | let _ = (x * 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:39:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:35:13 + --> $DIR/floating_point_log.rs:40:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:36:13 + --> $DIR/floating_point_log.rs:41:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:42:13 + | +LL | let _ = (x + 1.0).ln(); + | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:43:13 + | +LL | let _ = (x.powi(2) + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:44:13 + | +LL | let _ = (x + 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:45:13 + | +LL | let _ = (x * 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` + error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:48:13 + --> $DIR/floating_point_log.rs:58:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:49:13 + --> $DIR/floating_point_log.rs:59:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:50:13 + --> $DIR/floating_point_log.rs:60:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:51:13 + --> $DIR/floating_point_log.rs:61:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:52:13 + --> $DIR/floating_point_log.rs:62:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:54:13 + --> $DIR/floating_point_log.rs:64:13 | LL | let _ = x.log(b) / 2f32.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:60:13 + --> $DIR/floating_point_log.rs:70:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:61:13 + --> $DIR/floating_point_log.rs:71:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:62:13 + --> $DIR/floating_point_log.rs:72:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:63:13 + --> $DIR/floating_point_log.rs:73:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:64:13 + --> $DIR/floating_point_log.rs:74:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:66:13 + --> $DIR/floating_point_log.rs:76:13 | LL | let _ = x.log(b) / 2f64.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` -error: aborting due to 28 previous errors +error: aborting due to 36 previous errors From fd2506bcbf99de5f54a40d5156b1bbbca710f6f0 Mon Sep 17 00:00:00 2001 From: Krishna Veera Reddy Date: Fri, 3 Jan 2020 22:19:13 -0800 Subject: [PATCH 07/14] Add type suffixes to unsuffixed method receiver suggestions --- clippy_lints/src/floating_point_arithmetic.rs | 64 ++++++++++++--- tests/ui/floating_point_log.rs | 4 + tests/ui/floating_point_log.stderr | 80 ++++++++++++------- tests/ui/floating_point_powf.rs | 8 ++ tests/ui/floating_point_powf.stderr | 70 +++++++++++++--- 5 files changed, 177 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 6a1351260783..dbf8e0a9ac47 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -7,10 +7,13 @@ use if_chain::if_chain; use rustc::declare_lint_pass; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::ty; use rustc_errors::Applicability; use rustc_session::declare_tool_lint; use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; +use sugg::Sugg; +use syntax::ast; declare_clippy_lint! { /// **What it does:** Looks for floating-point expressions that @@ -80,7 +83,45 @@ fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr) -> Option<& None } -fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { +// Adds type suffixes and parenthesis to method receivers if necessary +fn prepare_receiver_sugg<'a>(cx: &LateContext<'_, '_>, mut expr: &'a Expr<'a>) -> Sugg<'a> { + let mut suggestion = Sugg::hir(cx, expr, ".."); + + if let ExprKind::Unary(UnOp::UnNeg, inner_expr) = &expr.kind { + expr = &inner_expr; + } + + if_chain! { + // if the expression is a float literal and it is unsuffixed then + // add a suffix so the suggestion is valid and unambiguous + if let ty::Float(float_ty) = cx.tables.expr_ty(expr).kind; + if let ExprKind::Lit(lit) = &expr.kind; + if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node; + then { + let op = format!( + "{}{}{}", + suggestion, + // Check for float literals without numbers following the decimal + // separator such as `2.` and adds a trailing zero + if sym.as_str().ends_with('.') { + "0" + } else { + "" + }, + float_ty.name_str() + ).into(); + + suggestion = match suggestion { + Sugg::MaybeParen(_) => Sugg::MaybeParen(op), + _ => Sugg::NonParen(op) + }; + } + } + + suggestion.maybe_par() +} + +fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { if let Some(method) = get_specialized_log_method(cx, &args[1]) { span_lint_and_sugg( cx, @@ -88,7 +129,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method), + format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method), Applicability::MachineApplicable, ); } @@ -113,7 +154,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { expr.span, "ln(1 + x) can be computed more accurately", "consider using", - format!("{}.ln_1p()", sugg::Sugg::hir(cx, recv, "..").maybe_par()), + format!("{}.ln_1p()", prepare_receiver_sugg(cx, recv)), Applicability::MachineApplicable, ); } @@ -164,7 +205,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", - format!("{}.{}()", sugg::Sugg::hir(cx, &args[1], "..").maybe_par(), method), + format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method), Applicability::MachineApplicable, ); } @@ -187,7 +228,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { expr.span, "exponentiation with integer powers can be computed more efficiently", "consider using", - format!("{}.powi({})", sugg::Sugg::hir(cx, &args[0], ".."), exponent), + format!("{}.powi({})", Sugg::hir(cx, &args[0], ".."), exponent), Applicability::MachineApplicable, ); @@ -202,7 +243,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { expr.span, help, "consider using", - format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method), + format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method), Applicability::MachineApplicable, ); } @@ -218,6 +259,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { if let Some((value, _)) = constant(cx, cx.tables, rhs); if F32(1.0) == value || F64(1.0) == value; if let ExprKind::MethodCall(ref path, _, ref method_args) = lhs.kind; + if cx.tables.expr_ty(&method_args[0]).is_floating_point(); if path.ident.name.as_str() == "exp"; then { span_lint_and_sugg( @@ -228,7 +270,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { "consider using", format!( "{}.exp_m1()", - sugg::Sugg::hir(cx, &method_args[0], "..") + Sugg::hir(cx, &method_args[0], "..") ), Applicability::MachineApplicable, ); @@ -275,7 +317,9 @@ fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { if op.node == BinOpKind::Div; if cx.tables.expr_ty(lhs).is_floating_point(); if let ExprKind::MethodCall(left_path, _, left_args) = &lhs.kind; + if cx.tables.expr_ty(&left_args[0]).is_floating_point(); if let ExprKind::MethodCall(right_path, _, right_args) = &rhs.kind; + if cx.tables.expr_ty(&right_args[0]).is_floating_point(); let left_method = left_path.ident.name.as_str(); if left_method == right_path.ident.name.as_str(); if log_methods.iter().any(|&method| left_method == method); @@ -290,12 +334,12 @@ fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { // Reduce the expression further for bases 2, 10 and e let suggestion = if let Some(method) = get_specialized_log_method(cx, right_recv) { - format!("{}.{}()", sugg::Sugg::hir(cx, left_recv, ".."), method) + format!("{}.{}()", Sugg::hir(cx, left_recv, ".."), method) } else { format!( "{}.log({})", - sugg::Sugg::hir(cx, left_recv, ".."), - sugg::Sugg::hir(cx, right_recv, "..") + Sugg::hir(cx, left_recv, ".."), + Sugg::hir(cx, right_recv, "..") ) }; diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 9a46d2803be3..5775d8715d46 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -20,6 +20,8 @@ fn check_log_base() { fn check_ln1p() { let x = 1f32; + let _ = (1f32 + 2.).ln(); + let _ = (1f32 + 2.0).ln(); let _ = (1.0 + x).ln(); let _ = (1.0 + x * 2.0).ln(); let _ = (1.0 + x.powi(2)).ln(); @@ -36,6 +38,8 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); let x = 1f64; + let _ = (1f64 + 2.).ln(); + let _ = (1f64 + 2.0).ln(); let _ = (1.0 + x).ln(); let _ = (1.0 + x * 2.0).ln(); let _ = (1.0 + x.powi(2)).ln(); diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index 6ae9de02f2ca..cd3142e041a2 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -51,170 +51,194 @@ LL | let _ = x.log(std::f64::consts::E); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:23:13 | +LL | let _ = (1f32 + 2.).ln(); + | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:24:13 + | +LL | let _ = (1f32 + 2.0).ln(); + | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:25:13 + | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:24:13 + --> $DIR/floating_point_log.rs:26:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:25:13 + --> $DIR/floating_point_log.rs:27:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:26:13 + --> $DIR/floating_point_log.rs:28:13 | LL | let _ = (1.0 + x.powi(2) * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:27:13 + --> $DIR/floating_point_log.rs:29:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:28:13 + --> $DIR/floating_point_log.rs:30:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:29:13 + --> $DIR/floating_point_log.rs:31:13 | LL | let _ = (x.powi(2) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:30:13 + --> $DIR/floating_point_log.rs:32:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:31:13 + --> $DIR/floating_point_log.rs:33:13 | LL | let _ = (x * 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:39:13 + --> $DIR/floating_point_log.rs:41:13 + | +LL | let _ = (1f64 + 2.).ln(); + | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:42:13 + | +LL | let _ = (1f64 + 2.0).ln(); + | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` + +error: ln(1 + x) can be computed more accurately + --> $DIR/floating_point_log.rs:43:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:40:13 + --> $DIR/floating_point_log.rs:44:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:41:13 + --> $DIR/floating_point_log.rs:45:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:42:13 + --> $DIR/floating_point_log.rs:46:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:43:13 + --> $DIR/floating_point_log.rs:47:13 | LL | let _ = (x.powi(2) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:44:13 + --> $DIR/floating_point_log.rs:48:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:45:13 + --> $DIR/floating_point_log.rs:49:13 | LL | let _ = (x * 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:58:13 + --> $DIR/floating_point_log.rs:62:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:59:13 + --> $DIR/floating_point_log.rs:63:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:60:13 + --> $DIR/floating_point_log.rs:64:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:61:13 + --> $DIR/floating_point_log.rs:65:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:62:13 + --> $DIR/floating_point_log.rs:66:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:64:13 + --> $DIR/floating_point_log.rs:68:13 | LL | let _ = x.log(b) / 2f32.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:70:13 + --> $DIR/floating_point_log.rs:74:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:71:13 + --> $DIR/floating_point_log.rs:75:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:72:13 + --> $DIR/floating_point_log.rs:76:13 | LL | let _ = x.ln() / y.ln(); | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:73:13 + --> $DIR/floating_point_log.rs:77:13 | LL | let _ = x.log(4.0) / y.log(4.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:74:13 + --> $DIR/floating_point_log.rs:78:13 | LL | let _ = x.log(b) / y.log(b); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:76:13 + --> $DIR/floating_point_log.rs:80:13 | LL | let _ = x.log(b) / 2f64.log(b); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` -error: aborting due to 36 previous errors +error: aborting due to 40 previous errors diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 14f1f531f0f8..97a1d93a8019 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -3,7 +3,11 @@ fn main() { let x = 3f32; let _ = 2f32.powf(x); + let _ = 2f32.powf(3.1); + let _ = 2f32.powf(-3.1); let _ = std::f32::consts::E.powf(x); + let _ = std::f32::consts::E.powf(3.1); + 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); @@ -15,7 +19,11 @@ fn main() { let x = 3f64; let _ = 2f64.powf(x); + let _ = 2f64.powf(3.1); + let _ = 2f64.powf(-3.1); let _ = std::f64::consts::E.powf(x); + let _ = std::f64::consts::E.powf(3.1); + 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); diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 2be54af96c6b..4e16e7af0465 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -9,68 +9,116 @@ LL | let _ = 2f32.powf(x); error: exponent for bases 2 and e can be computed more accurately --> $DIR/floating_point_powf.rs:6:13 | +LL | let _ = 2f32.powf(3.1); + | ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:7:13 + | +LL | let _ = 2f32.powf(-3.1); + | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:8:13 + | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:9:13 + | +LL | let _ = std::f32::consts::E.powf(3.1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:10:13 + | +LL | let _ = std::f32::consts::E.powf(-3.1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()` + error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:7:13 + --> $DIR/floating_point_powf.rs:11:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:8:13 + --> $DIR/floating_point_powf.rs:12:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:9:13 + --> $DIR/floating_point_powf.rs:13:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:10:13 + --> $DIR/floating_point_powf.rs:14:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:17:13 + --> $DIR/floating_point_powf.rs:21:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:18:13 + --> $DIR/floating_point_powf.rs:22:13 + | +LL | let _ = 2f64.powf(3.1); + | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:23:13 + | +LL | let _ = 2f64.powf(-3.1); + | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:24:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:25:13 + | +LL | let _ = std::f64::consts::E.powf(3.1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` + +error: exponent for bases 2 and e can be computed more accurately + --> $DIR/floating_point_powf.rs:26:13 + | +LL | let _ = std::f64::consts::E.powf(-3.1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` + error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:19:13 + --> $DIR/floating_point_powf.rs:27:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:20:13 + --> $DIR/floating_point_powf.rs:28:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:21:13 + --> $DIR/floating_point_powf.rs:29:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:22:13 + --> $DIR/floating_point_powf.rs:30:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` -error: aborting due to 12 previous errors +error: aborting due to 20 previous errors From bc03f465c3801887aa53b0f6eaf35d9b55827b95 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Mon, 17 Feb 2020 11:38:35 -0800 Subject: [PATCH 08/14] Remove lint for logarithm division identity --- clippy_lints/src/floating_point_arithmetic.rs | 86 +------------------ tests/ui/floating_point_log.rs | 26 ------ tests/ui/floating_point_log.stderr | 74 +--------------- 3 files changed, 4 insertions(+), 182 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index dbf8e0a9ac47..17babb46daad 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -4,12 +4,11 @@ use crate::consts::{ }; use crate::utils::*; use if_chain::if_chain; -use rustc::declare_lint_pass; -use rustc::hir::*; -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; use rustc::ty; use rustc_errors::Applicability; -use rustc_session::declare_tool_lint; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; use sugg::Sugg; @@ -278,84 +277,6 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { } } -// Checks whether two expressions evaluate to the same value -fn are_exprs_equivalent(cx: &LateContext<'_, '_>, left: &Expr, right: &Expr) -> bool { - // Checks whether the values are constant and equal - if_chain! { - if let Some((left_value, _)) = constant(cx, cx.tables, left); - if let Some((right_value, _)) = constant(cx, cx.tables, right); - if left_value == right_value; - then { - return true; - } - } - - // Checks whether the expressions resolve to the same variable - if_chain! { - if let ExprKind::Path(ref left_qpath) = left.kind; - if let QPath::Resolved(_, ref left_path) = *left_qpath; - if left_path.segments.len() == 1; - if let def::Res::Local(left_local_id) = qpath_res(cx, left_qpath, left.hir_id); - if let ExprKind::Path(ref right_qpath) = right.kind; - if let QPath::Resolved(_, ref right_path) = *right_qpath; - if right_path.segments.len() == 1; - if let def::Res::Local(right_local_id) = qpath_res(cx, right_qpath, right.hir_id); - if left_local_id == right_local_id; - then { - return true; - } - } - - false -} - -fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) { - let log_methods = ["log", "log2", "log10", "ln"]; - - if_chain! { - if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; - if op.node == BinOpKind::Div; - if cx.tables.expr_ty(lhs).is_floating_point(); - if let ExprKind::MethodCall(left_path, _, left_args) = &lhs.kind; - if cx.tables.expr_ty(&left_args[0]).is_floating_point(); - if let ExprKind::MethodCall(right_path, _, right_args) = &rhs.kind; - if cx.tables.expr_ty(&right_args[0]).is_floating_point(); - let left_method = left_path.ident.name.as_str(); - if left_method == right_path.ident.name.as_str(); - if log_methods.iter().any(|&method| left_method == method); - then { - let left_recv = &left_args[0]; - let right_recv = &right_args[0]; - - // Return early when bases are not equal - if left_method == "log" && !are_exprs_equivalent(cx, &left_args[1], &right_args[1]) { - return; - } - - // Reduce the expression further for bases 2, 10 and e - let suggestion = if let Some(method) = get_specialized_log_method(cx, right_recv) { - format!("{}.{}()", Sugg::hir(cx, left_recv, ".."), method) - } else { - format!( - "{}.log({})", - Sugg::hir(cx, left_recv, ".."), - Sugg::hir(cx, right_recv, "..") - ) - }; - - span_lint_and_sugg( - cx, - FLOATING_POINT_IMPROVEMENTS, - expr.span, - "x.log(b) / y.log(b) can be reduced to x.log(y)", - "consider using", - suggestion, - Applicability::MachineApplicable, - ); - } - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { @@ -371,7 +292,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { } } else { check_expm1(cx, expr); - check_log_division(cx, expr); } } } diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 5775d8715d46..18b7686280ec 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -54,30 +54,4 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); } -fn check_log_division() { - let x = 3f32; - let y = 2f32; - let b = 4f32; - - let _ = x.log2() / y.log2(); - let _ = x.log10() / y.log10(); - let _ = x.ln() / y.ln(); - let _ = x.log(4.0) / y.log(4.0); - let _ = x.log(b) / y.log(b); - let _ = x.log(b) / y.log(x); - let _ = x.log(b) / 2f32.log(b); - - let x = 3f64; - let y = 2f64; - let b = 4f64; - - let _ = x.log2() / y.log2(); - let _ = x.log10() / y.log10(); - let _ = x.ln() / y.ln(); - let _ = x.log(4.0) / y.log(4.0); - let _ = x.log(b) / y.log(b); - let _ = x.log(b) / y.log(x); - let _ = x.log(b) / 2f64.log(b); -} - fn main() {} diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index cd3142e041a2..c169745ddf94 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -168,77 +168,5 @@ error: ln(1 + x) can be computed more accurately LL | let _ = (x * 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:62:13 - | -LL | let _ = x.log2() / y.log2(); - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:63:13 - | -LL | let _ = x.log10() / y.log10(); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:64:13 - | -LL | let _ = x.ln() / y.ln(); - | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:65:13 - | -LL | let _ = x.log(4.0) / y.log(4.0); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:66:13 - | -LL | let _ = x.log(b) / y.log(b); - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:68:13 - | -LL | let _ = x.log(b) / 2f32.log(b); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:74:13 - | -LL | let _ = x.log2() / y.log2(); - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:75:13 - | -LL | let _ = x.log10() / y.log10(); - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:76:13 - | -LL | let _ = x.ln() / y.ln(); - | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:77:13 - | -LL | let _ = x.log(4.0) / y.log(4.0); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:78:13 - | -LL | let _ = x.log(b) / y.log(b); - | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` - -error: x.log(b) / y.log(b) can be reduced to x.log(y) - --> $DIR/floating_point_log.rs:80:13 - | -LL | let _ = x.log(b) / 2f64.log(b); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()` - -error: aborting due to 40 previous errors +error: aborting due to 28 previous errors From 6dacb1aa678046940d3fae7a68bd0112accecfd4 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Mon, 17 Feb 2020 12:56:55 -0800 Subject: [PATCH 09/14] Change lint name to `suboptimal_flops` --- CHANGELOG.md | 1 + clippy_lints/src/floating_point_arithmetic.rs | 39 +++++++++---------- clippy_lints/src/lib.rs | 3 +- src/lintlist/mod.rs | 7 ++++ tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_exp.stderr | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_log.stderr | 2 +- tests/ui/floating_point_powf.rs | 6 +-- tests/ui/floating_point_powf.stderr | 22 +++++------ 10 files changed, 45 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e99342e4a42..87ece835f7f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1349,6 +1349,7 @@ Released 2018-09-13 [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools +[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 17babb46daad..61938405d92d 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -4,10 +4,10 @@ use crate::consts::{ }; use crate::utils::*; use if_chain::if_chain; -use rustc_hir::*; -use rustc_lint::{LateContext, LateLintPass}; use rustc::ty; use rustc_errors::Applicability; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; @@ -16,11 +16,10 @@ use syntax::ast; declare_clippy_lint! { /// **What it does:** Looks for floating-point expressions that - /// can be expressed using built-in methods to improve accuracy, - /// performance and/or succinctness. + /// can be expressed using built-in methods to improve both + /// accuracy and performance. /// - /// **Why is this bad?** Negatively affects accuracy, performance - /// and/or readability. + /// **Why is this bad?** Negatively impacts accuracy and performance. /// /// **Known problems:** None /// @@ -59,16 +58,16 @@ declare_clippy_lint! { /// let _ = a.exp_m1(); /// let _ = a.powi(2); /// ``` - pub FLOATING_POINT_IMPROVEMENTS, + pub SUBOPTIMAL_FLOPS, nursery, - "looks for improvements to floating-point expressions" + "usage of sub-optimal floating point operations" } -declare_lint_pass!(FloatingPointArithmetic => [FLOATING_POINT_IMPROVEMENTS]); +declare_lint_pass!(FloatingPointArithmetic => [SUBOPTIMAL_FLOPS]); // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e -fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr) -> Option<&'static str> { +fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr<'_>) -> Option<&'static str> { if let Some((value, _)) = constant(cx, cx.tables, base) { if F32(2.0) == value || F64(2.0) == value { return Some("log2"); @@ -124,7 +123,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) if let Some(method) = get_specialized_log_method(cx, &args[1]) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", @@ -136,7 +135,7 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and // suggest usage of `(x + (y - 1)).ln_1p()` instead -fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { +fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { if_chain! { if let ExprKind::Binary(op, ref lhs, ref rhs) = &args[0].kind; if op.node == BinOpKind::Add; @@ -149,7 +148,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "ln(1 + x) can be computed more accurately", "consider using", @@ -185,7 +184,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { } } -fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { +fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver if let Some((value, _)) = constant(cx, cx.tables, &args[0]) { let method; @@ -200,7 +199,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", @@ -223,7 +222,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { } else if let Some(exponent) = get_integer_from_float_constant(&value) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "exponentiation with integer powers can be computed more efficiently", "consider using", @@ -238,7 +237,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, help, "consider using", @@ -250,7 +249,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec) { // 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) { +fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; if op.node == BinOpKind::Sub; @@ -263,7 +262,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { then { span_lint_and_sugg( cx, - FLOATING_POINT_IMPROVEMENTS, + SUBOPTIMAL_FLOPS, expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", @@ -278,7 +277,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { let recv_ty = cx.tables.expr_ty(&args[0]); diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9154a0dc3fff..59ad7e7a651a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -538,6 +538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &fallible_impl_from::FALLIBLE_IMPL_FROM, &float_literal::EXCESSIVE_PRECISION, &float_literal::LOSSY_FLOAT_LITERAL, + &floating_point_arithmetic::SUBOPTIMAL_FLOPS, &format::USELESS_FORMAT, &formatting::POSSIBLE_MISSING_COMMA, &formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING, @@ -1649,7 +1650,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), - LintId::of(&floating_point_arithmetic::FLOATING_POINT_IMPROVEMENTS), + LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 29b5a7ba08a2..de086f863e01 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1960,6 +1960,13 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "excessive_bools", }, + Lint { + name: "suboptimal_flops", + group: "nursery", + desc: "usage of sub-optimal floating point operations", + deprecation: None, + module: "floating_point_arithmetic", + }, Lint { name: "suspicious_arithmetic_impl", group: "correctness", diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index 303c6124775c..c7fe0d035689 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,4 +1,4 @@ -#![warn(clippy::floating_point_improvements)] +#![warn(clippy::suboptimal_flops)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index 783218999458..83adca8a46c9 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -4,7 +4,7 @@ error: (e.pow(x) - 1) can be computed more accurately LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` | - = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: (e.pow(x) - 1) can be computed more accurately --> $DIR/floating_point_exp.rs:6:13 diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 18b7686280ec..c26f71f3067d 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -#![warn(clippy::floating_point_improvements)] +#![warn(clippy::suboptimal_flops)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index c169745ddf94..db2fc999b6c3 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -4,7 +4,7 @@ error: logarithm for bases 2, 10 and e can be computed more accurately LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` | - = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: logarithm for bases 2, 10 and e can be computed more accurately --> $DIR/floating_point_log.rs:10:13 diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 97a1d93a8019..2076821b5b04 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,4 +1,4 @@ -#![warn(clippy::floating_point_improvements)] +#![warn(clippy::suboptimal_flops)] fn main() { let x = 3f32; @@ -14,8 +14,6 @@ fn main() { let _ = x.powf(-2.0); let _ = x.powf(2.1); let _ = x.powf(-2.1); - let _ = x.powf(16_777_217.0); - let _ = x.powf(-16_777_217.0); let x = 3f64; let _ = 2f64.powf(x); @@ -30,6 +28,4 @@ fn main() { let _ = x.powf(-2.0); let _ = x.powf(2.1); let _ = x.powf(-2.1); - let _ = x.powf(9_007_199_254_740_993.0); - let _ = x.powf(-9_007_199_254_740_993.0); } diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 4e16e7af0465..35e0c5e56fd8 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -4,7 +4,7 @@ error: exponent for bases 2 and e can be computed more accurately LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` | - = note: `-D clippy::floating-point-improvements` implied by `-D warnings` + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: exponent for bases 2 and e can be computed more accurately --> $DIR/floating_point_powf.rs:6:13 @@ -61,61 +61,61 @@ LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:21:13 + --> $DIR/floating_point_powf.rs:19:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:22:13 + --> $DIR/floating_point_powf.rs:20:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:23:13 + --> $DIR/floating_point_powf.rs:21:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:24:13 + --> $DIR/floating_point_powf.rs:22:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:25:13 + --> $DIR/floating_point_powf.rs:23:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:26:13 + --> $DIR/floating_point_powf.rs:24:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:27:13 + --> $DIR/floating_point_powf.rs:25:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:26:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:29:13 + --> $DIR/floating_point_powf.rs:27:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:30:13 + --> $DIR/floating_point_powf.rs:28:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` From bc706e3ba93be678852950fdef8cd10790aadfc4 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Sat, 22 Feb 2020 20:29:22 -0800 Subject: [PATCH 10/14] Fix `powi` suggestion and add general improvements --- clippy_lints/src/floating_point_arithmetic.rs | 72 +++++++++---------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 61938405d92d..d342afbc12a4 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; -use sugg::Sugg; +use sugg::{format_numeric_literal, Sugg}; use syntax::ast; declare_clippy_lint! { @@ -159,23 +159,23 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } -// Returns an integer if the float constant is a whole number and it -// can be converted to an integer without loss -// TODO: Add a better check to determine whether the float can be -// casted without loss +// Returns an integer if the float constant is a whole number and it can be +// converted to an integer without loss of precision. For now we only check +// ranges [-16777215, 16777216) for type f32 as whole number floats outside +// this range are lossy and ambiguous. #[allow(clippy::cast_possible_truncation)] -fn get_integer_from_float_constant(value: &Constant) -> Option { +fn get_integer_from_float_constant(value: &Constant) -> Option { match value { - F32(num) if (num.trunc() - num).abs() <= std::f32::EPSILON => { - if *num > -16_777_217.0 && *num < 16_777_217.0 { - Some(num.round() as i64) + F32(num) if num.fract() == 0.0 => { + if (-16_777_215.0..16_777_216.0).contains(num) { + Some(num.round() as i32) } else { None } }, - F64(num) if (num.trunc() - num).abs() <= std::f64::EPSILON => { - if *num > -9_007_199_254_740_993.0 && *num < 9_007_199_254_740_993.0 { - Some(num.round() as i64) + F64(num) if num.fract() == 0.0 => { + if (-2_147_483_648.0..2_147_483_648.0).contains(num) { + Some(num.round() as i32) } else { None } @@ -187,15 +187,13 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver if let Some((value, _)) = constant(cx, cx.tables, &args[0]) { - let method; - - if F32(f32_consts::E) == value || F64(f64_consts::E) == value { - method = "exp"; + let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + "exp" } else if F32(2.0) == value || F64(2.0) == value { - method = "exp2"; + "exp2" } else { return; - } + }; span_lint_and_sugg( cx, @@ -210,30 +208,28 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check argument if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { - let help; - let method; - - if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { - help = "square-root of a number can be computed more efficiently and accurately"; - method = "sqrt"; + let (help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { + ( + "square-root of a number can be computed more efficiently and accurately", + format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")) + ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { - help = "cube-root of a number can be computed more accurately"; - method = "cbrt"; + ( + "cube-root of a number can be computed more accurately", + format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")) + ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, + ( "exponentiation with integer powers can be computed more efficiently", - "consider using", - format!("{}.powi({})", Sugg::hir(cx, &args[0], ".."), exponent), - Applicability::MachineApplicable, - ); - - return; + format!( + "{}.powi({})", + Sugg::hir(cx, &args[0], ".."), + format_numeric_literal(&exponent.to_string(), None, false) + ) + ) } else { return; - } + }; span_lint_and_sugg( cx, @@ -241,7 +237,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { expr.span, help, "consider using", - format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method), + suggestion, Applicability::MachineApplicable, ); } From 454e505c12d6ca2d3c360e9d33d629c2e5652514 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Sat, 22 Feb 2020 20:32:13 -0800 Subject: [PATCH 11/14] Run rust-fix on tests --- tests/ui/floating_point_exp.fixed | 18 ++++++++ tests/ui/floating_point_exp.rs | 1 + tests/ui/floating_point_exp.stderr | 8 ++-- tests/ui/floating_point_log.fixed | 58 +++++++++++++++++++++++++ tests/ui/floating_point_log.rs | 3 +- tests/ui/floating_point_log.stderr | 56 ++++++++++++------------ tests/ui/floating_point_powf.fixed | 40 +++++++++++++++++ tests/ui/floating_point_powf.rs | 9 ++++ tests/ui/floating_point_powf.stderr | 66 ++++++++++++++++++++--------- 9 files changed, 205 insertions(+), 54 deletions(-) create mode 100644 tests/ui/floating_point_exp.fixed create mode 100644 tests/ui/floating_point_log.fixed create mode 100644 tests/ui/floating_point_powf.fixed diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed new file mode 100644 index 000000000000..1f534e3705d8 --- /dev/null +++ b/tests/ui/floating_point_exp.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 2f32; + let _ = x.exp_m1(); + let _ = x.exp_m1() + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; + + let x = 2f64; + let _ = x.exp_m1(); + let _ = x.exp_m1() + 2.0; + // Cases where the lint shouldn't be applied + let _ = x.exp() - 2.0; + let _ = x.exp() - 1.0 * 2.0; +} diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index c7fe0d035689..bed8d3121408 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::suboptimal_flops)] fn main() { diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index 83adca8a46c9..7882b2c24e3a 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -1,5 +1,5 @@ error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:5:13 + --> $DIR/floating_point_exp.rs:6:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` @@ -7,19 +7,19 @@ LL | let _ = x.exp() - 1.0; = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:6:13 + --> $DIR/floating_point_exp.rs:7:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:12:13 + --> $DIR/floating_point_exp.rs:13:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:13:13 + --> $DIR/floating_point_exp.rs:14:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed new file mode 100644 index 000000000000..ead45fc4a9f2 --- /dev/null +++ b/tests/ui/floating_point_log.fixed @@ -0,0 +1,58 @@ +// run-rustfix +#![allow(dead_code, clippy::double_parens)] +#![warn(clippy::suboptimal_flops)] + +const TWO: f32 = 2.0; +const E: f32 = std::f32::consts::E; + +fn check_log_base() { + let x = 1f32; + let _ = x.log2(); + let _ = x.log10(); + let _ = x.ln(); + let _ = x.log2(); + let _ = x.ln(); + + let x = 1f64; + let _ = x.log2(); + let _ = x.log10(); + let _ = x.ln(); +} + +fn check_ln1p() { + let x = 1f32; + let _ = 2.0f32.ln_1p(); + 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 _ = ((std::f32::consts::E - 1.0)).ln_1p(); + let _ = x.ln_1p(); + let _ = x.powi(2).ln_1p(); + let _ = (x + 2.0).ln_1p(); + let _ = (x * 2.0).ln_1p(); + // Cases where the lint shouldn't be applied + let _ = (1.0 + x + 2.0).ln(); + let _ = (x + 1.0 + 2.0).ln(); + let _ = (x + 1.0 * 2.0).ln(); + let _ = (1.0 + x - 2.0).ln(); + + let x = 1f64; + let _ = 2.0f64.ln_1p(); + let _ = 2.0f64.ln_1p(); + let _ = x.ln_1p(); + let _ = (x * 2.0).ln_1p(); + let _ = x.powi(2).ln_1p(); + let _ = x.ln_1p(); + let _ = x.powi(2).ln_1p(); + let _ = (x + 2.0).ln_1p(); + let _ = (x * 2.0).ln_1p(); + // Cases where the lint shouldn't be applied + let _ = (1.0 + x + 2.0).ln(); + let _ = (x + 1.0 + 2.0).ln(); + let _ = (x + 1.0 * 2.0).ln(); + let _ = (1.0 + x - 2.0).ln(); +} + +fn main() {} diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index c26f71f3067d..f888e1375dcf 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,4 +1,5 @@ -#![allow(dead_code)] +// run-rustfix +#![allow(dead_code, clippy::double_parens)] #![warn(clippy::suboptimal_flops)] const TWO: f32 = 2.0; diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index db2fc999b6c3..c8c32b61ca36 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -1,5 +1,5 @@ error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:9:13 + --> $DIR/floating_point_log.rs:10:13 | LL | let _ = x.log(2f32); | ^^^^^^^^^^^ help: consider using: `x.log2()` @@ -7,163 +7,163 @@ LL | let _ = x.log(2f32); = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:10:13 + --> $DIR/floating_point_log.rs:11:13 | LL | let _ = x.log(10f32); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:11:13 + --> $DIR/floating_point_log.rs:12:13 | LL | let _ = x.log(std::f32::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:12:13 + --> $DIR/floating_point_log.rs:13:13 | LL | let _ = x.log(TWO); | ^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:13:13 + --> $DIR/floating_point_log.rs:14:13 | LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:16:13 + --> $DIR/floating_point_log.rs:17:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:17:13 + --> $DIR/floating_point_log.rs:18:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:18:13 + --> $DIR/floating_point_log.rs:19:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:23:13 + --> $DIR/floating_point_log.rs:24:13 | LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:24:13 + --> $DIR/floating_point_log.rs:25:13 | LL | let _ = (1f32 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:25:13 + --> $DIR/floating_point_log.rs:26:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:26:13 + --> $DIR/floating_point_log.rs:27:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:27:13 + --> $DIR/floating_point_log.rs:28:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:28:13 + --> $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()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:29:13 + --> $DIR/floating_point_log.rs:30:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:30:13 + --> $DIR/floating_point_log.rs:31:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:31:13 + --> $DIR/floating_point_log.rs:32:13 | LL | let _ = (x.powi(2) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:32:13 + --> $DIR/floating_point_log.rs:33:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:33:13 + --> $DIR/floating_point_log.rs:34:13 | LL | let _ = (x * 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:41:13 + --> $DIR/floating_point_log.rs:42:13 | LL | let _ = (1f64 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:42:13 + --> $DIR/floating_point_log.rs:43:13 | LL | let _ = (1f64 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:43:13 + --> $DIR/floating_point_log.rs:44:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:44:13 + --> $DIR/floating_point_log.rs:45:13 | LL | let _ = (1.0 + x * 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:45:13 + --> $DIR/floating_point_log.rs:46:13 | LL | let _ = (1.0 + x.powi(2)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:46:13 + --> $DIR/floating_point_log.rs:47:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:47:13 + --> $DIR/floating_point_log.rs:48:13 | LL | let _ = (x.powi(2) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:48:13 + --> $DIR/floating_point_log.rs:49:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:49:13 + --> $DIR/floating_point_log.rs:50:13 | LL | let _ = (x * 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed new file mode 100644 index 000000000000..54d130a22beb --- /dev/null +++ b/tests/ui/floating_point_powf.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let _ = x.exp2(); + let _ = 3.1f32.exp2(); + let _ = (-3.1f32).exp2(); + let _ = x.exp(); + let _ = 3.1f32.exp(); + let _ = (-3.1f32).exp(); + let _ = x.sqrt(); + let _ = x.cbrt(); + let _ = x.powi(2); + let _ = x.powi(-2); + let _ = x.powi(16_777_215); + let _ = x.powi(-16_777_215); + let _ = x.powf(2.1); + let _ = x.powf(-2.1); + let _ = x.powf(16_777_216.0); + let _ = x.powf(-16_777_216.0); + + let x = 3f64; + let _ = x.exp2(); + let _ = 3.1f64.exp2(); + let _ = (-3.1f64).exp2(); + let _ = x.exp(); + let _ = 3.1f64.exp(); + let _ = (-3.1f64).exp(); + let _ = x.sqrt(); + let _ = x.cbrt(); + let _ = x.powi(2); + let _ = x.powi(-2); + let _ = x.powi(-2_147_483_648); + let _ = x.powi(2_147_483_647); + let _ = x.powf(2.1); + let _ = x.powf(-2.1); + let _ = x.powf(-2_147_483_649.0); + let _ = x.powf(2_147_483_648.0); +} diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 2076821b5b04..c1b64d704cd6 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,3 +1,4 @@ +// run-rustfix #![warn(clippy::suboptimal_flops)] fn main() { @@ -12,8 +13,12 @@ fn main() { let _ = x.powf(1.0 / 3.0); let _ = x.powf(2.0); let _ = x.powf(-2.0); + let _ = x.powf(16_777_215.0); + let _ = x.powf(-16_777_215.0); let _ = x.powf(2.1); let _ = x.powf(-2.1); + let _ = x.powf(16_777_216.0); + let _ = x.powf(-16_777_216.0); let x = 3f64; let _ = 2f64.powf(x); @@ -26,6 +31,10 @@ fn main() { let _ = x.powf(1.0 / 3.0); let _ = x.powf(2.0); let _ = x.powf(-2.0); + let _ = x.powf(-2_147_483_648.0); + let _ = x.powf(2_147_483_647.0); let _ = x.powf(2.1); let _ = x.powf(-2.1); + let _ = x.powf(-2_147_483_649.0); + let _ = x.powf(2_147_483_648.0); } diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 35e0c5e56fd8..2b912c5940ed 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -1,5 +1,5 @@ error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:5:13 + --> $DIR/floating_point_powf.rs:6:13 | LL | let _ = 2f32.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` @@ -7,118 +7,142 @@ LL | let _ = 2f32.powf(x); = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:6:13 + --> $DIR/floating_point_powf.rs:7:13 | LL | let _ = 2f32.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:7:13 + --> $DIR/floating_point_powf.rs:8:13 | LL | let _ = 2f32.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:8:13 + --> $DIR/floating_point_powf.rs:9:13 | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:9:13 + --> $DIR/floating_point_powf.rs:10:13 | LL | let _ = std::f32::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:10:13 + --> $DIR/floating_point_powf.rs:11:13 | LL | let _ = std::f32::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:11:13 + --> $DIR/floating_point_powf.rs:12:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:12:13 + --> $DIR/floating_point_powf.rs:13:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:13:13 + --> $DIR/floating_point_powf.rs:14:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:14:13 + --> $DIR/floating_point_powf.rs:15:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:16:13 + | +LL | let _ = x.powf(16_777_215.0); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:17:13 + | +LL | let _ = x.powf(-16_777_215.0); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)` + error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:19:13 + --> $DIR/floating_point_powf.rs:24:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:20:13 + --> $DIR/floating_point_powf.rs:25:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:21:13 + --> $DIR/floating_point_powf.rs:26:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:22:13 + --> $DIR/floating_point_powf.rs:27:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:23:13 + --> $DIR/floating_point_powf.rs:28:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:24:13 + --> $DIR/floating_point_powf.rs:29:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:25:13 + --> $DIR/floating_point_powf.rs:30:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:26:13 + --> $DIR/floating_point_powf.rs:31:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:27:13 + --> $DIR/floating_point_powf.rs:32:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:33:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` -error: aborting due to 20 previous errors +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:34:13 + | +LL | let _ = x.powf(-2_147_483_648.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:35:13 + | +LL | let _ = x.powf(2_147_483_647.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` + +error: aborting due to 24 previous errors From 4065ca9c8c4586e99688de53c7cf654c7693fc63 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Sun, 23 Feb 2020 00:04:11 -0800 Subject: [PATCH 12/14] Move `manual_mul_add` into `suboptimal_flops` lint --- CHANGELOG.md | 1 - clippy_lints/src/floating_point_arithmetic.rs | 59 +++++++++- clippy_lints/src/lib.rs | 5 +- clippy_lints/src/mul_add.rs | 111 ------------------ src/lintlist/mod.rs | 7 -- tests/ui/floating_point_fma.fixed | 21 ++++ tests/ui/floating_point_fma.rs | 21 ++++ tests/ui/floating_point_fma.stderr | 58 +++++++++ tests/ui/floating_point_log.fixed | 14 +-- tests/ui/floating_point_log.rs | 14 +-- tests/ui/floating_point_log.stderr | 20 ++-- tests/ui/mul_add.rs | 16 --- tests/ui/mul_add.stderr | 34 ------ tests/ui/mul_add_fixable.fixed | 24 ---- tests/ui/mul_add_fixable.rs | 24 ---- tests/ui/mul_add_fixable.stderr | 40 ------- 16 files changed, 179 insertions(+), 290 deletions(-) delete mode 100644 clippy_lints/src/mul_add.rs create mode 100644 tests/ui/floating_point_fma.fixed create mode 100644 tests/ui/floating_point_fma.rs create mode 100644 tests/ui/floating_point_fma.stderr delete mode 100644 tests/ui/mul_add.rs delete mode 100644 tests/ui/mul_add.stderr delete mode 100644 tests/ui/mul_add_fixable.fixed delete mode 100644 tests/ui/mul_add_fixable.rs delete mode 100644 tests/ui/mul_add_fixable.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ece835f7f0..ce696aa85501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1210,7 +1210,6 @@ Released 2018-09-13 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy -[`manual_mul_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_mul_add [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index d342afbc12a4..fbc375c655e6 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,11 +2,11 @@ use crate::consts::{ constant, Constant, Constant::{F32, F64}, }; -use crate::utils::*; +use crate::utils::{span_lint_and_sugg, sugg}; use if_chain::if_chain; use rustc::ty; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::f32::consts as f32_consts; @@ -39,6 +39,7 @@ declare_clippy_lint! { /// let _ = (1.0 + a).ln(); /// let _ = a.exp() - 1.0; /// let _ = a.powf(2.0); + /// let _ = a * 2.0 + 4.0; /// ``` /// /// is better expressed as @@ -57,6 +58,7 @@ declare_clippy_lint! { /// let _ = a.ln_1p(); /// let _ = a.exp_m1(); /// let _ = a.powi(2); + /// let _ = a.mul_add(2.0, 4.0); /// ``` pub SUBOPTIMAL_FLOPS, nursery, @@ -211,12 +213,12 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { let (help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")) + format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")) + format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -225,7 +227,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "{}.powi({})", Sugg::hir(cx, &args[0], ".."), format_numeric_literal(&exponent.to_string(), None, false) - ) + ), ) } else { return; @@ -272,6 +274,52 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { } } +fn is_float_mul_expr<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { + if_chain! { + if let ExprKind::Binary(op, ref lhs, ref rhs) = &expr.kind; + if let BinOpKind::Mul = op.node; + if cx.tables.expr_ty(lhs).is_floating_point(); + if cx.tables.expr_ty(rhs).is_floating_point(); + then { + return Some((lhs, rhs)); + } + } + + None +} + +// TODO: Fix rust-lang/rust-clippy#4735 +fn check_fma(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Binary(op, lhs, rhs) = &expr.kind; + if let BinOpKind::Add = op.node; + then { + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { + (inner_lhs, inner_rhs, rhs) + } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { + (inner_lhs, inner_rhs, lhs) + } else { + return; + }; + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "multiply and add expressions can be calculated more efficiently and accurately", + "consider using", + format!( + "{}.mul_add({}, {})", + prepare_receiver_sugg(cx, recv), + Sugg::hir(cx, arg1, ".."), + Sugg::hir(cx, arg2, ".."), + ), + Applicability::MachineApplicable, + ); + } + } +} + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::MethodCall(ref path, _, args) = &expr.kind { @@ -287,6 +335,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { } } else { check_expm1(cx, expr); + check_fma(cx, expr); } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 59ad7e7a651a..503eb9ec10d6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -208,6 +208,7 @@ pub mod exit; pub mod explicit_write; pub mod fallible_impl_from; pub mod float_literal; +pub mod floating_point_arithmetic; pub mod format; pub mod formatting; pub mod functions; @@ -248,7 +249,6 @@ pub mod missing_const_for_fn; pub mod missing_doc; pub mod missing_inline; pub mod modulo_arithmetic; -pub mod mul_add; pub mod multiple_crate_versions; pub mod mut_key; pub mod mut_mut; @@ -691,7 +691,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, &missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, &modulo_arithmetic::MODULO_ARITHMETIC, - &mul_add::MANUAL_MUL_ADD, &multiple_crate_versions::MULTIPLE_CRATE_VERSIONS, &mut_key::MUTABLE_KEY_TYPE, &mut_mut::MUT_MUT, @@ -967,7 +966,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box inherent_to_string::InherentToString); store.register_late_pass(|| box trait_bounds::TraitBounds); store.register_late_pass(|| box comparison_chain::ComparisonChain); - store.register_late_pass(|| box mul_add::MulAddCheck); store.register_late_pass(|| box mut_key::MutableKeyType); store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); store.register_early_pass(|| box reference::DerefAddrOf); @@ -1652,7 +1650,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), - LintId::of(&mul_add::MANUAL_MUL_ADD), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_INTEGER), LintId::of(&needless_borrow::NEEDLESS_BORROW), diff --git a/clippy_lints/src/mul_add.rs b/clippy_lints/src/mul_add.rs deleted file mode 100644 index 57e56d8f959a..000000000000 --- a/clippy_lints/src/mul_add.rs +++ /dev/null @@ -1,111 +0,0 @@ -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -use crate::utils::{snippet, span_lint_and_sugg}; - -declare_clippy_lint! { - /// **What it does:** Checks for expressions of the form `a * b + c` - /// or `c + a * b` where `a`, `b`, `c` are floats and suggests using - /// `a.mul_add(b, c)` instead. - /// - /// **Why is this bad?** Calculating `a * b + c` may lead to slight - /// numerical inaccuracies as `a * b` is rounded before being added to - /// `c`. Depending on the target architecture, `mul_add()` may be more - /// performant. - /// - /// **Known problems:** This lint can emit semantic incorrect suggestions. - /// For example, for `a * b * c + d` the suggestion `a * b.mul_add(c, d)` - /// is emitted, which is equivalent to `a * (b * c + d)`. (#4735) - /// - /// **Example:** - /// - /// ```rust - /// # let a = 0_f32; - /// # let b = 0_f32; - /// # let c = 0_f32; - /// let foo = (a * b) + c; - /// ``` - /// - /// can be written as - /// - /// ```rust - /// # let a = 0_f32; - /// # let b = 0_f32; - /// # let c = 0_f32; - /// let foo = a.mul_add(b, c); - /// ``` - pub MANUAL_MUL_ADD, - nursery, - "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`" -} - -declare_lint_pass!(MulAddCheck => [MANUAL_MUL_ADD]); - -fn is_float<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>) -> bool { - cx.tables.expr_ty(expr).is_floating_point() -} - -// Checks whether expression is multiplication of two floats -fn is_float_mult_expr<'a, 'tcx, 'b>( - cx: &LateContext<'a, 'tcx>, - expr: &'b Expr<'b>, -) -> Option<(&'b Expr<'b>, &'b Expr<'b>)> { - if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { - if let BinOpKind::Mul = op.node { - if is_float(cx, &lhs) && is_float(cx, &rhs) { - return Some((&lhs, &rhs)); - } - } - } - - None -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MulAddCheck { - fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(op, lhs, rhs) = &expr.kind { - if let BinOpKind::Add = op.node { - //Converts mult_lhs * mult_rhs + rhs to mult_lhs.mult_add(mult_rhs, rhs) - if let Some((mult_lhs, mult_rhs)) = is_float_mult_expr(cx, lhs) { - if is_float(cx, rhs) { - span_lint_and_sugg( - cx, - MANUAL_MUL_ADD, - expr.span, - "consider using `mul_add()` for better numerical precision", - "try", - format!( - "{}.mul_add({}, {})", - snippet(cx, mult_lhs.span, "_"), - snippet(cx, mult_rhs.span, "_"), - snippet(cx, rhs.span, "_"), - ), - Applicability::MaybeIncorrect, - ); - } - } - //Converts lhs + mult_lhs * mult_rhs to mult_lhs.mult_add(mult_rhs, lhs) - if let Some((mult_lhs, mult_rhs)) = is_float_mult_expr(cx, rhs) { - if is_float(cx, lhs) { - span_lint_and_sugg( - cx, - MANUAL_MUL_ADD, - expr.span, - "consider using `mul_add()` for better numerical precision", - "try", - format!( - "{}.mul_add({}, {})", - snippet(cx, mult_lhs.span, "_"), - snippet(cx, mult_rhs.span, "_"), - snippet(cx, lhs.span, "_"), - ), - Applicability::MaybeIncorrect, - ); - } - } - } - } - } -} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index de086f863e01..5b4aad347af2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1022,13 +1022,6 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "loops", }, - Lint { - name: "manual_mul_add", - group: "nursery", - desc: "Using `a.mul_add(b, c)` for floating points has higher numerical precision than `a * b + c`", - deprecation: None, - module: "mul_add", - }, Lint { name: "manual_saturating_arithmetic", group: "style", diff --git a/tests/ui/floating_point_fma.fixed b/tests/ui/floating_point_fma.fixed new file mode 100644 index 000000000000..e343c37740da --- /dev/null +++ b/tests/ui/floating_point_fma.fixed @@ -0,0 +1,21 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + let d: f64 = 0.0001; + + let _ = a.mul_add(b, c); + let _ = a.mul_add(b, c); + let _ = 2.0f64.mul_add(4.0, a); + let _ = 2.0f64.mul_add(4., a); + + let _ = a.mul_add(b, c); + let _ = a.mul_add(b, c); + let _ = (a * b).mul_add(c, d); + + let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; + let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); +} diff --git a/tests/ui/floating_point_fma.rs b/tests/ui/floating_point_fma.rs new file mode 100644 index 000000000000..810f929c8568 --- /dev/null +++ b/tests/ui/floating_point_fma.rs @@ -0,0 +1,21 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + let d: f64 = 0.0001; + + let _ = a * b + c; + let _ = c + a * b; + let _ = a + 2.0 * 4.0; + let _ = a + 2. * 4.; + + let _ = (a * b) + c; + let _ = c + (a * b); + let _ = a * b * c + d; + + let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; +} diff --git a/tests/ui/floating_point_fma.stderr b/tests/ui/floating_point_fma.stderr new file mode 100644 index 000000000000..5c653360ebc8 --- /dev/null +++ b/tests/ui/floating_point_fma.stderr @@ -0,0 +1,58 @@ +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:10:13 + | +LL | let _ = a * b + c; + | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:11:13 + | +LL | let _ = c + a * b; + | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:12:13 + | +LL | let _ = a + 2.0 * 4.0; + | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:13:13 + | +LL | let _ = a + 2. * 4.; + | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:15:13 + | +LL | let _ = (a * b) + c; + | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:16:13 + | +LL | let _ = c + (a * b); + | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:17:13 + | +LL | let _ = a * b * c + d; + | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:19:13 + | +LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_fma.rs:20:13 + | +LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index ead45fc4a9f2..afe72a8dd110 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -24,34 +24,34 @@ fn check_ln1p() { let _ = 2.0f32.ln_1p(); let _ = 2.0f32.ln_1p(); let _ = x.ln_1p(); - let _ = (x * 2.0).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(2) / 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 + 2.0).ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); let x = 1f64; let _ = 2.0f64.ln_1p(); let _ = 2.0f64.ln_1p(); let _ = x.ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); let _ = x.powi(2).ln_1p(); let _ = x.ln_1p(); let _ = x.powi(2).ln_1p(); let _ = (x + 2.0).ln_1p(); - let _ = (x * 2.0).ln_1p(); + let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); } diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index f888e1375dcf..785b5a3bc487 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -24,34 +24,34 @@ fn check_ln1p() { let _ = (1f32 + 2.).ln(); let _ = (1f32 + 2.0).ln(); let _ = (1.0 + x).ln(); - let _ = (1.0 + x * 2.0).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(2) / 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 + 2.0 + 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 let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); let x = 1f64; let _ = (1f64 + 2.).ln(); let _ = (1f64 + 2.0).ln(); let _ = (1.0 + x).ln(); - let _ = (1.0 + x * 2.0).ln(); + let _ = (1.0 + x / 2.0).ln(); let _ = (1.0 + x.powi(2)).ln(); let _ = (x + 1.0).ln(); let _ = (x.powi(2) + 1.0).ln(); let _ = (x + 2.0 + 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 let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); - let _ = (x + 1.0 * 2.0).ln(); + let _ = (x + 1.0 / 2.0).ln(); let _ = (1.0 + x - 2.0).ln(); } diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index c8c32b61ca36..cb0bb6d652a8 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -69,8 +69,8 @@ LL | let _ = (1.0 + x).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:27:13 | -LL | let _ = (1.0 + x * 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (1.0 + x / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:28:13 @@ -81,8 +81,8 @@ LL | let _ = (1.0 + x.powi(2)).ln(); 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(2) / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:30:13 @@ -111,8 +111,8 @@ LL | let _ = (x + 2.0 + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:34:13 | -LL | let _ = (x * 2.0 + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (x / 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:42:13 @@ -135,8 +135,8 @@ LL | let _ = (1.0 + x).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:45:13 | -LL | let _ = (1.0 + x * 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (1.0 + x / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:46:13 @@ -165,8 +165,8 @@ LL | let _ = (x + 2.0 + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:50:13 | -LL | let _ = (x * 2.0 + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()` +LL | let _ = (x / 2.0 + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: aborting due to 28 previous errors diff --git a/tests/ui/mul_add.rs b/tests/ui/mul_add.rs deleted file mode 100644 index 1322e002c641..000000000000 --- a/tests/ui/mul_add.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![warn(clippy::manual_mul_add)] -#![allow(unused_variables)] - -fn mul_add_test() { - let a: f64 = 1234.567; - let b: f64 = 45.67834; - let c: f64 = 0.0004; - - // Examples of not auto-fixable expressions - let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - let test2 = 1234.567 * 45.67834 + 0.0004; -} - -fn main() { - mul_add_test(); -} diff --git a/tests/ui/mul_add.stderr b/tests/ui/mul_add.stderr deleted file mode 100644 index 3b21646f7c30..000000000000 --- a/tests/ui/mul_add.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:17 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(a * b + c).mul_add((c + a * b), (c + (a * b) + c))` - | - = note: `-D clippy::manual-mul-add` implied by `-D warnings` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:17 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:31 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:10:46 - | -LL | let test1 = (a * b + c) * (c + a * b) + (c + (a * b) + c); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add.rs:11:17 - | -LL | let test2 = 1234.567 * 45.67834 + 0.0004; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1234.567.mul_add(45.67834, 0.0004)` - -error: aborting due to 5 previous errors - diff --git a/tests/ui/mul_add_fixable.fixed b/tests/ui/mul_add_fixable.fixed deleted file mode 100644 index 4af7c7e3e1a5..000000000000 --- a/tests/ui/mul_add_fixable.fixed +++ /dev/null @@ -1,24 +0,0 @@ -// run-rustfix - -#![warn(clippy::manual_mul_add)] -#![allow(unused_variables)] - -fn mul_add_test() { - let a: f64 = 1234.567; - let b: f64 = 45.67834; - let c: f64 = 0.0004; - - // Auto-fixable examples - let test1 = a.mul_add(b, c); - let test2 = a.mul_add(b, c); - - let test3 = a.mul_add(b, c); - let test4 = a.mul_add(b, c); - - let test5 = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; - let test6 = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); -} - -fn main() { - mul_add_test(); -} diff --git a/tests/ui/mul_add_fixable.rs b/tests/ui/mul_add_fixable.rs deleted file mode 100644 index 8b42f6f184a4..000000000000 --- a/tests/ui/mul_add_fixable.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-rustfix - -#![warn(clippy::manual_mul_add)] -#![allow(unused_variables)] - -fn mul_add_test() { - let a: f64 = 1234.567; - let b: f64 = 45.67834; - let c: f64 = 0.0004; - - // Auto-fixable examples - let test1 = a * b + c; - let test2 = c + a * b; - - let test3 = (a * b) + c; - let test4 = c + (a * b); - - let test5 = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; - let test6 = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; -} - -fn main() { - mul_add_test(); -} diff --git a/tests/ui/mul_add_fixable.stderr b/tests/ui/mul_add_fixable.stderr deleted file mode 100644 index 235443f4b02b..000000000000 --- a/tests/ui/mul_add_fixable.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:12:17 - | -LL | let test1 = a * b + c; - | ^^^^^^^^^ help: try: `a.mul_add(b, c)` - | - = note: `-D clippy::manual-mul-add` implied by `-D warnings` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:13:17 - | -LL | let test2 = c + a * b; - | ^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:15:17 - | -LL | let test3 = (a * b) + c; - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:16:17 - | -LL | let test4 = c + (a * b); - | ^^^^^^^^^^^ help: try: `a.mul_add(b, c)` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:18:17 - | -LL | let test5 = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` - -error: consider using `mul_add()` for better numerical precision - --> $DIR/mul_add_fixable.rs:19:17 - | -LL | let test6 = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` - -error: aborting due to 6 previous errors - From e94a167508604d4f4d37bbd654fc3a39056ef99b Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Sun, 23 Feb 2020 20:48:57 -0800 Subject: [PATCH 13/14] Rename `mul_add` test file and add general improvements --- clippy_lints/src/floating_point_arithmetic.rs | 108 +++++++++--------- ...fma.fixed => floating_point_mul_add.fixed} | 0 ...point_fma.rs => floating_point_mul_add.rs} | 0 ...a.stderr => floating_point_mul_add.stderr} | 18 +-- tests/ui/floating_point_powf.fixed | 2 + tests/ui/floating_point_powf.rs | 2 + tests/ui/floating_point_powf.stderr | 24 ++-- 7 files changed, 82 insertions(+), 72 deletions(-) rename tests/ui/{floating_point_fma.fixed => floating_point_mul_add.fixed} (100%) rename tests/ui/{floating_point_fma.rs => floating_point_mul_add.rs} (100%) rename tests/ui/{floating_point_fma.stderr => floating_point_mul_add.stderr} (84%) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index fbc375c655e6..542ea5132de8 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -9,6 +9,8 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + use std::f32::consts as f32_consts; use std::f64::consts as f64_consts; use sugg::{format_numeric_literal, Sugg}; @@ -138,26 +140,29 @@ fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and // suggest usage of `(x + (y - 1)).ln_1p()` instead fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if_chain! { - if let ExprKind::Binary(op, ref lhs, ref rhs) = &args[0].kind; - if op.node == BinOpKind::Add; - then { - let recv = match (constant(cx, cx.tables, lhs), constant(cx, cx.tables, rhs)) { - (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, - (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, - _ => return, - }; + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + lhs, + rhs, + ) = &args[0].kind + { + let recv = match (constant(cx, cx.tables, lhs), constant(cx, cx.tables, rhs)) { + (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, + _ => return, + }; - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "ln(1 + x) can be computed more accurately", - "consider using", - format!("{}.ln_1p()", prepare_receiver_sugg(cx, recv)), - Applicability::MachineApplicable, - ); - } + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "ln(1 + x) can be computed more accurately", + "consider using", + format!("{}.ln_1p()", prepare_receiver_sugg(cx, recv)), + Applicability::MachineApplicable, + ); } } @@ -249,8 +254,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // and suggest usage of `x.exp_m1() - (y - 1)` instead fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Binary(op, ref lhs, ref rhs) = expr.kind; - if op.node == BinOpKind::Sub; + if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind; if cx.tables.expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.tables, rhs); if F32(1.0) == value || F64(1.0) == value; @@ -276,8 +280,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { fn is_float_mul_expr<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> { if_chain! { - if let ExprKind::Binary(op, ref lhs, ref rhs) = &expr.kind; - if let BinOpKind::Mul = op.node; + if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref lhs, ref rhs) = &expr.kind; if cx.tables.expr_ty(lhs).is_floating_point(); if cx.tables.expr_ty(rhs).is_floating_point(); then { @@ -289,34 +292,37 @@ fn is_float_mul_expr<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option } // TODO: Fix rust-lang/rust-clippy#4735 -fn check_fma(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::Binary(op, lhs, rhs) = &expr.kind; - if let BinOpKind::Add = op.node; - then { - let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { - (inner_lhs, inner_rhs, rhs) - } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { - (inner_lhs, inner_rhs, lhs) - } else { - return; - }; +fn check_mul_add(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + lhs, + rhs, + ) = &expr.kind + { + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { + (inner_lhs, inner_rhs, rhs) + } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { + (inner_lhs, inner_rhs, lhs) + } else { + return; + }; - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "multiply and add expressions can be calculated more efficiently and accurately", - "consider using", - format!( - "{}.mul_add({}, {})", - prepare_receiver_sugg(cx, recv), - Sugg::hir(cx, arg1, ".."), - Sugg::hir(cx, arg2, ".."), - ), - Applicability::MachineApplicable, - ); - } + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "multiply and add expressions can be calculated more efficiently and accurately", + "consider using", + format!( + "{}.mul_add({}, {})", + prepare_receiver_sugg(cx, recv), + Sugg::hir(cx, arg1, ".."), + Sugg::hir(cx, arg2, ".."), + ), + Applicability::MachineApplicable, + ); } } @@ -335,7 +341,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic { } } else { check_expm1(cx, expr); - check_fma(cx, expr); + check_mul_add(cx, expr); } } } diff --git a/tests/ui/floating_point_fma.fixed b/tests/ui/floating_point_mul_add.fixed similarity index 100% rename from tests/ui/floating_point_fma.fixed rename to tests/ui/floating_point_mul_add.fixed diff --git a/tests/ui/floating_point_fma.rs b/tests/ui/floating_point_mul_add.rs similarity index 100% rename from tests/ui/floating_point_fma.rs rename to tests/ui/floating_point_mul_add.rs diff --git a/tests/ui/floating_point_fma.stderr b/tests/ui/floating_point_mul_add.stderr similarity index 84% rename from tests/ui/floating_point_fma.stderr rename to tests/ui/floating_point_mul_add.stderr index 5c653360ebc8..2dfbf562d15f 100644 --- a/tests/ui/floating_point_fma.stderr +++ b/tests/ui/floating_point_mul_add.stderr @@ -1,5 +1,5 @@ error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:10:13 + --> $DIR/floating_point_mul_add.rs:10:13 | LL | let _ = a * b + c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` @@ -7,49 +7,49 @@ LL | let _ = a * b + c; = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:11:13 + --> $DIR/floating_point_mul_add.rs:11:13 | LL | let _ = c + a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:12:13 + --> $DIR/floating_point_mul_add.rs:12:13 | LL | let _ = a + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:13:13 + --> $DIR/floating_point_mul_add.rs:13:13 | LL | let _ = a + 2. * 4.; | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:15:13 + --> $DIR/floating_point_mul_add.rs:15:13 | LL | let _ = (a * b) + c; | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:16:13 + --> $DIR/floating_point_mul_add.rs:16:13 | LL | let _ = c + (a * b); | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:17:13 + --> $DIR/floating_point_mul_add.rs:17:13 | LL | let _ = a * b * c + d; | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:19:13 + --> $DIR/floating_point_mul_add.rs:19:13 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` error: multiply and add expressions can be calculated more efficiently and accurately - --> $DIR/floating_point_fma.rs:20:13 + --> $DIR/floating_point_mul_add.rs:20:13 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index 54d130a22beb..c5d900de3294 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -15,6 +15,7 @@ fn main() { let _ = x.powi(-2); let _ = x.powi(16_777_215); let _ = x.powi(-16_777_215); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); let _ = x.powf(16_777_216.0); @@ -33,6 +34,7 @@ fn main() { let _ = x.powi(-2); let _ = x.powi(-2_147_483_648); let _ = x.powi(2_147_483_647); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); let _ = x.powf(-2_147_483_649.0); diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index c1b64d704cd6..cc75e230f7d0 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -15,6 +15,7 @@ fn main() { let _ = x.powf(-2.0); let _ = x.powf(16_777_215.0); let _ = x.powf(-16_777_215.0); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); let _ = x.powf(16_777_216.0); @@ -33,6 +34,7 @@ fn main() { let _ = x.powf(-2.0); let _ = x.powf(-2_147_483_648.0); let _ = x.powf(2_147_483_647.0); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); let _ = x.powf(-2_147_483_649.0); diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 2b912c5940ed..8f0544d4b582 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -73,73 +73,73 @@ LL | let _ = x.powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:24:13 + --> $DIR/floating_point_powf.rs:25:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:25:13 + --> $DIR/floating_point_powf.rs:26:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:26:13 + --> $DIR/floating_point_powf.rs:27:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:27:13 + --> $DIR/floating_point_powf.rs:28:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:29:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:29:13 + --> $DIR/floating_point_powf.rs:30:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:30:13 + --> $DIR/floating_point_powf.rs:31:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:31:13 + --> $DIR/floating_point_powf.rs:32:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:32:13 + --> $DIR/floating_point_powf.rs:33:13 | LL | let _ = x.powf(2.0); | ^^^^^^^^^^^ help: consider using: `x.powi(2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:33:13 + --> $DIR/floating_point_powf.rs:34:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:34:13 + --> $DIR/floating_point_powf.rs:35:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:35:13 + --> $DIR/floating_point_powf.rs:36:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` From ff0d44e45a27e688b5ee5447dc9175d5e72b37c9 Mon Sep 17 00:00:00 2001 From: Krishna Sai Veera Reddy Date: Sun, 23 Feb 2020 21:06:55 -0800 Subject: [PATCH 14/14] Add `imprecise_flops` lint Add lint to detect floating point operations that can be computed more accurately at the cost of performance. `cbrt`, `ln_1p` and `exp_m1` library functions call their equivalent cmath implementations which is slower but more accurate so moving checks for these under this new lint. --- CHANGELOG.md | 1 + README.md | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 55 +++++++++++++++---- clippy_lints/src/lib.rs | 2 + src/lintlist/mod.rs | 9 ++- tests/ui/floating_point_exp.fixed | 2 +- tests/ui/floating_point_exp.rs | 2 +- tests/ui/floating_point_exp.stderr | 2 +- tests/ui/floating_point_log.fixed | 2 +- tests/ui/floating_point_log.rs | 2 +- tests/ui/floating_point_log.stderr | 2 + tests/ui/floating_point_powf.fixed | 2 +- tests/ui/floating_point_powf.rs | 2 +- tests/ui/floating_point_powf.stderr | 2 + 14 files changed, 67 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce696aa85501..99e84ea51931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1169,6 +1169,7 @@ Released 2018-09-13 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask diff --git a/README.md b/README.md index 3103f9608398..1300c5ad47bf 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 357 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 358 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 542ea5132de8..eed4f58cf902 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -16,6 +16,39 @@ use std::f64::consts as f64_consts; use sugg::{format_numeric_literal, Sugg}; use syntax::ast; +declare_clippy_lint! { + /// **What it does:** Looks for floating-point expressions that + /// can be expressed using built-in methods to improve accuracy + /// at the cost of performance. + /// + /// **Why is this bad?** Negatively impacts accuracy. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// + /// let a = 3f32; + /// let _ = a.powf(1.0 / 3.0); + /// let _ = (1.0 + a).ln(); + /// let _ = a.exp() - 1.0; + /// ``` + /// + /// is better expressed as + /// + /// ```rust + /// + /// let a = 3f32; + /// let _ = a.cbrt(); + /// let _ = a.ln_1p(); + /// let _ = a.exp_m1(); + /// ``` + pub IMPRECISE_FLOPS, + nursery, + "usage of imprecise floating point operations" +} + declare_clippy_lint! { /// **What it does:** Looks for floating-point expressions that /// can be expressed using built-in methods to improve both @@ -34,12 +67,9 @@ declare_clippy_lint! { /// let _ = (2f32).powf(a); /// let _ = E.powf(a); /// let _ = a.powf(1.0 / 2.0); - /// let _ = a.powf(1.0 / 3.0); /// let _ = a.log(2.0); /// let _ = a.log(10.0); /// let _ = a.log(E); - /// let _ = (1.0 + a).ln(); - /// let _ = a.exp() - 1.0; /// let _ = a.powf(2.0); /// let _ = a * 2.0 + 4.0; /// ``` @@ -53,12 +83,9 @@ declare_clippy_lint! { /// let _ = a.exp2(); /// let _ = a.exp(); /// let _ = a.sqrt(); - /// let _ = a.cbrt(); /// let _ = a.log2(); /// let _ = a.log10(); /// let _ = a.ln(); - /// let _ = a.ln_1p(); - /// let _ = a.exp_m1(); /// let _ = a.powi(2); /// let _ = a.mul_add(2.0, 4.0); /// ``` @@ -67,7 +94,10 @@ declare_clippy_lint! { "usage of sub-optimal floating point operations" } -declare_lint_pass!(FloatingPointArithmetic => [SUBOPTIMAL_FLOPS]); +declare_lint_pass!(FloatingPointArithmetic => [ + IMPRECISE_FLOPS, + SUBOPTIMAL_FLOPS +]); // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e @@ -156,7 +186,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { span_lint_and_sugg( cx, - SUBOPTIMAL_FLOPS, + IMPRECISE_FLOPS, expr.span, "ln(1 + x) can be computed more accurately", "consider using", @@ -215,18 +245,21 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check argument if let Some((value, _)) = constant(cx, cx.tables, &args[1]) { - let (help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { + let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( + SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( + IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( + SUBOPTIMAL_FLOPS, "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", @@ -240,7 +273,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) { span_lint_and_sugg( cx, - SUBOPTIMAL_FLOPS, + lint, expr.span, help, "consider using", @@ -264,7 +297,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { then { span_lint_and_sugg( cx, - SUBOPTIMAL_FLOPS, + IMPRECISE_FLOPS, expr.span, "(e.pow(x) - 1) can be computed more accurately", "consider using", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 503eb9ec10d6..c732657b2e57 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -538,6 +538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &fallible_impl_from::FALLIBLE_IMPL_FROM, &float_literal::EXCESSIVE_PRECISION, &float_literal::LOSSY_FLOAT_LITERAL, + &floating_point_arithmetic::IMPRECISE_FLOPS, &floating_point_arithmetic::SUBOPTIMAL_FLOPS, &format::USELESS_FORMAT, &formatting::POSSIBLE_MISSING_COMMA, @@ -1648,6 +1649,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR), LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM), + LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 5b4aad347af2..15e6a4b6036a 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 357] = [ +pub const ALL_LINTS: [Lint; 358] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -749,6 +749,13 @@ pub const ALL_LINTS: [Lint; 357] = [ deprecation: None, module: "implicit_return", }, + Lint { + name: "imprecise_flops", + group: "nursery", + desc: "usage of imprecise floating point operations", + deprecation: None, + module: "floating_point_arithmetic", + }, Lint { name: "inconsistent_digit_grouping", group: "style", diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed index 1f534e3705d8..ae7805fdf018 100644 --- a/tests/ui/floating_point_exp.fixed +++ b/tests/ui/floating_point_exp.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::imprecise_flops)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index bed8d3121408..27e0b9bcbc93 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::imprecise_flops)] fn main() { let x = 2f32; diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index 7882b2c24e3a..5cd999ad47cd 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -4,7 +4,7 @@ error: (e.pow(x) - 1) can be computed more accurately LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` | - = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: (e.pow(x) - 1) can be computed more accurately --> $DIR/floating_point_exp.rs:7:13 diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index afe72a8dd110..42c5e5d2bae2 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code, clippy::double_parens)] -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 785b5a3bc487..8be0d9ad56fc 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code, clippy::double_parens)] -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] const TWO: f32 = 2.0; const E: f32 = std::f32::consts::E; diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index cb0bb6d652a8..943fbdb0b832 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -53,6 +53,8 @@ error: ln(1 + x) can be computed more accurately | LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` + | + = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:25:13 diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index c5d900de3294..78a9d44829bb 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index cc75e230f7d0..dbc1cac5cb43 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::suboptimal_flops)] +#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] fn main() { let x = 3f32; diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 8f0544d4b582..ad5163f0079b 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -47,6 +47,8 @@ error: cube-root of a number can be computed more accurately | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` + | + = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:14:13