Skip to content

Commit 1b21661

Browse files
Supress excessive_precision when constants are overly precise (#15193)
Suppress the `excessive_precision` lint when the literal is the initializer of a `const` item and overly precise (over 40 digits). If an overly precise literal is used in a let initialization it produces a note suggesting the change. changelog: [`excessive_precision`]: suppress the lint when `const` items are overly precise, configurable through the new `const_literal_digits_threshold` option Fixes #13855
2 parents c98ce18 + fc39590 commit 1b21661

File tree

13 files changed

+330
-24
lines changed

13 files changed

+330
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6712,6 +6712,7 @@ Released 2018-09-13
67126712
[`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers
67136713
[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items
67146714
[`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold
6715+
[`const-literal-digits-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#const-literal-digits-threshold
67156716
[`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros
67166717
[`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods
67176718
[`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names

book/src/lint_configuration.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,16 @@ The maximum cognitive complexity a function can have
485485
* [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
486486

487487

488+
## `const-literal-digits-threshold`
489+
The minimum digits a const float literal must have to supress the `excessive_precicion` lint
490+
491+
**Default Value:** `30`
492+
493+
---
494+
**Affected lints:**
495+
* [`excessive_precision`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision)
496+
497+
488498
## `disallowed-macros`
489499
The list of disallowed macros, written as fully qualified paths.
490500

clippy_config/src/conf.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,9 @@ define_Conf! {
570570
/// The maximum cognitive complexity a function can have
571571
#[lints(cognitive_complexity)]
572572
cognitive_complexity_threshold: u64 = 25,
573+
/// The minimum digits a const float literal must have to supress the `excessive_precicion` lint
574+
#[lints(excessive_precision)]
575+
const_literal_digits_threshold: usize = 30,
573576
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
574577
///
575578
/// Use the Cognitive Complexity lint instead.

clippy_lints/src/float_literal.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1+
use clippy_config::Conf;
12
use clippy_utils::diagnostics::span_lint_and_then;
2-
use clippy_utils::numeric_literal;
3+
use clippy_utils::{ExprUseNode, expr_use_ctxt, numeric_literal};
34
use rustc_ast::ast::{LitFloatType, LitKind};
45
use rustc_errors::Applicability;
56
use rustc_hir as hir;
67
use rustc_lint::{LateContext, LateLintPass};
78
use rustc_middle::ty::{self, FloatTy};
8-
use rustc_session::declare_lint_pass;
9+
use rustc_session::impl_lint_pass;
910
use std::fmt;
1011

1112
declare_clippy_lint! {
1213
/// ### What it does
1314
/// Checks for float literals with a precision greater
1415
/// than that supported by the underlying type.
1516
///
17+
/// The lint is suppressed for literals with over `const_literal_digits_threshold` digits.
18+
///
1619
/// ### Why is this bad?
1720
/// Rust will truncate the literal silently.
1821
///
@@ -58,7 +61,21 @@ declare_clippy_lint! {
5861
"lossy whole number float literals"
5962
}
6063

61-
declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
64+
pub struct FloatLiteral {
65+
const_literal_digits_threshold: usize,
66+
}
67+
68+
impl_lint_pass!(FloatLiteral => [
69+
EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL
70+
]);
71+
72+
impl FloatLiteral {
73+
pub fn new(conf: &'static Conf) -> Self {
74+
Self {
75+
const_literal_digits_threshold: conf.const_literal_digits_threshold,
76+
}
77+
}
78+
}
6279

6380
impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
6481
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
@@ -126,13 +143,25 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
126143
},
127144
);
128145
}
129-
} else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) {
146+
} else if digits > max as usize && count_digits(&float_str) < digits {
147+
if digits >= self.const_literal_digits_threshold
148+
&& matches!(expr_use_ctxt(cx, expr).use_node(cx), ExprUseNode::ConstStatic(_))
149+
{
150+
// If a big enough number of digits is specified and it's a constant
151+
// we assume the user is definining a constant, and excessive precision is ok
152+
return;
153+
}
130154
span_lint_and_then(
131155
cx,
132156
EXCESSIVE_PRECISION,
133157
expr.span,
134158
"float has excessive precision",
135159
|diag| {
160+
if digits >= self.const_literal_digits_threshold
161+
&& let Some(let_stmt) = maybe_let_stmt(cx, expr)
162+
{
163+
diag.span_note(let_stmt.span, "consider making it a `const` item");
164+
}
136165
diag.span_suggestion_verbose(
137166
expr.span,
138167
"consider changing the type or truncating it to",
@@ -196,3 +225,11 @@ impl FloatFormat {
196225
}
197226
}
198227
}
228+
229+
fn maybe_let_stmt<'a>(cx: &LateContext<'a>, expr: &hir::Expr<'_>) -> Option<&'a hir::LetStmt<'a>> {
230+
let parent = cx.tcx.parent_hir_node(expr.hir_id);
231+
match parent {
232+
hir::Node::LetStmt(let_stmt) => Some(let_stmt),
233+
_ => None,
234+
}
235+
}

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
475475
store.register_late_pass(move |_| Box::new(types::Types::new(conf)));
476476
store.register_late_pass(move |_| Box::new(booleans::NonminimalBool::new(conf)));
477477
store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
478-
store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
478+
store.register_late_pass(move |_| Box::new(float_literal::FloatLiteral::new(conf)));
479479
store.register_late_pass(|_| Box::new(ptr::Ptr));
480480
store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
481481
store.register_late_pass(|_| Box::new(bool_comparison::BoolComparison));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const-literal-digits-threshold = 20
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#![warn(clippy::excessive_precision)]
2+
#![allow(
3+
dead_code,
4+
overflowing_literals,
5+
unused_variables,
6+
clippy::print_literal,
7+
clippy::useless_vec
8+
)]
9+
10+
fn main() {
11+
// Overly specified constants
12+
let _: f32 = 1.012_345_7;
13+
//~^ excessive_precision
14+
let _: f64 = 1.012_345_678_901_234_6;
15+
//~^ excessive_precision
16+
const _: f32 = 1.012345678901234567890;
17+
const _: f64 = 1.012345678901234567890;
18+
19+
static STATIC1: f32 = 1.012345678901234567890;
20+
static STATIC2: f64 = 1.012345678901234567890;
21+
22+
static mut STATIC_MUT1: f32 = 1.012345678901234567890;
23+
static mut STATIC_MUT2: f64 = 1.012345678901234567890;
24+
}
25+
26+
trait ExcessivelyPreciseTrait {
27+
// Overly specified constants
28+
const GOOD1: f32 = 1.012345678901234567890;
29+
const GOOD2: f64 = 1.012345678901234567890;
30+
}
31+
32+
struct ExcessivelyPreciseStruct;
33+
34+
impl ExcessivelyPreciseStruct {
35+
// Overly specified constants
36+
const GOOD1: f32 = 1.012345678901234567890;
37+
const GOOD2: f64 = 1.012345678901234567890;
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#![warn(clippy::excessive_precision)]
2+
#![allow(
3+
dead_code,
4+
overflowing_literals,
5+
unused_variables,
6+
clippy::print_literal,
7+
clippy::useless_vec
8+
)]
9+
10+
fn main() {
11+
// Overly specified constants
12+
let _: f32 = 1.012345678901234567890;
13+
//~^ excessive_precision
14+
let _: f64 = 1.012345678901234567890;
15+
//~^ excessive_precision
16+
const _: f32 = 1.012345678901234567890;
17+
const _: f64 = 1.012345678901234567890;
18+
19+
static STATIC1: f32 = 1.012345678901234567890;
20+
static STATIC2: f64 = 1.012345678901234567890;
21+
22+
static mut STATIC_MUT1: f32 = 1.012345678901234567890;
23+
static mut STATIC_MUT2: f64 = 1.012345678901234567890;
24+
}
25+
26+
trait ExcessivelyPreciseTrait {
27+
// Overly specified constants
28+
const GOOD1: f32 = 1.012345678901234567890;
29+
const GOOD2: f64 = 1.012345678901234567890;
30+
}
31+
32+
struct ExcessivelyPreciseStruct;
33+
34+
impl ExcessivelyPreciseStruct {
35+
// Overly specified constants
36+
const GOOD1: f32 = 1.012345678901234567890;
37+
const GOOD2: f64 = 1.012345678901234567890;
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: float has excessive precision
2+
--> tests/ui-toml/excessive_precision/excessive_precision.rs:12:18
3+
|
4+
LL | let _: f32 = 1.012345678901234567890;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: consider making it a `const` item
8+
--> tests/ui-toml/excessive_precision/excessive_precision.rs:12:5
9+
|
10+
LL | let _: f32 = 1.012345678901234567890;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= note: `-D clippy::excessive-precision` implied by `-D warnings`
13+
= help: to override `-D warnings` add `#[allow(clippy::excessive_precision)]`
14+
help: consider changing the type or truncating it to
15+
|
16+
LL - let _: f32 = 1.012345678901234567890;
17+
LL + let _: f32 = 1.012_345_7;
18+
|
19+
20+
error: float has excessive precision
21+
--> tests/ui-toml/excessive_precision/excessive_precision.rs:14:18
22+
|
23+
LL | let _: f64 = 1.012345678901234567890;
24+
| ^^^^^^^^^^^^^^^^^^^^^^^
25+
|
26+
note: consider making it a `const` item
27+
--> tests/ui-toml/excessive_precision/excessive_precision.rs:14:5
28+
|
29+
LL | let _: f64 = 1.012345678901234567890;
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
help: consider changing the type or truncating it to
32+
|
33+
LL - let _: f64 = 1.012345678901234567890;
34+
LL + let _: f64 = 1.012_345_678_901_234_6;
35+
|
36+
37+
error: aborting due to 2 previous errors
38+

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
3535
check-inconsistent-struct-field-initializers
3636
check-private-items
3737
cognitive-complexity-threshold
38+
const-literal-digits-threshold
3839
disallowed-macros
3940
disallowed-methods
4041
disallowed-names
@@ -129,6 +130,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
129130
check-inconsistent-struct-field-initializers
130131
check-private-items
131132
cognitive-complexity-threshold
133+
const-literal-digits-threshold
132134
disallowed-macros
133135
disallowed-methods
134136
disallowed-names
@@ -223,6 +225,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
223225
check-inconsistent-struct-field-initializers
224226
check-private-items
225227
cognitive-complexity-threshold
228+
const-literal-digits-threshold
226229
disallowed-macros
227230
disallowed-methods
228231
disallowed-names

0 commit comments

Comments
 (0)