dei_core/
metrics.rs

1//! Code metrics with strong typing
2
3use serde::{Deserialize, Serialize};
4use std::sync::Arc;
5use crate::thresholds::*;
6
7/// Method-level metrics with zero-copy strings where possible
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct MethodMetrics {
10    pub name: Arc<str>,
11    pub lines: Lines,
12    pub complexity: Complexity,
13    pub parameters: ParamCount,
14    pub called_methods: Arc<[Arc<str>]>,
15    pub accessed_fields: Arc<[Arc<str>]>,
16    pub return_type: Arc<str>,
17    pub is_public: bool,
18    pub is_static: bool,
19    pub is_async: bool,
20    pub tokens: Arc<[Arc<str>]>, // For semantic analysis
21}
22
23impl MethodMetrics {
24    /// Check if method exceeds any threshold
25    pub fn is_god_method(&self, thresholds: &Thresholds) -> bool {
26        self.lines > thresholds.max_method_lines
27            || self.complexity > thresholds.max_method_complexity
28            || self.parameters > thresholds.max_parameters
29    }
30
31    /// Calculate violation score (higher = worse)
32    pub fn violation_score(&self, thresholds: &Thresholds) -> f64 {
33        let line_ratio = self.lines.0 as f64 / thresholds.max_method_lines.0 as f64;
34        let complexity_ratio = self.complexity.0 as f64 / thresholds.max_method_complexity.0 as f64;
35        let param_ratio = self.parameters.0 as f64 / thresholds.max_parameters.0 as f64;
36        
37        (line_ratio + complexity_ratio + param_ratio) / 3.0
38    }
39}
40
41/// Class-level metrics
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ClassMetrics {
44    pub name: Arc<str>,
45    pub fully_qualified_name: Arc<str>,
46    pub file_path: Arc<str>,
47    pub lines: Lines,
48    pub method_count: MethodCount,
49    pub property_count: usize,
50    pub field_count: usize,
51    pub complexity: Complexity,
52    pub methods: Arc<[MethodMetrics]>,
53    pub dependencies: Arc<[Arc<str>]>,
54}
55
56impl ClassMetrics {
57    /// Check if class exceeds any threshold
58    pub fn is_god_class(&self, thresholds: &Thresholds) -> bool {
59        self.lines > thresholds.max_class_lines
60            || self.method_count > thresholds.max_methods
61            || self.complexity > thresholds.max_class_complexity
62    }
63
64    /// Count god methods in this class
65    pub fn god_method_count(&self, thresholds: &Thresholds) -> usize {
66        self.methods.iter().filter(|m| m.is_god_method(thresholds)).count()
67    }
68}
69
70/// File-level metrics
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct FileMetrics {
73    pub path: Arc<str>,
74    pub lines: Lines,
75    pub classes: Arc<[ClassMetrics]>,
76}
77
78impl FileMetrics {
79    /// Check if file has too many classes or is too long
80    pub fn is_god_file(&self, thresholds: &Thresholds) -> bool {
81        self.classes.len() > thresholds.max_classes_per_file
82            || self.lines > thresholds.max_file_lines
83    }
84}
85