cha_core/plugins/
coupling.rs1use crate::{AnalysisContext, Finding, Location, Plugin, Severity, SmellCategory};
2
3pub struct CouplingAnalyzer {
5 pub max_imports: usize,
6}
7
8impl Default for CouplingAnalyzer {
9 fn default() -> Self {
10 Self { max_imports: 15 }
11 }
12}
13
14impl Plugin for CouplingAnalyzer {
15 fn name(&self) -> &str {
16 "coupling"
17 }
18
19 fn smells(&self) -> Vec<String> {
20 vec!["high_coupling".into()]
21 }
22
23 fn description(&self) -> &str {
24 "Too many imports (high coupling)"
25 }
26
27 fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
28 let mut findings = Vec::new();
29
30 let import_count = ctx
33 .model
34 .imports
35 .iter()
36 .filter(|i| !i.is_module_decl)
37 .count();
38
39 let first = ctx.model.imports.first().map(|i| i.line).unwrap_or(1);
40 let first_col = ctx.model.imports.first().map(|i| i.col).unwrap_or(0);
41 let last = ctx.model.imports.last().map(|i| i.line).unwrap_or(1);
42
43 if import_count > self.max_imports {
44 findings.push(Finding {
45 smell_name: "high_coupling".into(),
46 category: SmellCategory::Couplers,
47 severity: if import_count > self.max_imports * 2 {
48 Severity::Error
49 } else {
50 Severity::Warning
51 },
52 location: Location {
53 path: ctx.file.path.clone(),
54 start_line: first,
55 start_col: first_col,
56 end_line: last,
57 name: None,
58 ..Default::default()
59 },
60 message: format!(
61 "File has {} imports (threshold: {})",
62 import_count, self.max_imports
63 ),
64 suggested_refactorings: vec!["Move Method".into(), "Extract Class".into()],
65 actual_value: Some(import_count as f64),
66 threshold: Some(self.max_imports as f64),
67 });
68 }
69
70 findings
71 }
72}