Skip to main content

cha_core/plugins/
complexity.rs

1use crate::{AnalysisContext, Finding, Location, Plugin, Severity, SmellCategory};
2
3/// Configurable thresholds for cyclomatic complexity.
4pub struct ComplexityAnalyzer {
5    pub warn_threshold: usize,
6    pub error_threshold: usize,
7}
8
9impl Default for ComplexityAnalyzer {
10    fn default() -> Self {
11        Self {
12            warn_threshold: 10,
13            error_threshold: 20,
14        }
15    }
16}
17
18impl Plugin for ComplexityAnalyzer {
19    fn name(&self) -> &str {
20        "complexity"
21    }
22
23    fn description(&self) -> &str {
24        "Cyclomatic complexity exceeds threshold"
25    }
26
27    fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
28        ctx.model
29            .functions
30            .iter()
31            .filter_map(|f| self.check_function(ctx, f))
32            .collect()
33    }
34}
35
36impl ComplexityAnalyzer {
37    /// Build a finding for a single function if its complexity exceeds the threshold.
38    fn check_function(&self, ctx: &AnalysisContext, f: &crate::FunctionInfo) -> Option<Finding> {
39        if f.complexity < self.warn_threshold {
40            return None;
41        }
42        Some(Finding {
43            smell_name: "high_complexity".into(),
44            category: SmellCategory::Bloaters,
45            severity: if f.complexity >= self.error_threshold {
46                Severity::Error
47            } else {
48                Severity::Warning
49            },
50            location: Location {
51                path: ctx.file.path.clone(),
52                start_line: f.start_line,
53                end_line: f.end_line,
54                name: Some(f.name.clone()),
55            },
56            message: format!(
57                "Function `{}` has complexity {} (threshold: {})",
58                f.name, f.complexity, self.warn_threshold
59            ),
60            suggested_refactorings: vec![
61                "Extract Method".into(),
62                "Replace Conditional with Polymorphism".into(),
63            ],
64            actual_value: Some(f.complexity as f64),
65            threshold: Some(self.warn_threshold as f64),
66        })
67    }
68}