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