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 && line.contains("fn ")
70 && !line.trim().starts_with("//")
71 {
72 let signature = line.trim().to_string();
73 let name = signature
74 .split("fn ")
75 .nth(1)
76 .and_then(|s| s.split('(').next())
77 .map(|s| s.trim().to_string());
78 let return_type = if signature.contains("->") {
79 signature.split("->").nth(1).map(|s| s.trim().to_string())
80 } else {
81 None
82 };
83 return (name, Some(signature), return_type);
84 }
85 }
86 (None, None, None)
87}
88
89pub fn detect_error_handling_style(imports: &[String], content: &str) -> ErrorHandlingStyle {
91 if imports.iter().any(|i| i.contains("anyhow")) || content.contains("anyhow::Result") {
92 ErrorHandlingStyle::AnyhowResult
93 } else if content.contains("Result<") && !content.contains("std::result::Result") {
94 ErrorHandlingStyle::CustomResult
95 } else if content.contains("Result<") {
96 ErrorHandlingStyle::StdResult
97 } else if content.contains("Option<") {
98 ErrorHandlingStyle::OptionBased
99 } else if content.contains("panic!") || content.contains(".unwrap()") {
100 ErrorHandlingStyle::Panic
101 } else {
102 ErrorHandlingStyle::Unknown
103 }
104}
105
106fn detect_trait_impl(content: &str, line: usize) -> Option<String> {
111 let lines: Vec<&str> = content.lines().collect();
112 for i in (0..line.min(lines.len())).rev() {
113 if lines[i].contains("impl") && lines[i].contains("for") {
114 return Some(lines[i].trim().to_string());
115 }
116 }
117 None
118}