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 end_line: iface.end_line,
50 name: Some(iface.name.clone()),
51 },
52 message: format!(
53 "Interface `{}` has only {} implementation(s) in this file, consider Collapse Hierarchy",
54 iface.name, impl_count
55 ),
56 suggested_refactorings: vec![
57 "Collapse Hierarchy".into(),
58 "Inline Class".into(),
59 ],
60 ..Default::default()
61 });
62 }
63 }
64 findings
65 }
66}