cha_core/plugins/
speculative_generality.rs1use crate::{AnalysisContext, Finding, Location, Plugin, Severity, SmellCategory};
2
3pub struct SpeculativeGeneralityAnalyzer;
5
6impl Default for SpeculativeGeneralityAnalyzer {
7 fn default() -> Self {
8 Self
9 }
10}
11
12impl Plugin for SpeculativeGeneralityAnalyzer {
13 fn name(&self) -> &str {
14 "speculative_generality"
15 }
16
17 fn description(&self) -> &str {
18 "Interface with too few implementations"
19 }
20
21 fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
22 let interfaces: Vec<_> = ctx
24 .model
25 .classes
26 .iter()
27 .filter(|c| c.is_interface)
28 .collect();
29 if interfaces.is_empty() {
30 return vec![];
31 }
32 let mut findings = Vec::new();
33 for iface in &interfaces {
34 let impl_count = ctx
35 .model
36 .classes
37 .iter()
38 .filter(|c| c.parent_name.as_deref() == Some(&iface.name))
39 .count();
40 if impl_count <= 1 {
42 findings.push(Finding {
43 smell_name: "speculative_generality".into(),
44 category: SmellCategory::Dispensables,
45 severity: Severity::Hint,
46 location: Location {
47 path: ctx.file.path.clone(),
48 start_line: iface.start_line,
49 start_col: iface.name_col,
50 end_line: iface.start_line,
51 end_col: iface.name_end_col,
52 name: Some(iface.name.clone()),
53 },
54 message: format!(
55 "Interface `{}` has only {} implementation(s) in this file, consider Collapse Hierarchy",
56 iface.name, impl_count
57 ),
58 suggested_refactorings: vec![
59 "Collapse Hierarchy".into(),
60 "Inline Class".into(),
61 ],
62 ..Default::default()
63 });
64 }
65 }
66 findings
67 }
68}