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}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324
325 #[test]
328 fn test_generic_analyzer_creation() {
329 let analyzer = GenericAnalyzer::new();
330
331 let instances = analyzer.generic_instances.lock().unwrap();
332 let violations = analyzer.constraint_violations.lock().unwrap();
333 let events = analyzer.instantiation_events.lock().unwrap();
334
335 assert!(
336 instances.is_empty(),
337 "New analyzer should have no instances"
338 );
339 assert!(
340 violations.is_empty(),
341 "New analyzer should have no violations"
342 );
343 assert!(events.is_empty(), "New analyzer should have no events");
344 }
345
346 #[test]
349 fn test_generic_analyzer_default() {
350 let analyzer = GenericAnalyzer::default();
351
352 let instances = analyzer.generic_instances.lock().unwrap();
353 assert!(
354 instances.is_empty(),
355 "Default analyzer should have no instances"
356 );
357 }
358
359 #[test]
362 fn test_track_generic_instantiation() {
363 let analyzer = GenericAnalyzer::new();
364
365 analyzer.track_generic_instantiation("Vec", vec!["i32".to_string()], 0x1000);
366
367 let instances = analyzer.generic_instances.lock().unwrap();
368 assert!(instances.contains_key("Vec"), "Should contain Vec instance");
369 assert_eq!(
370 instances.get("Vec").unwrap().len(),
371 1,
372 "Should have one Vec instance"
373 );
374
375 let events = analyzer.instantiation_events.lock().unwrap();
376 assert_eq!(events.len(), 1, "Should have one event");
377 }
378
379 #[test]
382 fn test_track_generic_instantiation_with_name() {
383 let analyzer = GenericAnalyzer::new();
384
385 analyzer.track_generic_instantiation_with_name(
386 "MyVec",
387 "Vec",
388 vec!["String".to_string()],
389 0x2000,
390 );
391
392 let instances = analyzer.generic_instances.lock().unwrap();
393 assert!(
394 instances.contains_key("MyVec"),
395 "Should contain MyVec instance"
396 );
397
398 let instance = &instances.get("MyVec").unwrap()[0];
399 assert_eq!(instance.name, "MyVec", "Name should be MyVec");
400 assert_eq!(instance.base_type, "Vec", "Base type should be Vec");
401 assert!(instance.is_type_alias, "Should be marked as type alias");
402 }
403
404 #[test]
407 fn test_track_type_alias_instantiation() {
408 let analyzer = GenericAnalyzer::new();
409
410 analyzer.track_type_alias_instantiation("StringList", "Vec<String>", vec![], 0x3000);
411
412 let instances = analyzer.generic_instances.lock().unwrap();
413 assert!(
414 instances.contains_key("StringList"),
415 "Should contain StringList instance"
416 );
417
418 let instance = &instances.get("StringList").unwrap()[0];
419 assert_eq!(instance.name, "StringList", "Name should be StringList");
420 assert_eq!(
421 instance.underlying_type, "Vec<String>",
422 "Underlying type should be Vec<String>"
423 );
424 assert!(instance.is_type_alias, "Should be marked as type alias");
425 }
426
427 #[test]
430 fn test_analyze_constraints() {
431 let analyzer = GenericAnalyzer::new();
432
433 let constraints = analyzer.analyze_constraints("Vec<T: Clone>");
434
435 assert!(
436 !constraints.is_empty(),
437 "Should have constraints for Vec<T: Clone>"
438 );
439 }
440
441 #[test]
444 fn test_check_constraint_violations_valid() {
445 let analyzer = GenericAnalyzer::new();
446
447 let violations = analyzer.check_constraint_violations("Vec<T>", &["i32".to_string()]);
448
449 assert!(
450 violations.is_empty(),
451 "Should have no violations for valid params"
452 );
453 }
454
455 #[test]
458 fn test_get_generic_statistics_empty() {
459 let analyzer = GenericAnalyzer::new();
460
461 let stats = analyzer.get_generic_statistics();
462
463 assert_eq!(stats.total_instances, 0, "Should have 0 total instances");
464 assert_eq!(
465 stats.unique_base_types, 0,
466 "Should have 0 unique base types"
467 );
468 assert_eq!(
469 stats.total_instantiations, 0,
470 "Should have 0 instantiations"
471 );
472 assert_eq!(stats.constraint_violations, 0, "Should have 0 violations");
473 }
474
475 #[test]
478 fn test_get_generic_statistics_with_data() {
479 let analyzer = GenericAnalyzer::new();
480
481 analyzer.track_generic_instantiation("Vec", vec!["i32".to_string()], 0x1000);
482 analyzer.track_generic_instantiation("Vec", vec!["String".to_string()], 0x2000);
483 analyzer.track_generic_instantiation(
484 "HashMap",
485 vec!["String".to_string(), "i32".to_string()],
486 0x3000,
487 );
488
489 let stats = analyzer.get_generic_statistics();
490
491 assert_eq!(stats.total_instances, 3, "Should have 3 total instances");
492 assert_eq!(
493 stats.unique_base_types, 2,
494 "Should have 2 unique base types (Vec, HashMap)"
495 );
496 assert_eq!(
497 stats.total_instantiations, 3,
498 "Should have 3 instantiations"
499 );
500 }
501
502 #[test]
505 fn test_get_type_aliases_empty() {
506 let analyzer = GenericAnalyzer::new();
507
508 analyzer.track_generic_instantiation("Vec", vec!["i32".to_string()], 0x1000);
509
510 let aliases = analyzer.get_type_aliases();
511
512 assert!(aliases.is_empty(), "Should have no type aliases");
513 }
514
515 #[test]
518 fn test_get_type_aliases_with_data() {
519 let analyzer = GenericAnalyzer::new();
520
521 analyzer.track_type_alias_instantiation("StringList", "Vec<String>", vec![], 0x1000);
522 analyzer.track_type_alias_instantiation("StringList", "Vec<String>", vec![], 0x2000);
523
524 let aliases = analyzer.get_type_aliases();
525
526 assert_eq!(aliases.len(), 1, "Should have 1 type alias");
527 assert_eq!(
528 aliases[0].alias_name, "StringList",
529 "Alias name should be StringList"
530 );
531 assert_eq!(aliases[0].usage_count, 2, "Usage count should be 2");
532 }
533
534 #[test]
537 fn test_resolve_type_alias() {
538 let analyzer = GenericAnalyzer::new();
539
540 analyzer.track_type_alias_instantiation("IntList", "Vec<i32>", vec![], 0x1000);
541
542 let resolved = analyzer.resolve_type_alias("IntList");
543
544 assert!(resolved.is_some(), "Should resolve IntList");
545 assert_eq!(resolved.unwrap(), "Vec<i32>", "Should resolve to Vec<i32>");
546 }
547
548 #[test]
551 fn test_resolve_type_alias_nonexistent() {
552 let analyzer = GenericAnalyzer::new();
553
554 let resolved = analyzer.resolve_type_alias("NonExistent");
555
556 assert!(
557 resolved.is_none(),
558 "Should return None for non-existent alias"
559 );
560 }
561
562 #[test]
565 fn test_type_implements_trait_clone() {
566 let analyzer = GenericAnalyzer::new();
567
568 assert!(
569 analyzer.type_implements_trait(&["i32".to_string()], "Clone"),
570 "i32 should implement Clone"
571 );
572 assert!(
573 analyzer.type_implements_trait(&["String".to_string()], "Clone"),
574 "String should implement Clone"
575 );
576 assert!(
577 !analyzer.type_implements_trait(&["Mutex<i32>".to_string()], "Clone"),
578 "Mutex should not implement Clone"
579 );
580 }
581
582 #[test]
585 fn test_type_implements_trait_debug() {
586 let analyzer = GenericAnalyzer::new();
587
588 assert!(
589 analyzer.type_implements_trait(&["i32".to_string()], "Debug"),
590 "i32 should implement Debug"
591 );
592 assert!(
593 !analyzer.type_implements_trait(&["fn()".to_string()], "Debug"),
594 "fn() should not implement Debug"
595 );
596 }
597
598 #[test]
601 fn test_type_implements_trait_default() {
602 let analyzer = GenericAnalyzer::new();
603
604 assert!(
605 analyzer.type_implements_trait(&["Vec<i32>".to_string()], "Default"),
606 "Vec should implement Default"
607 );
608 assert!(
609 analyzer.type_implements_trait(&["String".to_string()], "Default"),
610 "String should implement Default"
611 );
612 assert!(
613 !analyzer.type_implements_trait(&["i32".to_string()], "Default"),
614 "i32 should not implement Default"
615 );
616 }
617
618 #[test]
621 fn test_type_implements_trait_partial_eq() {
622 let analyzer = GenericAnalyzer::new();
623
624 assert!(
625 analyzer.type_implements_trait(&["i32".to_string()], "PartialEq"),
626 "i32 should implement PartialEq"
627 );
628 assert!(
629 !analyzer.type_implements_trait(&["fn()".to_string()], "PartialEq"),
630 "fn() should not implement PartialEq"
631 );
632 }
633
634 #[test]
637 fn test_type_is_send() {
638 let analyzer = GenericAnalyzer::new();
639
640 assert!(
641 analyzer.type_is_send(&["i32".to_string()]),
642 "i32 should be Send"
643 );
644 assert!(
645 analyzer.type_is_send(&["Arc<i32>".to_string()]),
646 "Arc should be Send"
647 );
648 assert!(
649 !analyzer.type_is_send(&["Rc<i32>".to_string()]),
650 "Rc should not be Send"
651 );
652 assert!(
653 !analyzer.type_is_send(&["RefCell<i32>".to_string()]),
654 "RefCell should not be Send"
655 );
656 }
657
658 #[test]
661 fn test_type_is_sync() {
662 let analyzer = GenericAnalyzer::new();
663
664 assert!(
665 analyzer.type_is_sync(&["i32".to_string()]),
666 "i32 should be Sync"
667 );
668 assert!(
669 analyzer.type_is_sync(&["Arc<i32>".to_string()]),
670 "Arc should be Sync"
671 );
672 assert!(
673 !analyzer.type_is_sync(&["Cell<i32>".to_string()]),
674 "Cell should not be Sync"
675 );
676 assert!(
677 !analyzer.type_is_sync(&["RefCell<i32>".to_string()]),
678 "RefCell should not be Sync"
679 );
680 }
681
682 #[test]
685 fn test_is_cloneable_type() {
686 let analyzer = GenericAnalyzer::new();
687
688 assert!(analyzer.is_cloneable_type("i32"), "i32 should be cloneable");
689 assert!(
690 analyzer.is_cloneable_type("String"),
691 "String should be cloneable"
692 );
693 assert!(
694 !analyzer.is_cloneable_type("Mutex<i32>"),
695 "Mutex should not be cloneable"
696 );
697 assert!(
698 !analyzer.is_cloneable_type("File"),
699 "File should not be cloneable"
700 );
701 }
702
703 #[test]
706 fn test_is_debug_type() {
707 let analyzer = GenericAnalyzer::new();
708
709 assert!(analyzer.is_debug_type("i32"), "i32 should be Debug");
710 assert!(analyzer.is_debug_type("String"), "String should be Debug");
711 assert!(
712 !analyzer.is_debug_type("fn() -> i32"),
713 "fn() should not be Debug"
714 );
715 }
716
717 #[test]
720 fn test_is_default_type() {
721 let analyzer = GenericAnalyzer::new();
722
723 assert!(
724 analyzer.is_default_type("Vec<i32>"),
725 "Vec should be Default"
726 );
727 assert!(
728 analyzer.is_default_type("HashMap<String, i32>"),
729 "HashMap should be Default"
730 );
731 assert!(
732 analyzer.is_default_type("String"),
733 "String should be Default"
734 );
735 assert!(
736 !analyzer.is_default_type("i32"),
737 "i32 should not be Default"
738 );
739 }
740
741 #[test]
744 fn test_is_partial_eq_type() {
745 let analyzer = GenericAnalyzer::new();
746
747 assert!(
748 analyzer.is_partial_eq_type("i32"),
749 "i32 should be PartialEq"
750 );
751 assert!(
752 analyzer.is_partial_eq_type("String"),
753 "String should be PartialEq"
754 );
755 assert!(
756 !analyzer.is_partial_eq_type("fn()"),
757 "fn() should not be PartialEq"
758 );
759 assert!(
760 !analyzer.is_partial_eq_type("Mutex<i32>"),
761 "Mutex should not be PartialEq"
762 );
763 }
764
765 #[test]
768 fn test_global_generic_analyzer_singleton() {
769 let analyzer1 = get_global_generic_analyzer();
770 let analyzer2 = get_global_generic_analyzer();
771
772 assert!(
773 Arc::ptr_eq(&analyzer1, &analyzer2),
774 "Should return same instance"
775 );
776 }
777
778 #[test]
781 fn test_current_timestamp() {
782 let ts = current_timestamp();
783 assert!(ts > 0, "Timestamp should be positive");
784 }
785
786 #[test]
789 fn test_multiple_instantiations_same_type() {
790 let analyzer = GenericAnalyzer::new();
791
792 for i in 0..5 {
793 analyzer.track_generic_instantiation("Vec", vec!["i32".to_string()], 0x1000 + i);
794 }
795
796 let instances = analyzer.generic_instances.lock().unwrap();
797 assert_eq!(
798 instances.get("Vec").unwrap().len(),
799 5,
800 "Should have 5 Vec instances"
801 );
802
803 let events = analyzer.instantiation_events.lock().unwrap();
804 assert_eq!(events.len(), 5, "Should have 5 events");
805 }
806
807 #[test]
810 fn test_validate_constraint_sized() {
811 let analyzer = GenericAnalyzer::new();
812
813 let sized_constraint = GenericConstraint {
814 constraint_type: ConstraintType::Sized,
815 parameter_name: "T".to_string(),
816 description: String::new(),
817 };
818
819 assert!(
820 analyzer.validate_constraint(&sized_constraint, &["i32".to_string()]),
821 "i32 should be Sized"
822 );
823 assert!(
824 !analyzer.validate_constraint(&sized_constraint, &["dyn Any".to_string()]),
825 "dyn Any should not be Sized"
826 );
827 assert!(
828 !analyzer.validate_constraint(&sized_constraint, &["?Sized".to_string()]),
829 "?Sized should not satisfy Sized constraint"
830 );
831 }
832
833 #[test]
836 fn test_validate_constraint_lifetime() {
837 let analyzer = GenericAnalyzer::new();
838
839 let lifetime_constraint = GenericConstraint {
840 constraint_type: ConstraintType::Lifetime,
841 parameter_name: "'a".to_string(),
842 description: String::new(),
843 };
844
845 assert!(
846 analyzer.validate_constraint(&lifetime_constraint, &["i32".to_string()]),
847 "Lifetime constraint should always be valid"
848 );
849 }
850
851 #[test]
854 fn test_validate_constraint_send() {
855 let analyzer = GenericAnalyzer::new();
856
857 let send_constraint = GenericConstraint {
858 constraint_type: ConstraintType::Send,
859 parameter_name: "T".to_string(),
860 description: String::new(),
861 };
862
863 assert!(
864 analyzer.validate_constraint(&send_constraint, &["i32".to_string()]),
865 "i32 should be Send"
866 );
867 assert!(
868 !analyzer.validate_constraint(&send_constraint, &["Rc<i32>".to_string()]),
869 "Rc should not be Send"
870 );
871 }
872
873 #[test]
876 fn test_validate_constraint_sync() {
877 let analyzer = GenericAnalyzer::new();
878
879 let sync_constraint = GenericConstraint {
880 constraint_type: ConstraintType::Sync,
881 parameter_name: "T".to_string(),
882 description: String::new(),
883 };
884
885 assert!(
886 analyzer.validate_constraint(&sync_constraint, &["i32".to_string()]),
887 "i32 should be Sync"
888 );
889 assert!(
890 !analyzer.validate_constraint(&sync_constraint, &["Cell<i32>".to_string()]),
891 "Cell should not be Sync"
892 );
893 }
894
895 #[test]
898 fn test_type_implements_trait_unknown() {
899 let analyzer = GenericAnalyzer::new();
900
901 assert!(
902 analyzer.type_implements_trait(&["i32".to_string()], "UnknownTrait"),
903 "Unknown traits should return true by default"
904 );
905 }
906
907 #[test]
910 fn test_concurrent_access() {
911 use std::sync::Arc;
912 use std::thread;
913
914 let analyzer = Arc::new(GenericAnalyzer::new());
915 let mut handles = vec![];
916
917 for i in 0..5 {
918 let analyzer_clone = analyzer.clone();
919 let handle = thread::spawn(move || {
920 analyzer_clone.track_generic_instantiation(
921 "Vec",
922 vec![format!("Type{}", i)],
923 0x1000 + i,
924 );
925 });
926 handles.push(handle);
927 }
928
929 for handle in handles {
930 handle.join().unwrap();
931 }
932
933 let instances = analyzer.generic_instances.lock().unwrap();
934 assert_eq!(
935 instances.get("Vec").unwrap().len(),
936 5,
937 "Should have 5 instances from 5 threads"
938 );
939 }
940
941 #[test]
944 fn test_statistics_with_type_aliases() {
945 let analyzer = GenericAnalyzer::new();
946
947 analyzer.track_generic_instantiation("Vec", vec!["i32".to_string()], 0x1000);
948 analyzer.track_type_alias_instantiation("IntVec", "Vec<i32>", vec![], 0x2000);
949 analyzer.track_type_alias_instantiation("IntVec", "Vec<i32>", vec![], 0x3000);
950
951 let stats = analyzer.get_generic_statistics();
952
953 assert_eq!(stats.total_instances, 3, "Should have 3 total instances");
954 assert_eq!(
955 stats.type_aliases_count, 2,
956 "Should have 2 type alias instances"
957 );
958 }
959}