ferrous_forge/ai_analyzer/
context.rs1use super::types::{CodeContext, ErrorHandlingStyle};
7
8pub fn extract_code_context(line_number: usize, content: &str) -> CodeContext {
10 let lines: Vec<&str> = content.lines().collect();
11 let context_start = line_number.saturating_sub(10);
12 let context_end = (line_number + 10).min(lines.len());
13
14 let surrounding_code = lines[context_start..context_end]
15 .iter()
16 .map(|s| s.to_string())
17 .collect();
18
19 let imports = extract_imports(content);
20 let (function_name, function_signature, return_type) =
21 extract_function_info(&lines, line_number);
22 let is_async = function_signature
23 .as_ref()
24 .map(|s| s.contains("async"))
25 .unwrap_or(false);
26 let is_generic = function_signature
27 .as_ref()
28 .map(|s| s.contains('<'))
29 .unwrap_or(false);
30 let trait_impl = detect_trait_impl(content, line_number);
31 let error_handling_style = detect_error_handling_style(&imports, content);
32
33 CodeContext {
34 function_name,
35 function_signature,
36 return_type,
37 is_async,
38 is_generic,
39 trait_impl,
40 surrounding_code,
41 imports,
42 error_handling_style,
43 }
44}
45
46fn extract_imports(content: &str) -> Vec<String> {
50 content
51 .lines()
52 .filter(|line| line.trim().starts_with("use "))
53 .map(|s| s.to_string())
54 .collect()
55}
56
57fn extract_function_info(
64 lines: &[&str],
65 line_number: usize,
66) -> (Option<String>, Option<String>, Option<String>) {
67 for i in (0..line_number).rev() {
68 if let Some(line) = lines.get(i) {
69 if line.contains("fn ") && !line.trim().starts_with("//") {
70 let signature = line.trim().to_string();
71 let name = signature
72 .split("fn ")
73 .nth(1)
74 .and_then(|s| s.split('(').next())
75 .map(|s| s.trim().to_string());
76 let return_type = if signature.contains("->") {
77 signature.split("->").nth(1).map(|s| s.trim().to_string())
78 } else {
79 None
80 };
81 return (name, Some(signature), return_type);
82 }
83 }
84 }
85 (None, None, None)
86}
87
88pub fn detect_error_handling_style(imports: &[String], content: &str) -> ErrorHandlingStyle {
90 if imports.iter().any(|i| i.contains("anyhow")) || content.contains("anyhow::Result") {
91 ErrorHandlingStyle::AnyhowResult
92 } else if content.contains("Result<") && !content.contains("std::result::Result") {
93 ErrorHandlingStyle::CustomResult
94 } else if content.contains("Result<") {
95 ErrorHandlingStyle::StdResult
96 } else if content.contains("Option<") {
97 ErrorHandlingStyle::OptionBased
98 } else if content.contains("panic!") || content.contains(".unwrap()") {
99 ErrorHandlingStyle::Panic
100 } else {
101 ErrorHandlingStyle::Unknown
102 }
103}
104
105fn detect_trait_impl(content: &str, line: usize) -> Option<String> {
110 let lines: Vec<&str> = content.lines().collect();
111 for i in (0..line.min(lines.len())).rev() {
112 if lines[i].contains("impl") && lines[i].contains("for") {
113 return Some(lines[i].trim().to_string());
114 }
115 }
116 None
117}