diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index b96ae1882..553476f63 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -69,13 +69,16 @@ impl ExcessivePrecision { fn check(&self, sym: &Symbol, fty: &FloatTy) -> Option { let max = max_digits(fty); let sym_str = sym.as_str(); - let formatter = FloatFormat::new(&sym_str); - let digits = count_digits(&sym_str); + if dot_zero_exclusion(&sym_str) { + return None + } // Try to bail out if the float is for sure fine. // If its within the 2 decimal digits of being out of precision we // check if the parsed representation is the same as the string // since we'll need the truncated string anyway. + let digits = count_digits(&sym_str); if digits > max as usize { + let formatter = FloatFormat::new(&sym_str); let sr = match *fty { FloatTy::F32 => sym_str.parse::().map(|f| formatter.format(f)), FloatTy::F64 => sym_str.parse::().map(|f| formatter.format(f)), @@ -86,7 +89,8 @@ impl ExcessivePrecision { if sym_str == s { None } else { - Some(s) + let di = super::literal_representation::DigitInfo::new(&s, true); + Some(di.grouping_hint()) } } else { None @@ -94,6 +98,23 @@ impl ExcessivePrecision { } } +/// Should we exclude the float because it has a .0 suffix +/// Ex 1_000_000_000.0 +fn dot_zero_exclusion(s: &str) -> bool { + if let Some(after_dec) = s.split('.').nth(1) { + let mut decpart = after_dec + .chars() + .take_while(|c| *c != 'e' || *c != 'E'); + + match decpart.next() { + Some('0') => decpart.count() == 0, + _ => false, + } + } else { + false + } +} + fn max_digits(fty: &FloatTy) -> u32 { match fty { FloatTy::F32 => f32::DIGITS, @@ -101,7 +122,9 @@ fn max_digits(fty: &FloatTy) -> u32 { } } +/// Counts the digits excluding leading zeros fn count_digits(s: &str) -> usize { + // Note that s does not contain the f32/64 suffix s.chars() .filter(|c| *c != '-' || *c != '.') .take_while(|c| *c != 'e' || *c != 'E') diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 89396ebd5..6c2351d43 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -81,7 +81,7 @@ declare_clippy_lint! { } #[derive(Debug, PartialEq)] -enum Radix { +pub(super) enum Radix { Binary, Octal, Decimal, @@ -99,7 +99,7 @@ impl Radix { } #[derive(Debug)] -struct DigitInfo<'a> { +pub(super) struct DigitInfo<'a> { /// Characters of a literal between the radix prefix and type suffix. pub digits: &'a str, /// Which radix the literal was represented in. @@ -160,7 +160,7 @@ impl<'a> DigitInfo<'a> { } /// Returns digits grouped in a sensible way. - fn grouping_hint(&self) -> String { + pub fn grouping_hint(&self) -> String { let group_size = self.radix.suggest_grouping(); if self.digits.contains('.') { let mut parts = self.digits.split('.'); diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index d209367cc..47e73aa0b 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -3,45 +3,50 @@ #![allow(print_literal)] fn main() { - // TODO add prefix tests // Consts - const GOOD32_SUF: f32 = 0.123_456_f32; const GOOD32: f32 = 0.123_456; const GOOD32_SM: f32 = 0.000_000_000_1; + const GOOD32_DOT: f32 = 10_000_000_000.0; + const GOOD32_EDGE: f32 = 1.000_000_8; const GOOD64: f64 = 0.123_456_789_012; const GOOD64_SM: f32 = 0.000_000_000_000_000_1; + const GOOD64_DOT: f32 = 10_000_000_000_000_000.0; const BAD32_1: f32 = 0.123_456_789_f32; const BAD32_2: f32 = 0.123_456_789; const BAD32_3: f32 = 0.100_000_000_000_1; + const BAD32_EDGE: f32 = 1.000_000_9; const BAD64_1: f64 = 0.123_456_789_012_345_67f64; const BAD64_2: f64 = 0.123_456_789_012_345_67; const BAD64_3: f64 = 0.100_000_000_000_000_000_1; - // Literal + // Literal as param println!("{}", 8.888_888_888_888_888_888_888); - // TODO add inferred type tests for f32 - // TODO add tests cases exactly on the edge + // // TODO add inferred type tests for f32 // Locals let good32: f32 = 0.123_456_f32; let good32_2: f32 = 0.123_456; - let good64: f64 = 0.123_456_789_012f64; let good64: f64 = 0.123_456_789_012; - let good64_2 = 0.123_456_789_012; + let good64_suf: f64 = 0.123_456_789_012f64; + let good64_inf = 0.123_456_789_012; - let bad32_1: f32 = 1.123_456_789_f32; - let bad32_2: f32 = 1.123_456_789; + let bad32: f32 = 1.123_456_789; + let bad32_suf: f32 = 1.123_456_789_f32; + let bad32_inf = 1.123_456_789_f32; - let bad64_1: f64 = 0.123_456_789_012_345_67f64; - let bad64_2: f64 = 0.123_456_789_012_345_67; - let bad64_3 = 0.123_456_789_012_345_67; + let bad64: f64 = 0.123_456_789_012_345_67; + let bad64_suf: f64 = 0.123_456_789_012_345_67f64; + let bad64_inf = 0.123_456_789_012_345_67; - // TODO Vectors / nested vectors - let vec32: Vec = vec![0.123_456_789]; - let vec64: Vec = vec![0.123_456_789_123_456_789]; + // Vectors + let good_vec32: Vec = vec![0.123_456]; + let good_vec64: Vec = vec![0.123_456_789]; + + let bad_vec32: Vec = vec![0.123_456_789]; + let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; // Exponential float notation let good_e32: f32 = 1e-10; diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index de022afb5..a167deac0 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -1,100 +1,112 @@ error: float has excessive precision - --> $DIR/excessive_precision.rs:14:26 + --> $DIR/excessive_precision.rs:15:26 | -14 | const BAD32_1: f32 = 0.123_456_789_f32; - | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345679` +15 | const BAD32_1: f32 = 0.123_456_789_f32; + | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` | = note: `-D excessive-precision` implied by `-D warnings` -error: float has excessive precision - --> $DIR/excessive_precision.rs:15:26 - | -15 | const BAD32_2: f32 = 0.123_456_789; - | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345679` - error: float has excessive precision --> $DIR/excessive_precision.rs:16:26 | -16 | const BAD32_3: f32 = 0.100_000_000_000_1; +16 | const BAD32_2: f32 = 0.123_456_789; + | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` + +error: float has excessive precision + --> $DIR/excessive_precision.rs:17:26 + | +17 | const BAD32_3: f32 = 0.100_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:18:26 + --> $DIR/excessive_precision.rs:18:29 | -18 | const BAD64_1: f64 = 0.123_456_789_012_345_67f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678901234566` - -error: float has excessive precision - --> $DIR/excessive_precision.rs:19:26 - | -19 | const BAD64_2: f64 = 0.123_456_789_012_345_67; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678901234566` +18 | const BAD32_EDGE: f32 = 1.000_000_9; + | ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001` error: float has excessive precision --> $DIR/excessive_precision.rs:20:26 | -20 | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; +20 | const BAD64_1: f64 = 0.123_456_789_012_345_67f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` + +error: float has excessive precision + --> $DIR/excessive_precision.rs:21:26 + | +21 | const BAD64_2: f64 = 0.123_456_789_012_345_67; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` + +error: float has excessive precision + --> $DIR/excessive_precision.rs:22:26 + | +22 | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:23:20 + --> $DIR/excessive_precision.rs:25:20 | -23 | println!("{}", 8.888_888_888_888_888_888_888); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.88888888888889` +25 | println!("{}", 8.888_888_888_888_888_888_888); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` error: float has excessive precision - --> $DIR/excessive_precision.rs:35:24 + --> $DIR/excessive_precision.rs:36:22 | -35 | let bad32_1: f32 = 1.123_456_789_f32; - | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.1234568` +36 | let bad32: f32 = 1.123_456_789; + | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:36:24 + --> $DIR/excessive_precision.rs:37:26 | -36 | let bad32_2: f32 = 1.123_456_789; - | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.1234568` +37 | let bad32_suf: f32 = 1.123_456_789_f32; + | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:38:24 + --> $DIR/excessive_precision.rs:38:21 | -38 | let bad64_1: f64 = 0.123_456_789_012_345_67f64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678901234566` +38 | let bad32_inf = 1.123_456_789_f32; + | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:39:24 + --> $DIR/excessive_precision.rs:40:22 | -39 | let bad64_2: f64 = 0.123_456_789_012_345_67; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678901234566` +40 | let bad64: f64 = 0.123_456_789_012_345_67; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:40:19 + --> $DIR/excessive_precision.rs:41:26 | -40 | let bad64_3 = 0.123_456_789_012_345_67; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678901234566` +41 | let bad64_suf: f64 = 0.123_456_789_012_345_67f64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:43:32 + --> $DIR/excessive_precision.rs:42:21 | -43 | let vec32: Vec = vec![0.123_456_789]; - | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345679` +42 | let bad64_inf = 0.123_456_789_012_345_67; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66` error: float has excessive precision - --> $DIR/excessive_precision.rs:44:32 + --> $DIR/excessive_precision.rs:48:36 | -44 | let vec64: Vec = vec![0.123_456_789_123_456_789]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678912345678` +48 | let bad_vec32: Vec = vec![0.123_456_789]; + | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:48:24 + --> $DIR/excessive_precision.rs:49:36 | -48 | let bad_e32: f32 = 1.123_456_788_888e-10; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.1234568e-10` +49 | let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78` error: float has excessive precision - --> $DIR/excessive_precision.rs:51:27 + --> $DIR/excessive_precision.rs:53:24 | -51 | let bad_bige32: f32 = 1.123_456_788_888E-10; - | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.1234568E-10` +53 | let bad_e32: f32 = 1.123_456_788_888e-10; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10` -error: aborting due to 16 previous errors +error: float has excessive precision + --> $DIR/excessive_precision.rs:56:27 + | +56 | let bad_bige32: f32 = 1.123_456_788_888E-10; + | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` + +error: aborting due to 18 previous errors