Skip to main content

cha_core/plugins/
lazy_class.rs

1use crate::{AnalysisContext, Finding, Location, Plugin, Severity, SmellCategory};
2
3/// Detect classes with very few methods and lines (nearly empty wrappers).
4pub struct LazyClassAnalyzer {
5    pub max_methods: usize,
6    pub max_lines: usize,
7}
8
9impl Default for LazyClassAnalyzer {
10    fn default() -> Self {
11        Self {
12            max_methods: 1,
13            max_lines: 10,
14        }
15    }
16}
17
18impl Plugin for LazyClassAnalyzer {
19    fn name(&self) -> &str {
20        "lazy_class"
21    }
22
23    fn smells(&self) -> Vec<String> {
24        vec!["lazy_class".into()]
25    }
26
27    fn description(&self) -> &str {
28        "Class too small to justify its existence"
29    }
30
31    fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding> {
32        ctx.model
33            .classes
34            .iter()
35            .filter_map(|c| {
36                if c.is_interface
37                    || c.method_count > self.max_methods
38                    || c.line_count > self.max_lines
39                {
40                    return None;
41                }
42                Some(Finding {
43                    smell_name: "lazy_class".into(),
44                    category: SmellCategory::Dispensables,
45                    severity: Severity::Hint,
46                    location: Location {
47                        path: ctx.file.path.clone(),
48                        start_line: c.start_line,
49                        start_col: c.name_col,
50                        end_line: c.start_line,
51                        end_col: c.name_end_col,
52                        name: Some(c.name.clone()),
53                    },
54                    message: format!(
55                        "Class `{}` has only {} method(s) and {} lines, consider Inline Class",
56                        c.name, c.method_count, c.line_count
57                    ),
58                    suggested_refactorings: vec!["Inline Class".into()],
59                    actual_value: Some(c.method_count as f64),
60                    threshold: Some(self.max_methods as f64),
61                    risk_score: None,
62                })
63            })
64            .collect()
65    }
66}