ferrous_forge/validation/rust_validator/
patterns.rs1use crate::{Error, Result};
4use regex::Regex;
5
6pub struct ValidationPatterns {
8 pub function_def: Regex,
10 pub underscore_param: Regex,
12 pub underscore_let: Regex,
14 pub unwrap_call: Regex,
16 pub expect_call: Regex,
18}
19
20impl ValidationPatterns {
21 pub fn new() -> Result<Self> {
27 Ok(Self {
28 function_def: Regex::new(r"^\s*(pub\s+)?(async\s+)?fn\s+")
29 .map_err(|e| Error::validation(format!("Invalid function regex: {}", e)))?,
30
31 underscore_param: Regex::new(r"fn\s+\w+[^{]*\b_\w+\s*:")
32 .map_err(|e| Error::validation(format!("Invalid underscore param regex: {}", e)))?,
33
34 underscore_let: Regex::new(r"^\s*let\s+_\s*=")
35 .map_err(|e| Error::validation(format!("Invalid underscore let regex: {}", e)))?,
36
37 unwrap_call: Regex::new(r"\.unwrap\(\)")
38 .map_err(|e| Error::validation(format!("Invalid unwrap regex: {}", e)))?,
39
40 expect_call: Regex::new(r"\.expect\(")
41 .map_err(|e| Error::validation(format!("Invalid expect regex: {}", e)))?,
42 })
43 }
44}
45
46pub fn is_in_string_literal(line: &str, pattern: &str) -> bool {
48 if !line.contains(pattern) {
50 return false;
51 }
52
53 let pattern_positions: Vec<usize> = line.match_indices(pattern).map(|(i, _)| i).collect();
55 if pattern_positions.is_empty() {
56 return false;
57 }
58
59 for pattern_pos in pattern_positions {
61 let mut in_string = false;
62 let mut in_raw_string = false;
63 let mut escaped = false;
64 let mut pos = 0;
65
66 if let Some(comment_pos) = line.find("//")
68 && pattern_pos >= comment_pos
69 {
70 continue; }
72
73 for c in line.chars() {
74 if pos >= pattern_pos {
75 if !in_string && !in_raw_string {
78 return false;
79 }
80 break;
81 }
82
83 if escaped {
84 escaped = false;
85 pos += c.len_utf8();
86 continue;
87 }
88
89 match c {
90 '\\' if in_string && !in_raw_string => escaped = true,
91 '"' if !in_raw_string => in_string = !in_string,
92 'r' if !in_string && !in_raw_string => {
93 let remaining = &line[pos..];
95 if remaining.starts_with("r\"") || remaining.starts_with("r#\"") {
96 in_raw_string = true;
97 }
98 }
99 _ => {}
100 }
101
102 pos += c.len_utf8();
103 }
104 }
105
106 true
108}