use crate::llm::ResponseSchema;
use crate::report_types::LLMVerdict;
use crate::roles::{classify_file_role, file_role_label};
use crate::types::FileRecord;
use std::path::Path;
use super::support;
use super::verdicts::{build_file_verdict, normalize_file_verdict};
use super::{Analyzer, ReviewProgressCallback, analyzer_prompts};
pub(super) async fn analyze_file(
analyzer: &Analyzer,
file: &FileRecord,
static_signals: &[String],
on_progress: Option<&ReviewProgressCallback>,
) -> Result<(Option<LLMVerdict>, usize, usize), String> {
let filename = Path::new(&file.file_path)
.file_name()
.and_then(|s| s.to_str())
.unwrap_or("");
let review_source = support::strip_rust_cfg_test_source(&file.source);
let prompt = support::render_template(
analyzer_prompts::FILE_REVIEW_PROMPT,
&[
&filename,
&file.file_path,
&file_role_label(classify_file_role(&file.file_path)),
&support::format_method_inventory(file),
&support::format_static_signals(static_signals),
&review_source,
],
);
let (result, mut i, mut o) = analyzer
.llm_client
.call(&prompt, ResponseSchema::FileReview)
.await?;
let Some(result) = result else {
support::log_ai_review_miss("file", &file.file_path, None);
return Ok((None, i, o));
};
let mut verdict = build_file_verdict(&result, &file.file_path);
normalize_file_verdict(file, &analyzer.llm_client, &mut verdict);
if support::clear_if_unsupported_reason(&mut verdict) {
return Ok((Some(verdict), i, o));
}
let retry_label = format!("file {}", file.file_path);
let (verdict, retry_i, retry_o) = support::retry_invalid_evidence(
analyzer,
&prompt,
ResponseSchema::FileReview,
verdict,
support::RetryContext {
source: &review_source,
label: &retry_label,
on_progress,
},
|retry_result| {
let mut verdict = build_file_verdict(retry_result, &file.file_path);
normalize_file_verdict(file, &analyzer.llm_client, &mut verdict);
verdict
},
)
.await?;
i += retry_i;
o += retry_o;
Ok((Some(verdict), i, o))
}