ricecoder_refactoring/adapters/
python.rs1use crate::error::Result;
4use crate::providers::{RefactoringAnalysis, RefactoringProvider};
5use crate::types::{Refactoring, RefactoringType, ValidationResult};
6use regex::Regex;
7
8pub struct PythonRefactoringProvider;
10
11impl PythonRefactoringProvider {
12 pub fn new() -> Self {
14 Self
15 }
16
17 fn is_valid_python(code: &str) -> bool {
19 let open_parens = code.matches('(').count();
21 let close_parens = code.matches(')').count();
22 let open_brackets = code.matches('[').count();
23 let close_brackets = code.matches(']').count();
24 let open_braces = code.matches('{').count();
25 let close_braces = code.matches('}').count();
26
27 open_parens == close_parens
28 && open_brackets == close_brackets
29 && open_braces == close_braces
30 }
31
32 pub fn apply_python_rename(code: &str, old_name: &str, new_name: &str) -> Result<String> {
34 let pattern = format!(r"\b{}\b", regex::escape(old_name));
35 match Regex::new(&pattern) {
36 Ok(re) => Ok(re.replace_all(code, new_name).to_string()),
37 Err(_) => Ok(code.replace(old_name, new_name)),
38 }
39 }
40
41 pub fn check_python_quality(code: &str) -> Vec<String> {
43 let mut issues = vec![];
44
45 if code.contains("eval(") {
46 issues.push("Code uses eval() which is a security risk".to_string());
47 }
48
49 if code.contains("exec(") {
50 issues.push("Code uses exec() which is a security risk".to_string());
51 }
52
53 if code.contains("__import__") {
54 issues.push("Code uses __import__() for dynamic imports".to_string());
55 }
56
57 issues
58 }
59}
60
61impl Default for PythonRefactoringProvider {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl RefactoringProvider for PythonRefactoringProvider {
68 fn analyze_refactoring(
69 &self,
70 _code: &str,
71 _language: &str,
72 refactoring_type: RefactoringType,
73 ) -> Result<RefactoringAnalysis> {
74 let complexity = match refactoring_type {
75 RefactoringType::Rename => 3,
76 RefactoringType::Extract => 5,
77 RefactoringType::Inline => 4,
78 RefactoringType::Move => 6,
79 RefactoringType::ChangeSignature => 7,
80 RefactoringType::RemoveUnused => 3,
81 RefactoringType::Simplify => 4,
82 };
83
84 Ok(RefactoringAnalysis {
85 applicable: true,
86 reason: None,
87 complexity,
88 })
89 }
90
91 fn apply_refactoring(
92 &self,
93 code: &str,
94 _language: &str,
95 refactoring: &Refactoring,
96 ) -> Result<String> {
97 match refactoring.refactoring_type {
99 RefactoringType::Rename => {
100 Self::apply_python_rename(code, &refactoring.target.symbol, &refactoring.target.symbol)
102 }
103 _ => Ok(code.to_string()),
104 }
105 }
106
107 fn validate_refactoring(
108 &self,
109 original: &str,
110 refactored: &str,
111 _language: &str,
112 ) -> Result<ValidationResult> {
113 let mut errors = vec![];
114 let mut warnings = vec![];
115
116 if refactored.is_empty() {
118 errors.push("Refactored code cannot be empty".to_string());
119 }
120
121 if original == refactored {
123 warnings.push("No changes were made".to_string());
124 }
125
126 if !Self::is_valid_python(refactored) {
128 errors.push("Refactored code has syntax errors (paren/bracket mismatch)".to_string());
129 }
130
131 if refactored.contains("exec(") && !original.contains("exec(") {
133 warnings.push("Refactoring introduced exec() call".to_string());
134 }
135
136 Ok(ValidationResult {
137 passed: errors.is_empty(),
138 errors,
139 warnings,
140 })
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_python_provider_analyze() -> Result<()> {
150 let provider = PythonRefactoringProvider::new();
151 let analysis = provider.analyze_refactoring("def main():", "python", RefactoringType::Rename)?;
152
153 assert!(analysis.applicable);
154 assert_eq!(analysis.complexity, 3);
155
156 Ok(())
157 }
158
159 #[test]
160 fn test_python_provider_validate_valid() -> Result<()> {
161 let provider = PythonRefactoringProvider::new();
162 let result = provider.validate_refactoring("def main():", "def main():\n print()", "python")?;
163
164 assert!(result.passed);
165
166 Ok(())
167 }
168
169 #[test]
170 fn test_python_provider_validate_invalid_parens() -> Result<()> {
171 let provider = PythonRefactoringProvider::new();
172 let result = provider.validate_refactoring("def main():", "def main(:", "python")?;
173
174 assert!(!result.passed);
175
176 Ok(())
177 }
178
179 #[test]
180 fn test_is_valid_python() {
181 assert!(PythonRefactoringProvider::is_valid_python("def main():"));
182 assert!(PythonRefactoringProvider::is_valid_python("x = [1, 2, 3]"));
183 assert!(!PythonRefactoringProvider::is_valid_python("def main("));
184 assert!(!PythonRefactoringProvider::is_valid_python("x = [1, 2, 3"));
185 }
186}