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> {
23 Ok(Self {
24 function_def: Regex::new(r"^\s*(pub\s+)?(async\s+)?fn\s+")
25 .map_err(|e| Error::validation(format!("Invalid function regex: {}", e)))?,
26
27 underscore_param: Regex::new(r"fn\s+\w+[^{]*\b_\w+\s*:")
28 .map_err(|e| Error::validation(format!("Invalid underscore param regex: {}", e)))?,
29
30 underscore_let: Regex::new(r"^\s*let\s+_\s*=")
31 .map_err(|e| Error::validation(format!("Invalid underscore let regex: {}", e)))?,
32
33 unwrap_call: Regex::new(r"\.unwrap\(\)")
34 .map_err(|e| Error::validation(format!("Invalid unwrap regex: {}", e)))?,
35
36 expect_call: Regex::new(r"\.expect\(")
37 .map_err(|e| Error::validation(format!("Invalid expect regex: {}", e)))?,
38 })
39 }
40}
41
42pub fn is_in_string_literal(line: &str, pattern: &str) -> bool {
44 if !line.contains(pattern) {
46 return false;
47 }
48
49 let pattern_positions: Vec<usize> = line.match_indices(pattern).map(|(i, _)| i).collect();
51 if pattern_positions.is_empty() {
52 return false;
53 }
54
55 for pattern_pos in pattern_positions {
57 let mut in_string = false;
58 let mut in_raw_string = false;
59 let mut escaped = false;
60 let mut pos = 0;
61
62 if let Some(comment_pos) = line.find("//") {
64 if pattern_pos >= comment_pos {
65 continue; }
67 }
68
69 for c in line.chars() {
70 if pos >= pattern_pos {
71 if !in_string && !in_raw_string {
74 return false;
75 }
76 break;
77 }
78
79 if escaped {
80 escaped = false;
81 pos += c.len_utf8();
82 continue;
83 }
84
85 match c {
86 '\\' if in_string && !in_raw_string => escaped = true,
87 '"' if !in_raw_string => in_string = !in_string,
88 'r' if !in_string && !in_raw_string => {
89 let remaining = &line[pos..];
91 if remaining.starts_with("r\"") || remaining.starts_with("r#\"") {
92 in_raw_string = true;
93 }
94 }
95 _ => {}
96 }
97
98 pos += c.len_utf8();
99 }
100 }
101
102 true
104}