Skip to main content

rigsql_rules/layout/
lt14.rs

1use rigsql_core::SegmentType;
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::violation::{LintViolation, SourceEdit};
5
6/// LT14: Redundant/multiple semicolons at end of statement.
7#[derive(Debug, Default)]
8pub struct RuleLT14;
9
10impl Rule for RuleLT14 {
11    fn code(&self) -> &'static str {
12        "LT14"
13    }
14    fn name(&self) -> &'static str {
15        "layout.semicolons"
16    }
17    fn description(&self) -> &'static str {
18        "Statements should not end with multiple semicolons."
19    }
20    fn explanation(&self) -> &'static str {
21        "Each SQL statement should end with exactly one semicolon. Multiple consecutive \
22         semicolons (;;) indicate a redundant terminator that should be removed."
23    }
24    fn groups(&self) -> &[RuleGroup] {
25        &[RuleGroup::Layout]
26    }
27    fn is_fixable(&self) -> bool {
28        true
29    }
30
31    fn crawl_type(&self) -> CrawlType {
32        CrawlType::Segment(vec![SegmentType::Semicolon])
33    }
34
35    fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
36        // Check if next non-trivia sibling is also a semicolon
37        let mut i = ctx.index_in_parent + 1;
38        while i < ctx.siblings.len() {
39            let seg = &ctx.siblings[i];
40            if seg.segment_type().is_trivia() {
41                i += 1;
42                continue;
43            }
44            if seg.segment_type() == SegmentType::Semicolon {
45                return vec![LintViolation::with_fix(
46                    self.code(),
47                    "Found multiple consecutive semicolons.",
48                    ctx.segment.span(),
49                    vec![SourceEdit::delete(ctx.segment.span())],
50                )];
51            }
52            break;
53        }
54
55        vec![]
56    }
57}