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 88 89 90 91 92 93 94 95 96
use super::*; use crate::ast_util::{range, HasSideEffects}; use std::convert::Infallible; use full_moon::{ ast::{self, Ast}, node::Node, visitors::Visitor, }; pub struct IfsSameCondLint; impl Rule for IfsSameCondLint { type Config = (); type Error = Infallible; fn new(_: Self::Config) -> Result<Self, Self::Error> { Ok(IfsSameCondLint) } fn pass(&self, ast: &Ast, _: &Context) -> Vec<Diagnostic> { let mut visitor = IfsSameCondVisitor { positions: Vec::new(), }; visitor.visit_ast(ast); visitor .positions .drain(..) .map(|position| { Diagnostic::new_complete( "ifs_same_cond", "this `elseif` has the same condition as a previous if".to_owned(), Label::new(position.0), Vec::new(), vec![Label::new_with_message( position.1, "note: same as this".to_owned(), )], ) }) .collect() } fn severity(&self) -> Severity { Severity::Error } fn rule_type(&self) -> RuleType { RuleType::Correctness } } struct IfsSameCondVisitor { positions: Vec<((u32, u32), (u32, u32))>, } impl Visitor for IfsSameCondVisitor { fn visit_if(&mut self, if_block: &ast::If) { if let Some(else_ifs) = if_block.else_if() { let mut conditions = Vec::with_capacity(else_ifs.len() + 1); if !if_block.condition().has_side_effects() { conditions.push(if_block.condition()); } 'else_ifs: for else_if in else_ifs { let condition = else_if.condition(); if !condition.has_side_effects() { for other in &conditions { if other.similar(&condition) { self.positions.push((range(condition), range(other))); continue 'else_ifs; } } conditions.push(condition); } } } } } #[cfg(test)] mod tests { use super::{super::test_util::test_lint, *}; #[test] fn test_ifs_same_cond() { test_lint( IfsSameCondLint::new(()).unwrap(), "ifs_same_cond", "ifs_same_cond", ); } }