-
-
Notifications
You must be signed in to change notification settings - Fork 84
/
Copy pathapproximated_constants.rs
87 lines (73 loc) · 2.34 KB
/
approximated_constants.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use super::*;
use std::convert::Infallible;
use full_moon::{ast::Ast, tokenizer::TokenType, visitors::Visitor};
pub struct ApproximatedConstantsLint;
impl Lint for ApproximatedConstantsLint {
type Config = ();
type Error = Infallible;
const SEVERITY: Severity = Severity::Warning;
const LINT_TYPE: LintType = LintType::Correctness;
fn new((): Self::Config) -> Result<Self, Self::Error> {
Ok(ApproximatedConstantsLint)
}
fn pass(&self, ast: &Ast, _: &Context, _: &AstContext) -> Vec<Diagnostic> {
let mut visitor = ApproxConstantVisitor {
approximated_constants: Vec::new(),
};
visitor.visit_ast(ast);
visitor
.approximated_constants
.iter()
.map(|constant| {
Diagnostic::new(
"approximated_constants",
format!("`{}` is more precise", constant.constant),
Label::new(constant.range),
)
})
.collect()
}
}
struct ApproxConstantVisitor {
approximated_constants: Vec<ApproximatedConstant>,
}
struct ApproximatedConstant {
range: (usize, usize),
constant: String,
}
impl Visitor for ApproxConstantVisitor {
fn visit_number(&mut self, token: &full_moon::tokenizer::Token) {
if let TokenType::Number { text } = token.token_type() {
if is_approx_const(std::f64::consts::PI, text, 3) {
self.approximated_constants.push(ApproximatedConstant {
range: (token.start_position().bytes(), token.end_position().bytes()),
constant: "math.pi".to_string(),
});
}
}
}
}
#[must_use]
fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
if value.len() <= min_digits {
false
} else if constant.to_string().starts_with(value) {
// The value is a truncated constant
true
} else {
let round_const = format!("{constant:.*}", value.len() - 2);
value == round_const
}
}
#[cfg(test)]
mod tests {
use super::{super::test_util::test_lint, *};
#[test]
fn test_approximated_constants() {
test_lint(
ApproximatedConstantsLint::new(()).unwrap(),
"approximated_constants",
"approximated_constants",
);
}
}