memscope_rs/analysis/generic/
analyzer.rs1use 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}