Skip to main content

debtmap/analysis/patterns/
rust_traits.rs

1//! Rust trait-based pattern recognition
2//!
3//! Detects design patterns implemented using Rust traits, such as:
4//! - Trait-based observer patterns
5//! - Visitor pattern through trait implementations
6
7use super::{Implementation, PatternInstance, PatternType, UsageSite};
8use crate::analysis::call_graph::TraitRegistry;
9use std::sync::Arc;
10
11pub struct RustTraitPatternRecognizer {
12    trait_registry: Arc<TraitRegistry>,
13}
14
15impl RustTraitPatternRecognizer {
16    pub fn new(trait_registry: Arc<TraitRegistry>) -> Self {
17        Self { trait_registry }
18    }
19
20    /// Detect trait-based observer patterns in Rust
21    pub fn detect_trait_observer_patterns(&self) -> Vec<PatternInstance> {
22        let mut patterns = Vec::new();
23
24        let stats = self.trait_registry.get_statistics();
25        if stats.total_traits == 0 {
26            return patterns;
27        }
28
29        let unresolved_calls = self.trait_registry.get_unresolved_trait_calls();
30
31        let mut trait_names = std::collections::HashSet::new();
32        for call in unresolved_calls.iter() {
33            if call.trait_name != "Unknown" {
34                trait_names.insert(call.trait_name.clone());
35            }
36        }
37
38        for trait_name in &trait_names {
39            if let Some(implementations) = self.trait_registry.find_implementations(trait_name) {
40                if !implementations.is_empty() {
41                    let impls: Vec<Implementation> = implementations
42                        .iter()
43                        .map(|impl_info| Implementation {
44                            file: impl_info.method_id.file.clone(),
45                            class_name: None,
46                            function_name: impl_info.method_name.clone(),
47                            line: impl_info.method_id.line,
48                        })
49                        .collect();
50
51                    let usage_sites = self.find_trait_method_calls(trait_name);
52
53                    patterns.push(PatternInstance {
54                        pattern_type: PatternType::Observer,
55                        confidence: 0.95,
56                        base_class: Some(trait_name.clone()),
57                        implementations: impls,
58                        usage_sites,
59                        reasoning: format!(
60                            "Rust trait {} with {} implementations",
61                            trait_name,
62                            implementations.len()
63                        ),
64                    });
65                }
66            }
67        }
68
69        patterns
70    }
71
72    fn find_trait_method_calls(&self, trait_name: &str) -> Vec<UsageSite> {
73        self.trait_registry
74            .get_unresolved_trait_calls()
75            .iter()
76            .filter(|call| call.trait_name == trait_name || call.trait_name == "Unknown")
77            .map(|call| UsageSite {
78                file: call.caller.file.clone(),
79                line: call.line,
80                context: format!("Trait method call: {}", call.method_name),
81            })
82            .collect()
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_rust_trait_recognizer_creation() {
92        let registry = Arc::new(TraitRegistry::new());
93        let recognizer = RustTraitPatternRecognizer::new(registry);
94        let patterns = recognizer.detect_trait_observer_patterns();
95        assert_eq!(patterns.len(), 0);
96    }
97}