impl LanguageAnalyzer {
pub async fn analyze_file(
&self,
path: &Path,
analysis_types: Vec<AnalysisType>,
) -> Result<LanguageAnalysisResult> {
let start_time = std::time::Instant::now();
let language = self.language_registry.detect_language(path);
let content = tokio::fs::read_to_string(path).await?;
let metadata = self.analyze_file_metadata(&content, language);
let analysis_results = self
.perform_analyses(&content, language, &analysis_types)
.await?;
let processing_time = start_time.elapsed().as_millis() as u64;
if let Ok(mut metrics) = self.metrics.lock() {
metrics.record_request(start_time.elapsed(), true);
}
Ok(LanguageAnalysisResult {
path: path.to_path_buf(),
language,
analysis_results,
metadata,
processing_time_ms: processing_time,
})
}
#[must_use]
pub fn supported_languages(&self) -> &[Language] {
self.language_registry.supported_languages()
}
#[must_use]
pub fn supports_analysis(&self, language: Language, analysis_type: &AnalysisType) -> bool {
match analysis_type {
AnalysisType::Complexity => language.supports_complexity(),
AnalysisType::Satd => true, AnalysisType::DeadCode => language.has_ast_support(),
AnalysisType::Security => language.supports_complexity(), AnalysisType::Style => language.has_ast_support(),
AnalysisType::Documentation => matches!(
language,
Language::Markdown | Language::LaTeX | Language::AsciiDoc | Language::Unknown
), AnalysisType::Dependencies => language.has_ast_support(),
AnalysisType::Metrics => true, }
}
fn analyze_file_metadata(&self, content: &str, language: Language) -> FileMetadata {
let lines: Vec<&str> = content.lines().collect();
let total_lines = lines.len();
let mut code_lines = 0;
let mut comment_lines = 0;
let mut blank_lines = 0;
for line in &lines {
let trimmed = line.trim();
if trimmed.is_empty() {
blank_lines += 1;
} else if self.is_comment_line(trimmed, language) {
comment_lines += 1;
} else {
code_lines += 1;
}
}
FileMetadata {
lines_total: total_lines,
lines_code: code_lines,
lines_comment: comment_lines,
lines_blank: blank_lines,
file_size_bytes: content.len() as u64,
detected_language: language,
confidence: 1.0, }
}
fn is_comment_line(&self, line: &str, language: Language) -> bool {
match self.get_comment_style(language) {
CommentStyle::CStyle => self.is_c_style_comment(line),
CommentStyle::Hash => line.starts_with('#'),
CommentStyle::Semicolon => line.starts_with(';'),
CommentStyle::Percent => line.starts_with('%'),
CommentStyle::DoubleDash => line.starts_with("--"),
CommentStyle::Xml => line.starts_with("<!--"),
CommentStyle::None => false,
}
}
fn get_comment_style(&self, language: Language) -> CommentStyle {
match language {
Language::Rust
| Language::C
| Language::Cpp
| Language::Go
| Language::Java
| Language::Kotlin
| Language::JavaScript
| Language::TypeScript
| Language::CSharp
| Language::Swift
| Language::Dart
| Language::Scala
| Language::Groovy => CommentStyle::CStyle,
Language::Python
| Language::Ruby
| Language::Bash
| Language::Zsh
| Language::Fish
| Language::Perl
| Language::R
| Language::YAML
| Language::TOML
| Language::Makefile => CommentStyle::Hash,
Language::Clojure => CommentStyle::Semicolon,
Language::Erlang | Language::Matlab => CommentStyle::Percent,
Language::SQL | Language::Haskell | Language::Lean => CommentStyle::DoubleDash,
Language::XML => CommentStyle::Xml,
_ => CommentStyle::None,
}
}
fn is_c_style_comment(&self, line: &str) -> bool {
line.starts_with("//") || line.starts_with("/*") || line.starts_with('*')
}
}