Skip to main content

cha_core/plugins/
brain_method.rs

1use crate::{AnalysisContext, Finding, Location, Plugin, Severity, SmellCategory};
2
3/// Detect Brain Methods using the detection strategy from [1]:
4///
5///   (LOC > High/2) AND (CYCLO >= High) AND (MAXNESTING >= Several) AND (NOAV > Many)
6///
7/// Since cha does not track MAXNESTING, we use a three-metric variant:
8///
9///   (LOC > 65) AND (CYCLO >= 4) AND (NOAV > 7)
10///
11/// ## References
12///
13/// [1] M. Lanza and R. Marinescu, "Object-Oriented Metrics in Practice:
14///     Using Software Metrics to Characterize, Evaluate, and Improve the
15///     Design of Object-Oriented Systems," Springer, 2006.
16///     doi: 10.1007/3-540-39538-5. Chapter 6.2.
17///     Thresholds derived from Table A.2 (45 Java projects):
18///     LOC High = 130, CYCLO High ≈ 3.1, Several = 3, Many = 7–8.
19pub struct BrainMethodAnalyzer {
20    /// LOC threshold (High/2 = 65)
21    pub min_lines: usize,
22    /// CYCLO threshold (High ≈ 4)
23    pub min_complexity: usize,
24    /// NOAV threshold (Many = 7)
25    pub min_external_refs: usize,
26}
27
28impl Default for BrainMethodAnalyzer {
29    fn default() -> Self {
30        Self {
31            min_lines: 65,
32            min_complexity: 4,
33            min_external_refs: 7,
34        }
35    }
36}
37
38impl Plugin for BrainMethodAnalyzer {
39    fn name(&self) -> &str {
40        "brain_method"
41    }
42
43    fn description(&self) -> &str {
44        "Brain Method: too long, complex, and coupled"
45    }
46
47    fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
48        ctx.model
49            .functions
50            .iter()
51            .filter(|f| {
52                f.line_count >= self.min_lines
53                    && f.complexity >= self.min_complexity
54                    && f.external_refs.len() >= self.min_external_refs
55            })
56            .map(|f| Finding {
57                smell_name: "brain_method".into(),
58                category: SmellCategory::Bloaters,
59                severity: Severity::Warning,
60                location: Location {
61                    path: ctx.file.path.clone(),
62                    start_line: f.start_line,
63                    end_line: f.end_line,
64                    name: Some(f.name.clone()),
65                },
66                message: format!(
67                    "Function `{}` is a Brain Method ({}L, complexity {}, {} external refs)",
68                    f.name,
69                    f.line_count,
70                    f.complexity,
71                    f.external_refs.len()
72                ),
73                suggested_refactorings: vec!["Extract Method".into(), "Move Method".into()],
74                ..Default::default()
75            })
76            .collect()
77    }
78}