Skip to main content

cha_core/plugins/
complexity.rs

1use crate::{AnalysisContext, Finding, Plugin, Severity, SmellCategory, func_location};
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 smells(&self) -> Vec<String> {
24        vec!["high_complexity".into()]
25    }
26
27    fn description(&self) -> &str {
28        "Cyclomatic complexity exceeds threshold"
29    }
30
31    fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
32        ctx.model
33            .functions
34            .iter()
35            .filter_map(|f| self.check_function(ctx, f))
36            .collect()
37    }
38}
39
40impl ComplexityAnalyzer {
41    /// Build a finding for a single function if its complexity exceeds the threshold.
42    fn check_function(&self, ctx: &AnalysisContext, f: &crate::FunctionInfo) -> Option<Finding> {
43        if f.complexity < self.warn_threshold {
44            return None;
45        }
46        let severity = if f.complexity >= self.error_threshold {
47            Severity::Error
48        } else {
49            Severity::Warning
50        };
51        Some(Finding {
52            smell_name: "high_complexity".into(),
53            category: SmellCategory::Bloaters,
54            severity,
55            location: func_location(&ctx.file.path, f),
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}