selene_lib/lints/
divide_by_zero.rs1use super::*;
2use std::convert::Infallible;
3
4use full_moon::{
5 ast::{self, Ast},
6 node::Node,
7 visitors::Visitor,
8};
9
10pub struct DivideByZeroLint;
11
12impl Lint for DivideByZeroLint {
13 type Config = ();
14 type Error = Infallible;
15
16 const SEVERITY: Severity = Severity::Warning;
17 const LINT_TYPE: LintType = LintType::Complexity;
18
19 fn new(_: Self::Config) -> Result<Self, Self::Error> {
20 Ok(DivideByZeroLint)
21 }
22
23 fn pass(&self, ast: &Ast, _: &Context, _: &AstContext) -> Vec<Diagnostic> {
24 let mut visitor = DivideByZeroVisitor {
25 positions: Vec::new(),
26 };
27
28 visitor.visit_ast(ast);
29
30 visitor
31 .positions
32 .iter()
33 .map(|position| {
34 Diagnostic::new(
35 "divide_by_zero",
36 "dividing by zero is not allowed, use math.huge instead".to_owned(),
37 Label::new(*position),
38 )
39 })
40 .collect()
41 }
42}
43
44struct DivideByZeroVisitor {
45 positions: Vec<(usize, usize)>,
46}
47
48fn value_is_zero(value: &ast::Expression) -> bool {
49 if let ast::Expression::Number(token) = value {
50 token.token().to_string() == "0"
51 } else {
52 false
53 }
54}
55
56impl Visitor for DivideByZeroVisitor {
57 fn visit_expression(&mut self, node: &ast::Expression) {
58 if_chain::if_chain! {
59 if let ast::Expression::BinaryOperator { lhs, binop, rhs, .. } = node;
60 if let ast::BinOp::Slash(_) = binop;
61 if value_is_zero(rhs) && !value_is_zero(lhs);
62 then {
63 let range = node.range().unwrap();
64 self.positions.push((range.0.bytes(), range.1.bytes()));
65 }
66 }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::{super::test_util::test_lint, *};
73
74 #[test]
75 fn test_divide_by_zero() {
76 test_lint(
77 DivideByZeroLint::new(()).unwrap(),
78 "divide_by_zero",
79 "divide_by_zero",
80 );
81 }
82}