]>
git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/approx_const.rs
3 use std
::f64::consts
as f64;
4 use syntax
::ast
::{Lit, LitKind, FloatTy}
;
8 /// **What it does:** Checks for floating point literals that approximate
9 /// constants which are defined in
10 /// [`std::f32::consts`](https://doc.rust-lang.
11 /// org/stable/std/f32/consts/#constants)
13 /// [`std::f64::consts`](https://doc.rust-lang.
14 /// org/stable/std/f64/consts/#constants),
15 /// respectively, suggesting to use the predefined constant.
17 /// **Why is this bad?** Usually, the definition in the standard library is more
18 /// precise than what people come up with. If you find that your definition is
19 /// actually more precise, please [file a Rust
20 /// issue](https://github.com/rust-lang/rust/issues).
22 /// **Known problems:** If you happen to have a value that is within 1/8192 of a
23 /// known constant, but is not *and should not* be the same, this lint will
24 /// report your value anyway. We have not yet noticed any false positives in
25 /// code we tested clippy with (this includes servo), but YMMV.
34 "the approximate of a known float constant (in `std::fXX::consts`)"
37 // Tuples are of the form (constant, name, min_digits)
38 const KNOWN_CONSTS
: &'
static [(f64, &'
static str, usize)] = &[
40 (f64::FRAC_1_PI
, "FRAC_1_PI", 4),
41 (f64::FRAC_1_SQRT_2
, "FRAC_1_SQRT_2", 5),
42 (f64::FRAC_2_PI
, "FRAC_2_PI", 5),
43 (f64::FRAC_2_SQRT_PI
, "FRAC_2_SQRT_PI", 5),
44 (f64::FRAC_PI_2
, "FRAC_PI_2", 5),
45 (f64::FRAC_PI_3
, "FRAC_PI_3", 5),
46 (f64::FRAC_PI_4
, "FRAC_PI_4", 5),
47 (f64::FRAC_PI_6
, "FRAC_PI_6", 5),
48 (f64::FRAC_PI_8
, "FRAC_PI_8", 5),
49 (f64::LN_10
, "LN_10", 5),
50 (f64::LN_2
, "LN_2", 5),
51 (f64::LOG10_E
, "LOG10_E", 5),
52 (f64::LOG2_E
, "LOG2_E", 5),
54 (f64::SQRT_2
, "SQRT_2", 5),
57 #[derive(Copy, Clone)]
60 impl LintPass
for Pass
{
61 fn get_lints(&self) -> LintArray
{
62 lint_array
!(APPROX_CONSTANT
)
66 impl<'a
, 'tcx
> LateLintPass
<'a
, 'tcx
> for Pass
{
67 fn check_expr(&mut self, cx
: &LateContext
<'a
, 'tcx
>, e
: &'tcx Expr
) {
68 if let ExprLit(ref lit
) = e
.node
{
69 check_lit(cx
, lit
, e
);
74 fn check_lit(cx
: &LateContext
, lit
: &Lit
, e
: &Expr
) {
76 LitKind
::Float(ref s
, FloatTy
::F32
) => check_known_consts(cx
, e
, s
, "f32"),
77 LitKind
::Float(ref s
, FloatTy
::F64
) => check_known_consts(cx
, e
, s
, "f64"),
78 LitKind
::FloatUnsuffixed(ref s
) => check_known_consts(cx
, e
, s
, "f{32, 64}"),
83 fn check_known_consts(cx
: &LateContext
, e
: &Expr
, s
: &symbol
::Symbol
, module
: &str) {
85 if s
.parse
::<f64>().is_ok() {
86 for &(constant
, name
, min_digits
) in KNOWN_CONSTS
{
87 if is_approx_const(constant
, &s
, min_digits
) {
93 "approximate value of `{}::consts::{}` found. \
94 Consider using it directly",
105 /// Returns false if the number of significant figures in `value` are
106 /// less than `min_digits`; otherwise, returns true if `value` is equal
107 /// to `constant`, rounded to the number of digits present in `value`.
108 fn is_approx_const(constant
: f64, value
: &str, min_digits
: usize) -> bool
{
109 if value
.len() <= min_digits
{
112 let round_const
= format
!("{:.*}", value
.len() - 2, constant
);
114 let mut trunc_const
= constant
.to_string();
115 if trunc_const
.len() > value
.len() {
116 trunc_const
.truncate(value
.len());
119 (value
== round_const
) || (value
== trunc_const
)