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 description(&self) -> &str {
24 "Class that only delegates to others"
25 }
26
27 fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
28 ctx.model
29 .classes
30 .iter()
31 .filter(|c| {
32 c.method_count >= self.min_methods
33 && c.delegating_method_count > 0
34 && (c.delegating_method_count as f64 / c.method_count as f64)
35 >= self.delegation_ratio
36 })
37 .map(|c| Finding {
38 smell_name: "middle_man".into(),
39 category: SmellCategory::Couplers,
40 severity: Severity::Hint,
41 location: Location {
42 path: ctx.file.path.clone(),
43 start_line: c.start_line,
44 start_col: c.name_col,
45 end_line: c.start_line,
46 end_col: c.name_end_col,
47 name: Some(c.name.clone()),
48 },
49 message: format!(
50 "Class `{}` delegates {}/{} methods, acting as a middle man",
51 c.name, c.delegating_method_count, c.method_count
52 ),
53 suggested_refactorings: vec!["Remove Middle Man".into()],
54 actual_value: Some(c.delegating_method_count as f64 / c.method_count as f64),
55 threshold: Some(self.delegation_ratio),
56 })
57 .collect()
58 }
59}