Fix 1x..x.0 false positive, pretty suggestion

This commit is contained in:
Evan Simmons 2018-05-02 11:40:52 -07:00
parent 0557359ecd
commit d4b536f540
4 changed files with 112 additions and 72 deletions

View file

@ -69,13 +69,16 @@ impl ExcessivePrecision {
fn check(&self, sym: &Symbol, fty: &FloatTy) -> Option<String> {
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::<f32>().map(|f| formatter.format(f)),
FloatTy::F64 => sym_str.parse::<f64>().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')

View file

@ -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('.');

View file

@ -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<f32> = vec![0.123_456_789];
let vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
// Vectors
let good_vec32: Vec<f32> = vec![0.123_456];
let good_vec64: Vec<f64> = vec![0.123_456_789];
let bad_vec32: Vec<f32> = vec![0.123_456_789];
let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
// Exponential float notation
let good_e32: f32 = 1e-10;

View file

@ -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<f32> = 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<f64> = vec![0.123_456_789_123_456_789];
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.12345678912345678`
48 | let bad_vec32: Vec<f32> = 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<f64> = 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