cha_core/plugins/
middle_man.rs1use crate::{AnalysisContext, Finding, Location, Plugin, Severity, SmellCategory};
2
3pub struct MiddleManAnalyzer {
5 pub min_methods: usize,
6 pub delegation_ratio: f64,
7}
8
9impl Default for MiddleManAnalyzer {
10 fn default() -> Self {
11 Self {
12 min_methods: 3,
13 delegation_ratio: 0.5,
14 }
15 }
16}
17
18impl Plugin for MiddleManAnalyzer {
19 fn name(&self) -> &str {
20 "middle_man"
21 }
22
23 fn smells(&self) -> Vec<String> {
24 vec!["middle_man".into()]
25 }
26
27 fn description(&self) -> &str {
28 "Class that only delegates to others"
29 }
30
31 fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
32 ctx.model
33 .classes
34 .iter()
35 .filter(|c| {
36 c.method_count >= self.min_methods
37 && c.delegating_method_count > 0
38 && (c.delegating_method_count as f64 / c.method_count as f64)
39 >= self.delegation_ratio
40 })
41 .map(|c| Finding {
42 smell_name: "middle_man".into(),
43 category: SmellCategory::Couplers,
44 severity: Severity::Hint,
45 location: Location {
46 path: ctx.file.path.clone(),
47 start_line: c.start_line,
48 start_col: c.name_col,
49 end_line: c.start_line,
50 end_col: c.name_end_col,
51 name: Some(c.name.clone()),
52 },
53 message: format!(
54 "Class `{}` delegates {}/{} methods, acting as a middle man",
55 c.name, c.delegating_method_count, c.method_count
56 ),
57 suggested_refactorings: vec!["Remove Middle Man".into()],
58 actual_value: Some(c.delegating_method_count as f64 / c.method_count as f64),
59 threshold: Some(self.delegation_ratio),
60 risk_score: None,
61 })
62 .collect()
63 }
64}