use crate::domain::detectors::detect_all;
use crate::domain::metrics::{CodeMetrics, ItemType, SmellDetection};
use crate::ports::parser::CodeParser;
use super::{
GenericParser, build_func_metrics_full, cached_regex, cached_regex_owned, calculate_cc,
count_block_comment_lines, count_line_comment_lines, count_loc, count_local_vars,
count_primitive_params_go, find_matching_brace, line_number,
};
pub struct GoFullParser {
inner: GenericParser,
}
impl GoFullParser {
pub fn new() -> Self {
Self {
inner: super::generic::go_parser(),
}
}
}
impl Default for GoFullParser {
fn default() -> Self {
Self::new()
}
}
impl CodeParser for GoFullParser {
fn parse_code(&self, code: &str, file_name: &str) -> Vec<SmellDetection> {
let cleaned = self.inner.strip_comments(code);
let mut detections: Vec<SmellDetection> = Vec::new();
let func_re = self.inner.get_func_re();
for cap in func_re.captures_iter(&cleaned) {
let name = &cap[1];
let full = cap.get(0).unwrap();
let start = full.start();
let brace_pos = match cleaned[start..].find('{') {
Some(off) => start + off,
None => continue,
};
let end_pos = match find_matching_brace(&cleaned, brace_pos) {
Some(p) => p,
None => continue,
};
let body = &cleaned[start..=end_pos];
let sig = &cleaned[start..];
let raw_body = &code[start..=end_pos];
let comment_count =
count_line_comment_lines(raw_body, "//") + count_block_comment_lines(raw_body);
let metrics = build_func_metrics_full(
body,
sig,
calculate_cc,
count_local_vars,
count_primitive_params_go,
comment_count,
);
let location = format!("{}:{}", file_name, line_number(&cleaned, start));
detections.extend(detect_all(&metrics, &location, name));
}
let struct_re = cached_regex(r"(?m)type\s+(\w+)\s+struct\s*\{");
for cap in struct_re.captures_iter(&cleaned) {
let name = &cap[1];
let full = cap.get(0).unwrap();
let start = full.start();
let brace_pos = match cleaned[start..].find('{') {
Some(off) => start + off,
None => continue,
};
let end_pos = match find_matching_brace(&cleaned, brace_pos) {
Some(p) => p,
None => continue,
};
let body = &cleaned[start..=end_pos];
let field_count = body
.lines()
.filter(|l| {
let t = l.trim();
!t.is_empty() && t != "{" && t != "}" && !t.starts_with("//")
})
.count();
let method_re = cached_regex_owned(&format!(r"(?m)func\s+\([^)]*\s+\*?{name}\)\s+\w+"));
let method_count = method_re.find_iter(&cleaned).count();
let metrics = CodeMetrics {
loc: count_loc(body),
method_count,
field_count,
item_type: ItemType::Class,
..Default::default()
};
let location = format!("{}:{}", file_name, line_number(&cleaned, start));
detections.extend(detect_all(&metrics, &location, name));
}
detections
}
fn supported_extensions(&self) -> &[&str] {
&["go"]
}
}