Skip to main content

memscope_rs/analysis/generic/
analyzer.rs

1use crate::analysis::generic::types::*;
2use crate::analysis::generic::utils::{extract_constraints, parse_generic_parameters};
3use crate::core::safe_operations::SafeLock;
4use std::collections::HashMap;
5use std::sync::{Arc, Mutex, OnceLock};
6use std::time::{SystemTime, UNIX_EPOCH};
7
8static GLOBAL_GENERIC_ANALYZER: OnceLock<Arc<GenericAnalyzer>> = OnceLock::new();
9
10pub fn get_global_generic_analyzer() -> Arc<GenericAnalyzer> {
11    GLOBAL_GENERIC_ANALYZER
12        .get_or_init(|| Arc::new(GenericAnalyzer::default()))
13        .clone()
14}
15
16pub struct GenericAnalyzer {
17    pub generic_instances: Mutex<HashMap<String, Vec<GenericInstance>>>,
18    pub constraint_violations: Mutex<Vec<ConstraintViolation>>,
19    pub instantiation_events: Mutex<Vec<InstantiationEvent>>,
20}
21
22impl Default for GenericAnalyzer {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl GenericAnalyzer {
29    pub fn new() -> Self {
30        Self {
31            generic_instances: Mutex::new(HashMap::new()),
32            constraint_violations: Mutex::new(Vec::new()),
33            instantiation_events: Mutex::new(Vec::new()),
34        }
35    }
36
37    pub fn track_generic_instantiation(
38        &self,
39        base_type: &str,
40        type_params: Vec<String>,
41        ptr: usize,
42    ) {
43        self.track_generic_instantiation_with_name(base_type, base_type, type_params, ptr);
44    }
45
46    pub fn track_generic_instantiation_with_name(
47        &self,
48        name: &str,
49        base_type: &str,
50        type_params: Vec<String>,
51        ptr: usize,
52    ) {
53        let event = InstantiationEvent {
54            base_type: base_type.to_string(),
55            type_parameters: type_params.clone(),
56            ptr,
57            timestamp: current_timestamp(),
58            thread_id: format!("{:?}", std::thread::current().id()),
59        };
60
61        if let Ok(mut events) = self.instantiation_events.lock() {
62            events.push(event);
63        }
64
65        let instance = GenericInstance {
66            name: name.to_string(),
67            base_type: base_type.to_string(),
68            underlying_type: base_type.to_string(),
69            type_parameters: type_params.clone(),
70            ptr,
71            size: 0,
72            constraints: extract_constraints(base_type),
73            is_type_alias: name != base_type,
74        };
75
76        if let Ok(mut instances) = self.generic_instances.lock() {
77            instances
78                .entry(name.to_string())
79                .or_default()
80                .push(instance);
81        }
82    }
83
84    pub fn track_type_alias_instantiation(
85        &self,
86        alias_name: &str,
87        underlying_type: &str,
88        type_params: Vec<String>,
89        ptr: usize,
90    ) {
91        let (base_type, resolved_params) = parse_generic_parameters(underlying_type);
92
93        let event = InstantiationEvent {
94            base_type: base_type.clone(),
95            type_parameters: if resolved_params.is_empty() {
96                type_params.clone()
97            } else {
98                resolved_params.clone()
99            },
100            ptr,
101            timestamp: current_timestamp(),
102            thread_id: format!("{:?}", std::thread::current().id()),
103        };
104
105        if let Ok(mut events) = self.instantiation_events.lock() {
106            events.push(event);
107        }
108
109        let instance = GenericInstance {
110            name: alias_name.to_string(),
111            base_type: base_type.clone(),
112            underlying_type: underlying_type.to_string(),
113            type_parameters: if resolved_params.is_empty() {
114                type_params
115            } else {
116                resolved_params
117            },
118            ptr,
119            size: 0,
120            constraints: extract_constraints(underlying_type),
121            is_type_alias: true,
122        };
123
124        if let Ok(mut instances) = self.generic_instances.lock() {
125            instances
126                .entry(alias_name.to_string())
127                .or_default()
128                .push(instance);
129        }
130    }
131
132    pub fn analyze_constraints(&self, type_name: &str) -> Vec<GenericConstraint> {
133        extract_constraints(type_name)
134    }
135
136    pub fn check_constraint_violations(
137        &self,
138        type_name: &str,
139        actual_params: &[String],
140    ) -> Vec<ConstraintViolation> {
141        let constraints = self.analyze_constraints(type_name);
142        let mut violations = Vec::new();
143
144        for constraint in constraints {
145            if !self.validate_constraint(&constraint, actual_params) {
146                violations.push(ConstraintViolation {
147                    constraint: constraint.clone(),
148                    actual_type: actual_params.join(", "),
149                    violation_type: ViolationType::ConstraintNotSatisfied,
150                    timestamp: current_timestamp(),
151                });
152            }
153        }
154
155        violations
156    }
157
158    pub fn get_generic_statistics(&self) -> GenericStatistics {
159        let instances = self
160            .generic_instances
161            .safe_lock()
162            .expect("Failed to acquire lock on generic_instances");
163        let events = self
164            .instantiation_events
165            .safe_lock()
166            .expect("Failed to acquire lock on instantiation_events");
167        let violations = self
168            .constraint_violations
169            .safe_lock()
170            .expect("Failed to acquire lock on constraint_violations");
171        let total_instances: usize = instances.values().map(|v| v.len()).sum();
172        let unique_base_types = instances.len();
173        let total_instantiations = events.len();
174        let constraint_violations = violations.len();
175
176        let mut type_usage: HashMap<String, usize> = HashMap::new();
177        let mut alias_count = 0;
178
179        for (_name, instance_list) in instances.iter() {
180            for instance in instance_list {
181                if instance.is_type_alias {
182                    alias_count += 1;
183                    *type_usage
184                        .entry(instance.underlying_type.clone())
185                        .or_insert(0) += 1;
186                } else {
187                    *type_usage.entry(instance.name.clone()).or_insert(0) += 1;
188                }
189            }
190        }
191
192        let most_used_types: Vec<(String, usize)> = {
193            let mut sorted: Vec<_> = type_usage.into_iter().collect();
194            sorted.sort_by(|a, b| b.1.cmp(&a.1));
195            sorted.into_iter().take(10).collect()
196        };
197
198        GenericStatistics {
199            total_instances,
200            unique_base_types,
201            total_instantiations,
202            constraint_violations,
203            most_used_types,
204            type_aliases_count: alias_count,
205        }
206    }
207
208    pub fn get_type_aliases(&self) -> Vec<TypeAliasInfo> {
209        let instances = self
210            .generic_instances
211            .safe_lock()
212            .expect("Failed to acquire lock on generic_instances");
213        let mut alias_map: HashMap<String, TypeAliasInfo> = HashMap::new();
214
215        for (_name, instance_list) in instances.iter() {
216            for instance in instance_list {
217                if instance.is_type_alias {
218                    let alias_name = instance.name.clone();
219
220                    if let Some(existing) = alias_map.get_mut(&alias_name) {
221                        existing.usage_count += 1;
222                    } else {
223                        alias_map.insert(
224                            alias_name.clone(),
225                            TypeAliasInfo {
226                                alias_name,
227                                underlying_type: instance.underlying_type.clone(),
228                                base_type: instance.base_type.clone(),
229                                type_parameters: instance.type_parameters.clone(),
230                                usage_count: 1,
231                            },
232                        );
233                    }
234                }
235            }
236        }
237
238        alias_map.into_values().collect()
239    }
240
241    pub fn resolve_type_alias(&self, alias_name: &str) -> Option<String> {
242        let instances = self
243            .generic_instances
244            .safe_lock()
245            .expect("Failed to acquire lock on generic_instances");
246
247        if let Some(instance_list) = instances.get(alias_name) {
248            for instance in instance_list {
249                if instance.is_type_alias {
250                    return Some(instance.underlying_type.clone());
251                }
252            }
253        }
254        None
255    }
256
257    fn validate_constraint(
258        &self,
259        constraint: &GenericConstraint,
260        actual_params: &[String],
261    ) -> bool {
262        match &constraint.constraint_type {
263            ConstraintType::Trait(trait_name) => {
264                self.type_implements_trait(actual_params, trait_name)
265            }
266            ConstraintType::Lifetime => true,
267            ConstraintType::Sized => !actual_params
268                .iter()
269                .any(|t| t.contains("dyn ") || t.contains("?Sized")),
270            ConstraintType::Send => self.type_is_send(actual_params),
271            ConstraintType::Sync => self.type_is_sync(actual_params),
272        }
273    }
274
275    fn type_implements_trait(&self, types: &[String], trait_name: &str) -> bool {
276        match trait_name {
277            "Clone" => types.iter().all(|t| self.is_cloneable_type(t)),
278            "Debug" => types.iter().all(|t| self.is_debug_type(t)),
279            "Default" => types.iter().all(|t| self.is_default_type(t)),
280            "PartialEq" => types.iter().all(|t| self.is_partial_eq_type(t)),
281            _ => true,
282        }
283    }
284
285    fn type_is_send(&self, types: &[String]) -> bool {
286        !types
287            .iter()
288            .any(|t| t.contains("Rc<") || t.contains("RefCell<"))
289    }
290
291    fn type_is_sync(&self, types: &[String]) -> bool {
292        !types
293            .iter()
294            .any(|t| t.contains("Cell<") || t.contains("RefCell<"))
295    }
296
297    fn is_cloneable_type(&self, type_name: &str) -> bool {
298        !type_name.contains("Mutex<") && !type_name.contains("File")
299    }
300
301    fn is_debug_type(&self, type_name: &str) -> bool {
302        !type_name.contains("fn(")
303    }
304
305    fn is_default_type(&self, type_name: &str) -> bool {
306        type_name.contains("Vec<") || type_name.contains("HashMap<") || type_name.contains("String")
307    }
308
309    fn is_partial_eq_type(&self, type_name: &str) -> bool {
310        !type_name.contains("fn(") && !type_name.contains("Mutex<")
311    }
312}
313
314fn current_timestamp() -> u64 {
315    SystemTime::now()
316        .duration_since(UNIX_EPOCH)
317        .unwrap_or_default()
318        .as_secs()
319}