|
1 | 1 | use clippy_utils::diagnostics::span_lint;
|
| 2 | +use clippy_utils::{meets_msrv, msrvs}; |
2 | 3 | use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
|
3 | 4 | use rustc_hir::{Expr, ExprKind};
|
4 |
| -use rustc_lint::{LateContext, LateLintPass}; |
5 |
| -use rustc_session::{declare_lint_pass, declare_tool_lint}; |
| 5 | +use rustc_lint::{LateContext, LateLintPass, LintContext}; |
| 6 | +use rustc_semver::RustcVersion; |
| 7 | +use rustc_session::{declare_tool_lint, impl_lint_pass}; |
6 | 8 | use rustc_span::symbol;
|
7 | 9 | use std::f64::consts as f64;
|
8 | 10 |
|
@@ -36,68 +38,83 @@ declare_clippy_lint! {
|
36 | 38 | "the approximate of a known float constant (in `std::fXX::consts`)"
|
37 | 39 | }
|
38 | 40 |
|
39 |
| -// Tuples are of the form (constant, name, min_digits) |
40 |
| -const KNOWN_CONSTS: [(f64, &str, usize); 18] = [ |
41 |
| - (f64::E, "E", 4), |
42 |
| - (f64::FRAC_1_PI, "FRAC_1_PI", 4), |
43 |
| - (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5), |
44 |
| - (f64::FRAC_2_PI, "FRAC_2_PI", 5), |
45 |
| - (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5), |
46 |
| - (f64::FRAC_PI_2, "FRAC_PI_2", 5), |
47 |
| - (f64::FRAC_PI_3, "FRAC_PI_3", 5), |
48 |
| - (f64::FRAC_PI_4, "FRAC_PI_4", 5), |
49 |
| - (f64::FRAC_PI_6, "FRAC_PI_6", 5), |
50 |
| - (f64::FRAC_PI_8, "FRAC_PI_8", 5), |
51 |
| - (f64::LN_2, "LN_2", 5), |
52 |
| - (f64::LN_10, "LN_10", 5), |
53 |
| - (f64::LOG2_10, "LOG2_10", 5), |
54 |
| - (f64::LOG2_E, "LOG2_E", 5), |
55 |
| - (f64::LOG10_2, "LOG10_2", 5), |
56 |
| - (f64::LOG10_E, "LOG10_E", 5), |
57 |
| - (f64::PI, "PI", 3), |
58 |
| - (f64::SQRT_2, "SQRT_2", 5), |
| 41 | +// Tuples are of the form (constant, name, min_digits, msrv) |
| 42 | +const KNOWN_CONSTS: [(f64, &str, usize, Option<RustcVersion>); 18] = [ |
| 43 | + (f64::E, "E", 4, None), |
| 44 | + (f64::FRAC_1_PI, "FRAC_1_PI", 4, None), |
| 45 | + (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5, None), |
| 46 | + (f64::FRAC_2_PI, "FRAC_2_PI", 5, None), |
| 47 | + (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5, None), |
| 48 | + (f64::FRAC_PI_2, "FRAC_PI_2", 5, None), |
| 49 | + (f64::FRAC_PI_3, "FRAC_PI_3", 5, None), |
| 50 | + (f64::FRAC_PI_4, "FRAC_PI_4", 5, None), |
| 51 | + (f64::FRAC_PI_6, "FRAC_PI_6", 5, None), |
| 52 | + (f64::FRAC_PI_8, "FRAC_PI_8", 5, None), |
| 53 | + (f64::LN_2, "LN_2", 5, None), |
| 54 | + (f64::LN_10, "LN_10", 5, None), |
| 55 | + (f64::LOG2_10, "LOG2_10", 5, Some(msrvs::LOG2_10)), |
| 56 | + (f64::LOG2_E, "LOG2_E", 5, None), |
| 57 | + (f64::LOG10_2, "LOG10_2", 5, Some(msrvs::LOG10_2)), |
| 58 | + (f64::LOG10_E, "LOG10_E", 5, None), |
| 59 | + (f64::PI, "PI", 3, None), |
| 60 | + (f64::SQRT_2, "SQRT_2", 5, None), |
59 | 61 | ];
|
60 | 62 |
|
61 |
| -declare_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); |
| 63 | +pub struct ApproxConstant { |
| 64 | + msrv: Option<RustcVersion>, |
| 65 | +} |
62 | 66 |
|
63 |
| -impl<'tcx> LateLintPass<'tcx> for ApproxConstant { |
64 |
| - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { |
65 |
| - if let ExprKind::Lit(lit) = &e.kind { |
66 |
| - check_lit(cx, &lit.node, e); |
| 67 | +impl ApproxConstant { |
| 68 | + #[must_use] |
| 69 | + pub fn new(msrv: Option<RustcVersion>) -> Self { |
| 70 | + Self { msrv } |
| 71 | + } |
| 72 | + |
| 73 | + fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { |
| 74 | + match *lit { |
| 75 | + LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { |
| 76 | + FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"), |
| 77 | + FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"), |
| 78 | + }, |
| 79 | + LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"), |
| 80 | + _ => (), |
67 | 81 | }
|
68 | 82 | }
|
69 |
| -} |
70 | 83 |
|
71 |
| -fn check_lit(cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) { |
72 |
| - match *lit { |
73 |
| - LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { |
74 |
| - FloatTy::F32 => check_known_consts(cx, e, s, "f32"), |
75 |
| - FloatTy::F64 => check_known_consts(cx, e, s, "f64"), |
76 |
| - }, |
77 |
| - LitKind::Float(s, LitFloatType::Unsuffixed) => check_known_consts(cx, e, s, "f{32, 64}"), |
78 |
| - _ => (), |
| 84 | + fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) { |
| 85 | + let s = s.as_str(); |
| 86 | + if s.parse::<f64>().is_ok() { |
| 87 | + for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { |
| 88 | + if is_approx_const(constant, &s, min_digits) |
| 89 | + && msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv)) |
| 90 | + { |
| 91 | + span_lint( |
| 92 | + cx, |
| 93 | + APPROX_CONSTANT, |
| 94 | + e.span, |
| 95 | + &format!( |
| 96 | + "approximate value of `{}::consts::{}` found. \ |
| 97 | + Consider using it directly", |
| 98 | + module, &name |
| 99 | + ), |
| 100 | + ); |
| 101 | + return; |
| 102 | + } |
| 103 | + } |
| 104 | + } |
79 | 105 | }
|
80 | 106 | }
|
81 | 107 |
|
82 |
| -fn check_known_consts(cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) { |
83 |
| - let s = s.as_str(); |
84 |
| - if s.parse::<f64>().is_ok() { |
85 |
| - for &(constant, name, min_digits) in &KNOWN_CONSTS { |
86 |
| - if is_approx_const(constant, &s, min_digits) { |
87 |
| - span_lint( |
88 |
| - cx, |
89 |
| - APPROX_CONSTANT, |
90 |
| - e.span, |
91 |
| - &format!( |
92 |
| - "approximate value of `{}::consts::{}` found. \ |
93 |
| - Consider using it directly", |
94 |
| - module, &name |
95 |
| - ), |
96 |
| - ); |
97 |
| - return; |
98 |
| - } |
| 108 | +impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); |
| 109 | + |
| 110 | +impl<'tcx> LateLintPass<'tcx> for ApproxConstant { |
| 111 | + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { |
| 112 | + if let ExprKind::Lit(lit) = &e.kind { |
| 113 | + self.check_lit(cx, &lit.node, e); |
99 | 114 | }
|
100 | 115 | }
|
| 116 | + |
| 117 | + extract_msrv_attr!(LateContext); |
101 | 118 | }
|
102 | 119 |
|
103 | 120 | /// Returns `false` if the number of significant figures in `value` are
|
|
0 commit comments