selene_lib/lints/
ifs_same_cond.rs

1use super::*;
2use crate::ast_util::{range, HasSideEffects};
3use std::convert::Infallible;
4
5use full_moon::{
6    ast::{self, Ast},
7    node::Node,
8    visitors::Visitor,
9};
10
11pub struct IfsSameCondLint;
12
13impl Lint for IfsSameCondLint {
14    type Config = ();
15    type Error = Infallible;
16
17    const SEVERITY: Severity = Severity::Error;
18    const LINT_TYPE: LintType = LintType::Correctness;
19
20    fn new(_: Self::Config) -> Result<Self, Self::Error> {
21        Ok(IfsSameCondLint)
22    }
23
24    fn pass(&self, ast: &Ast, _: &Context, _: &AstContext) -> Vec<Diagnostic> {
25        let mut visitor = IfsSameCondVisitor {
26            positions: Vec::new(),
27        };
28
29        visitor.visit_ast(ast);
30
31        visitor
32            .positions
33            .drain(..)
34            .map(|position| {
35                Diagnostic::new_complete(
36                    "ifs_same_cond",
37                    "this `elseif` has the same condition as a previous if".to_owned(),
38                    Label::new(position.0),
39                    Vec::new(),
40                    vec![Label::new_with_message(
41                        position.1,
42                        "note: same as this".to_owned(),
43                    )],
44                )
45            })
46            .collect()
47    }
48}
49
50struct IfsSameCondVisitor {
51    positions: Vec<((u32, u32), (u32, u32))>,
52}
53
54impl Visitor for IfsSameCondVisitor {
55    fn visit_if(&mut self, if_block: &ast::If) {
56        if let Some(else_ifs) = if_block.else_if() {
57            let mut conditions = Vec::with_capacity(else_ifs.len() + 1);
58            if !if_block.condition().has_side_effects() {
59                conditions.push(if_block.condition());
60            }
61
62            'else_ifs: for else_if in else_ifs {
63                let condition = else_if.condition();
64                if !condition.has_side_effects() {
65                    for other in &conditions {
66                        if other.similar(&condition) {
67                            self.positions.push((range(condition), range(other)));
68                            continue 'else_ifs;
69                        }
70                    }
71
72                    conditions.push(condition);
73                }
74            }
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::{super::test_util::test_lint, *};
82
83    #[test]
84    fn test_ifs_same_cond() {
85        test_lint(
86            IfsSameCondLint::new(()).unwrap(),
87            "ifs_same_cond",
88            "ifs_same_cond",
89        );
90    }
91}