rigsql_rules/convention/
cv09.rs1use rigsql_core::{Segment, SegmentType};
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::violation::LintViolation;
5
6#[derive(Debug, Default)]
10pub struct RuleCV09 {
11 pub blocked_words: Vec<String>,
12}
13
14impl Rule for RuleCV09 {
15 fn code(&self) -> &'static str {
16 "CV09"
17 }
18 fn name(&self) -> &'static str {
19 "convention.blocked_words"
20 }
21 fn description(&self) -> &'static str {
22 "Use of blocked words."
23 }
24 fn explanation(&self) -> &'static str {
25 "Certain words may be reserved, deprecated, or disallowed by team convention. \
26 This rule flags identifiers that match a configurable list of blocked words."
27 }
28 fn groups(&self) -> &[RuleGroup] {
29 &[RuleGroup::Convention]
30 }
31 fn is_fixable(&self) -> bool {
32 false
33 }
34
35 fn configure(&mut self, settings: &std::collections::HashMap<String, String>) {
36 if let Some(val) = settings.get("blocked_words") {
37 self.blocked_words = val
38 .split(',')
39 .map(|s| s.trim().to_lowercase())
40 .filter(|s| !s.is_empty())
41 .collect();
42 }
43 }
44
45 fn crawl_type(&self) -> CrawlType {
46 CrawlType::Segment(vec![SegmentType::Identifier])
47 }
48
49 fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
50 if self.blocked_words.is_empty() {
51 return vec![];
52 }
53
54 let Segment::Token(t) = ctx.segment else {
55 return vec![];
56 };
57
58 let word = t.token.text.to_lowercase();
59 if self.blocked_words.contains(&word) {
60 return vec![LintViolation::with_msg_key(
61 self.code(),
62 format!("Identifier '{}' is a blocked word.", t.token.text),
63 t.token.span,
64 "rules.CV09.msg",
65 vec![("name".to_string(), t.token.text.to_string())],
66 )];
67 }
68
69 vec![]
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::test_utils::lint_sql;
77
78 #[test]
79 fn test_cv09_no_blocked_words_no_violation() {
80 let violations = lint_sql("SELECT temp FROM t", RuleCV09::default());
81 assert_eq!(violations.len(), 0);
82 }
83
84 #[test]
85 fn test_cv09_flags_blocked_word() {
86 let rule = RuleCV09 {
87 blocked_words: vec!["temp".to_string(), "foo".to_string()],
88 };
89 let violations = lint_sql("SELECT temp FROM t", rule);
90 assert_eq!(violations.len(), 1);
91 }
92}