about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/approx_const.rs33
-rw-r--r--tests/ui/approx_const.rs15
-rw-r--r--tests/ui/approx_const.stderr34
3 files changed, 74 insertions, 8 deletions
diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs
index 852e48cbcae..c263d430bd8 100644
--- a/clippy_lints/src/approx_const.rs
+++ b/clippy_lints/src/approx_const.rs
@@ -92,9 +92,11 @@ impl LateLintPass<'_> for ApproxConstant {
 impl ApproxConstant {
     fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) {
         let s = s.as_str();
-        if s.parse::<f64>().is_ok() {
+        if let Ok(maybe_constant) = s.parse::<f64>() {
             for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
-                if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv)) {
+                if is_approx_const(constant, s, maybe_constant, min_digits)
+                    && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv))
+                {
                     span_lint_and_help(
                         cx,
                         APPROX_CONSTANT,
@@ -112,18 +114,35 @@ impl ApproxConstant {
 
 impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
 
+fn count_digits_after_dot(input: &str) -> usize {
+    input
+        .char_indices()
+        .find(|(_, ch)| *ch == '.')
+        .map_or(0, |(i, _)| input.len() - i - 1)
+}
+
 /// Returns `false` if the number of significant figures in `value` are
 /// less than `min_digits`; otherwise, returns true if `value` is equal
-/// to `constant`, rounded to the number of digits present in `value`.
+/// to `constant`, rounded to the number of significant digits present in `value`.
 #[must_use]
-fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
+fn is_approx_const(constant: f64, value: &str, f_value: f64, min_digits: usize) -> bool {
     if value.len() <= min_digits {
+        // The value is not precise enough
         false
-    } else if constant.to_string().starts_with(value) {
-        // The value is a truncated constant
+    } else if f_value.to_string().len() > min_digits && constant.to_string().starts_with(&f_value.to_string()) {
+        // The value represents the same value
         true
     } else {
-        let round_const = format!("{constant:.*}", value.len() - 2);
+        // The value is a truncated constant
+
+        // Print constant with numeric formatting (`0`), with the length of `value` as minimum width
+        // (`value_len$`), and with the same precision as `value` (`.value_prec$`).
+        // See https://doc.rust-lang.org/std/fmt/index.html.
+        let round_const = format!(
+            "{constant:0value_len$.value_prec$}",
+            value_len = value.len(),
+            value_prec = count_digits_after_dot(value)
+        );
         value == round_const
     }
 }
diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs
index 6461666be8f..fc493421a16 100644
--- a/tests/ui/approx_const.rs
+++ b/tests/ui/approx_const.rs
@@ -106,4 +106,19 @@ fn main() {
     //~^ approx_constant
 
     let no_tau = 6.3;
+
+    // issue #15194
+    #[allow(clippy::excessive_precision)]
+    let x: f64 = 3.1415926535897932384626433832;
+    //~^ approx_constant
+
+    #[allow(clippy::excessive_precision)]
+    let _: f64 = 003.14159265358979311599796346854418516159057617187500;
+    //~^ approx_constant
+
+    let almost_frac_1_sqrt_2 = 00.70711;
+    //~^ approx_constant
+
+    let almost_frac_1_sqrt_2 = 00.707_11;
+    //~^ approx_constant
 }
diff --git a/tests/ui/approx_const.stderr b/tests/ui/approx_const.stderr
index f7bda0468cb..32a3517ff2e 100644
--- a/tests/ui/approx_const.stderr
+++ b/tests/ui/approx_const.stderr
@@ -184,5 +184,37 @@ LL |     let almost_tau = 6.28;
    |
    = help: consider using the constant directly
 
-error: aborting due to 23 previous errors
+error: approximate value of `f{32, 64}::consts::PI` found
+  --> tests/ui/approx_const.rs:112:18
+   |
+LL |     let x: f64 = 3.1415926535897932384626433832;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::PI` found
+  --> tests/ui/approx_const.rs:116:18
+   |
+LL |     let _: f64 = 003.14159265358979311599796346854418516159057617187500;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
+  --> tests/ui/approx_const.rs:119:32
+   |
+LL |     let almost_frac_1_sqrt_2 = 00.70711;
+   |                                ^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
+  --> tests/ui/approx_const.rs:122:32
+   |
+LL |     let almost_frac_1_sqrt_2 = 00.707_11;
+   |                                ^^^^^^^^^
+   |
+   = help: consider using the constant directly
+
+error: aborting due to 27 previous errors