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 end_line: c.end_line,
45 name: Some(c.name.clone()),
46 },
47 message: format!(
48 "Class `{}` delegates {}/{} methods, acting as a middle man",
49 c.name, c.delegating_method_count, c.method_count
50 ),
51 suggested_refactorings: vec!["Remove Middle Man".into()],
52 actual_value: Some(c.delegating_method_count as f64 / c.method_count as f64),
53 threshold: Some(self.delegation_ratio),
54 })
55 .collect()
56 }
57}