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 97 98 99 100 101 102
use super::*; use crate::ast_util::range; use std::convert::Infallible; use full_moon::{ ast::{self, Ast}, node::Node, visitors::Visitor, }; pub struct IfSameThenElseLint; impl Rule for IfSameThenElseLint { type Config = (); type Error = Infallible; fn new(_: Self::Config) -> Result<Self, Self::Error> { Ok(IfSameThenElseLint) } fn pass(&self, ast: &Ast, _: &Context) -> Vec<Diagnostic> { let mut visitor = IfSameThenElseVisitor { positions: Vec::new(), }; visitor.visit_ast(ast); visitor .positions .drain(..) .map(|position| { Diagnostic::new_complete( "if_same_then_else", "this has the same block 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 IfSameThenElseVisitor { positions: Vec<((u32, u32), (u32, u32))>, } impl Visitor for IfSameThenElseVisitor { fn visit_if(&mut self, if_block: &ast::If) { let else_ifs = if_block .else_if() .map(|else_ifs| else_ifs.iter().collect()) .unwrap_or_else(Vec::new); let mut blocks = Vec::with_capacity(2 + else_ifs.len()); blocks.push(if_block.block()); 'blocks: for block in else_ifs .iter() .map(|else_if| else_if.block()) .chain(if_block.else_block()) { if block.stmts().next().is_none() { continue; } for other in &blocks { if other.similar(&block) { self.positions.push((range(block), range(other))); continue 'blocks; } } blocks.push(block); } } } #[cfg(test)] mod tests { use super::{super::test_util::test_lint, *}; #[test] fn test_if_same_then_else() { test_lint( IfSameThenElseLint::new(()).unwrap(), "if_same_then_else", "if_same_then_else", ); } }