Skip to main content

rigsql_rules/tsql/
tq02.rs

1use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
2use crate::violation::LintViolation;
3
4/// TQ02: IF/WHILE blocks should use BEGIN...END for multi-statement bodies.
5///
6/// This is a stub implementation. Precise detection requires tracking statement
7/// counts after control-flow keywords, which is deferred to a future iteration.
8#[derive(Debug, Default)]
9pub struct RuleTQ02;
10
11impl Rule for RuleTQ02 {
12    fn code(&self) -> &'static str {
13        "TQ02"
14    }
15    fn name(&self) -> &'static str {
16        "tsql.block_structure"
17    }
18    fn description(&self) -> &'static str {
19        "IF/WHILE blocks should use BEGIN...END for multi-statement bodies."
20    }
21    fn explanation(&self) -> &'static str {
22        "In T-SQL, IF and WHILE without BEGIN...END only execute the immediately following \
23         statement. This is a common source of bugs when additional statements are added later. \
24         Always wrapping the body in BEGIN...END makes the intent explicit."
25    }
26    fn groups(&self) -> &[RuleGroup] {
27        &[RuleGroup::Convention]
28    }
29    fn is_fixable(&self) -> bool {
30        false
31    }
32
33    fn crawl_type(&self) -> CrawlType {
34        CrawlType::RootOnly
35    }
36
37    fn eval(&self, _ctx: &RuleContext) -> Vec<LintViolation> {
38        // Stub: precise multi-statement detection is deferred.
39        vec![]
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use crate::test_utils::lint_sql_with_dialect;
47
48    #[test]
49    fn test_tq02_no_false_positives_simple() {
50        let violations = lint_sql_with_dialect("SELECT 1", RuleTQ02, "tsql");
51        assert_eq!(violations.len(), 0);
52    }
53
54    #[test]
55    fn test_tq02_no_false_positives_ansi() {
56        let violations = lint_sql_with_dialect("SELECT 1", RuleTQ02, "ansi");
57        assert_eq!(violations.len(), 0);
58    }
59}