sqrust_rules/layout/
nested_parentheses.rs1use sqrust_core::{Diagnostic, FileContext, Rule};
2
3pub struct NestedParentheses {
4 pub max_depth: usize,
5}
6
7impl Default for NestedParentheses {
8 fn default() -> Self {
9 NestedParentheses { max_depth: 5 }
10 }
11}
12
13impl Rule for NestedParentheses {
14 fn name(&self) -> &'static str {
15 "Layout/NestedParentheses"
16 }
17
18 fn check(&self, ctx: &FileContext) -> Vec<Diagnostic> {
19 find_violations(&ctx.source, self.name(), self.max_depth)
20 }
21}
22
23fn find_violations(source: &str, rule_name: &'static str, max_depth: usize) -> Vec<Diagnostic> {
24 let bytes = source.as_bytes();
25 let len = bytes.len();
26 let mut diags = Vec::new();
27
28 let mut depth = 0usize;
29 let mut in_string = false;
30 let mut over_max = false;
33
34 let mut i = 0usize;
35 while i < len {
36 let byte = bytes[i];
37
38 if in_string {
39 if byte == b'\'' {
40 if i + 1 < len && bytes[i + 1] == b'\'' {
42 i += 2;
43 continue;
44 }
45 in_string = false;
46 }
47 i += 1;
48 continue;
49 }
50
51 if byte == b'\'' {
53 in_string = true;
54 i += 1;
55 continue;
56 }
57
58 if byte == b'(' {
59 depth += 1;
60 if depth > max_depth && !over_max {
61 over_max = true;
62 let (line, col) = byte_offset_to_line_col(source, i);
63 diags.push(Diagnostic {
64 rule: rule_name,
65 message: format!(
66 "Parenthesis nesting depth {} exceeds maximum of {}",
67 depth, max_depth
68 ),
69 line,
70 col,
71 });
72 }
73 } else if byte == b')' {
74 if depth > 0 {
75 depth -= 1;
76 }
77 if depth <= max_depth {
80 over_max = false;
81 }
82 }
83
84 i += 1;
85 }
86
87 diags
88}
89
90fn byte_offset_to_line_col(source: &str, offset: usize) -> (usize, usize) {
92 let mut line = 1usize;
93 let mut line_start = 0usize;
94 for (i, ch) in source.char_indices() {
95 if i == offset {
96 break;
97 }
98 if ch == '\n' {
99 line += 1;
100 line_start = i + 1;
101 }
102 }
103 let col = offset - line_start + 1;
104 (line, col)
105}