1pub mod node_id;
16
17pub mod detectors;
19
20pub mod circular_reference;
21pub mod heap_scanner;
22pub mod relation_inference;
23pub mod unsafe_ffi_tracker;
24pub mod unsafe_inference;
25pub mod variable_relationships;
26
27pub mod closure;
29pub mod generic;
30pub mod safety;
31pub mod security;
32pub mod unknown;
33
34pub mod async_analysis;
36pub mod borrow_analysis;
37
38pub mod ffi_function_resolver;
39pub mod lifecycle;
40pub mod lifecycle_analysis;
41pub mod memory_passport_tracker;
42pub mod top_n;
43
44pub mod classification;
46pub mod estimation;
47pub mod metrics;
48pub mod quality;
49
50pub use circular_reference::{CircularReference, CircularReferenceAnalysis, CircularReferenceNode};
52pub use unsafe_ffi_tracker::UnsafeFFITracker;
53pub use variable_relationships::{
54 build_variable_relationship_graph, GraphStatistics, RelationshipType as VarRelationshipType,
55 SmartPointerInfo as VarSmartPointerInfo, VariableCategory, VariableCluster, VariableNode,
56 VariableRelationship, VariableRelationshipGraph,
57};
58
59pub use node_id::{is_virtual_pointer, NodeId, VIRTUAL_PTR_BASE};
61pub mod relationship_cycle_detector;
62pub use relationship_cycle_detector::{detect_cycles_in_relationships, CycleDetectionResult};
63
64pub mod ownership_graph;
66pub use ownership_graph::{Edge, EdgeKind, Node, OwnershipGraph, OwnershipOp};
67
68pub mod ownership_analyzer;
70
71pub use detectors::{
73 Detector, LeakDetector, LeakDetectorConfig, LifecycleDetector, LifecycleDetectorConfig,
74 OverflowDetector, OverflowDetectorConfig, SafetyDetector, SafetyDetectorConfig, UafDetector,
75 UafDetectorConfig,
76};
77
78pub use async_analysis::{
79 get_global_async_analyzer, AsyncAnalyzer, AsyncPatternAnalysis, AsyncStatistics,
80};
81pub use borrow_analysis::{get_global_borrow_analyzer, BorrowAnalyzer, BorrowPatternAnalysis};
82pub use closure::{get_global_closure_analyzer, ClosureAnalysisReport, ClosureAnalyzer};
83pub use ffi_function_resolver::{
84 get_global_ffi_resolver, initialize_global_ffi_resolver, FfiFunctionCategory,
85 FfiFunctionResolver, FfiRiskLevel, ResolutionStats, ResolvedFfiFunction, ResolverConfig,
86};
87pub use generic::{get_global_generic_analyzer, GenericAnalyzer, GenericStatistics};
88pub use lifecycle::{
89 lifecycle_summary::{
90 AllocationLifecycleSummary, ExportMetadata, LifecycleEvent, LifecycleEventSummary,
91 LifecycleExportData, LifecyclePattern, LifecycleSummaryGenerator, SummaryConfig,
92 VariableGroup,
93 },
94 ownership_history::{
95 BorrowInfo, CloneInfo, OwnershipEvent, OwnershipEventType, OwnershipHistoryRecorder,
96 OwnershipStatistics, OwnershipSummary, RefCountInfo,
97 },
98};
99pub use lifecycle_analysis::{
100 get_global_lifecycle_analyzer, LifecycleAnalysisReport, LifecycleAnalyzer,
101};
102pub use memory_passport_tracker::{
103 get_global_passport_tracker, initialize_global_passport_tracker, LeakDetail,
104 LeakDetectionResult, MemoryPassport, MemoryPassportTracker, PassportEvent, PassportEventType,
105 PassportStatus, PassportTrackerConfig, PassportTrackerStats,
106};
107pub use safety::{
108 DynamicViolation, RiskAssessment, RiskFactor, RiskFactorType, SafetyAnalysisConfig,
109 SafetyAnalysisStats, SafetyAnalyzer, UnsafeReport, UnsafeSource,
110};
111pub use unsafe_ffi_tracker::ComprehensiveSafetyReport;
112pub use unsafe_inference::{
113 count_valid_pointers, get_valid_regions, is_valid_ptr, is_valid_ptr_static, InferenceMethod,
114 InferenceRecord, MemoryRegion, MemoryView, TypeGuess, TypeKind, UnsafeInferenceEngine,
115 ValidRegions,
116};
117
118pub use heap_scanner::{HeapScanner, ScanResult};
120
121pub use relation_inference::{
123 detect_clones, detect_owner, detect_slice, CloneConfig, GraphBuilderConfig, RangeMap, Relation,
124 RelationEdge, RelationGraph, RelationGraphBuilder,
125};
126
127pub use classification::{
129 pattern_matcher::PatternMatcher,
130 rule_engine::{Rule as ClassificationRule, RuleEngine},
131 type_classifier::{TypeCategory, TypeClassifier},
132};
133pub use estimation::{
134 size_estimator::SizeEstimator, type_classifier::TypeClassifier as EstimationTypeClassifier,
135};
136pub use metrics::{
137 analyzer::{Benchmark, PerformanceAnalyzer, PerformanceReport},
138 collector::{Metric, MetricType, MetricValue, MetricsCollector},
139 reporter::{AlertThreshold, MetricsReporter, ReportFormat},
140};
141pub use quality::{
142 analyzer::{AnalysisReport, CodeAnalyzer, QualityMetric},
143 checker::{MemoryLeakChecker, PerformanceChecker, SafetyChecker},
144 validator::{QualityValidator, ValidationResult, ValidationRule},
145};
146
147use crate::capture::types::stats::FragmentationAnalysis;
148use crate::capture::types::*;
149use std::sync::Arc;
150
151pub struct AnalysisManager {
153 }
155
156impl AnalysisManager {
157 pub fn new() -> Self {
159 Self {}
160 }
161
162 pub fn analyze_fragmentation(&self, allocations: &[AllocationInfo]) -> FragmentationAnalysis {
164 if allocations.is_empty() {
165 return FragmentationAnalysis::default();
166 }
167
168 let active_allocations: Vec<_> = allocations
169 .iter()
170 .filter(|a| a.timestamp_dealloc.is_none())
171 .collect();
172
173 if active_allocations.is_empty() {
174 return FragmentationAnalysis::default();
175 }
176
177 let mut sorted_ptrs: Vec<usize> = active_allocations.iter().map(|a| a.ptr).collect();
178 sorted_ptrs.sort();
179
180 let mut gaps: Vec<usize> = Vec::new();
181 for i in 1..sorted_ptrs.len() {
182 let prev = sorted_ptrs[i - 1];
183 let curr = sorted_ptrs[i];
184 if curr > prev {
185 let prev_alloc = active_allocations
186 .iter()
187 .find(|a| a.ptr == prev)
188 .map(|a| a.size)
189 .unwrap_or(0);
190 let gap = curr.saturating_sub(prev + prev_alloc);
191 if gap > 0 {
192 gaps.push(gap);
193 }
194 }
195 }
196
197 let total_memory: usize = active_allocations.iter().map(|a| a.size).sum();
198 let total_gap: usize = gaps.iter().sum();
199
200 let fragmentation_ratio = if total_memory > 0 {
201 total_gap as f64 / (total_memory + total_gap) as f64
202 } else {
203 0.0
204 };
205
206 let largest_free_block = gaps.iter().max().copied().unwrap_or(0);
207 let smallest_free_block = gaps.iter().min().copied().unwrap_or(0);
208 let free_block_count = gaps.len();
209 let total_free_memory = total_gap;
210
211 let external_fragmentation = if !gaps.is_empty() {
212 let avg_gap = total_gap as f64 / gaps.len() as f64;
213 let max_gap = largest_free_block as f64;
214 if max_gap > 0.0 {
215 1.0 - (avg_gap / max_gap)
216 } else {
217 0.0
218 }
219 } else {
220 0.0
221 };
222
223 let total_requested: usize = active_allocations.iter().map(|a| a.size).sum();
224 let total_allocated = total_requested + total_gap;
225 let internal_fragmentation = if total_allocated > 0 {
226 (total_gap as f64 / total_allocated as f64) * 100.0
227 } else {
228 0.0
229 };
230
231 FragmentationAnalysis {
232 fragmentation_ratio,
233 largest_free_block,
234 smallest_free_block,
235 free_block_count,
236 total_free_memory,
237 external_fragmentation,
238 internal_fragmentation,
239 }
240 }
241
242 pub fn analyze_system_libraries(&self, allocations: &[AllocationInfo]) -> SystemLibraryStats {
244 let mut stats = SystemLibraryStats::default();
245
246 for alloc in allocations {
247 let type_name = alloc.type_name.as_deref().unwrap_or("");
248 let stack = alloc.stack_trace.as_deref().unwrap_or(&[]);
249
250 if type_name.contains("Vec<")
251 || type_name.contains("HashMap")
252 || type_name.contains("HashSet")
253 || type_name.contains("BTreeMap")
254 || type_name.contains("BTreeSet")
255 {
256 stats.std_collections.allocation_count += 1;
257 stats.std_collections.total_bytes += alloc.size;
258 }
259
260 if type_name.contains("Future")
261 || type_name.contains("async")
262 || type_name.contains("tokio")
263 || type_name.contains("async_std")
264 {
265 stats.async_runtime.allocation_count += 1;
266 stats.async_runtime.total_bytes += alloc.size;
267 }
268
269 if type_name.contains("TcpStream")
270 || type_name.contains("UdpSocket")
271 || type_name.contains("Http")
272 || stack.iter().any(|s| s.contains("net::"))
273 {
274 stats.network_io.allocation_count += 1;
275 stats.network_io.total_bytes += alloc.size;
276 }
277
278 if type_name.contains("File")
279 || type_name.contains("Path")
280 || stack.iter().any(|s| s.contains("fs::"))
281 {
282 stats.file_system.allocation_count += 1;
283 stats.file_system.total_bytes += alloc.size;
284 }
285
286 if type_name.contains("serde")
287 || type_name.contains("Json")
288 || type_name.contains("Deserialize")
289 {
290 stats.serialization.allocation_count += 1;
291 stats.serialization.total_bytes += alloc.size;
292 }
293
294 if type_name.contains("Regex") || type_name.contains("regex") {
295 stats.regex_engine.allocation_count += 1;
296 stats.regex_engine.total_bytes += alloc.size;
297 }
298
299 if type_name.contains("Crypto")
300 || type_name.contains("Hash")
301 || type_name.contains("Signature")
302 {
303 stats.crypto_security.allocation_count += 1;
304 stats.crypto_security.total_bytes += alloc.size;
305 }
306
307 if type_name.contains("Database")
308 || type_name.contains("Connection")
309 || type_name.contains("Query")
310 {
311 stats.database.allocation_count += 1;
312 stats.database.total_bytes += alloc.size;
313 }
314
315 if type_name.contains("Window")
316 || type_name.contains("Canvas")
317 || type_name.contains("Surface")
318 || type_name.contains("wgpu")
319 {
320 stats.graphics_ui.allocation_count += 1;
321 stats.graphics_ui.total_bytes += alloc.size;
322 }
323
324 if type_name.contains("Request")
325 || type_name.contains("Response")
326 || type_name.contains("hyper")
327 || type_name.contains("reqwest")
328 {
329 stats.http_stack.allocation_count += 1;
330 stats.http_stack.total_bytes += alloc.size;
331 }
332 }
333
334 stats
335 }
336
337 pub fn analyze_concurrency_safety(
339 &self,
340 allocations: &[AllocationInfo],
341 ) -> ConcurrencyAnalysis {
342 let mut analysis = ConcurrencyAnalysis::default();
343
344 let mut thread_alloc_counts: std::collections::HashMap<u64, usize> =
348 std::collections::HashMap::new();
349
350 for alloc in allocations {
351 let type_name = alloc.type_name.as_deref().unwrap_or("");
352
353 if type_name.contains("Arc<")
354 || type_name.contains("Mutex<")
355 || type_name.contains("RwLock<")
356 {
357 analysis.thread_safety_allocations += 1;
358 analysis.shared_memory_bytes += alloc.size;
359 }
360
361 if type_name.contains("Arc<") {
362 analysis.arc_shared += 1;
363 }
364
365 if type_name.contains("mpsc")
366 || type_name.contains("channel")
367 || type_name.contains("Sender")
368 || type_name.contains("Receiver")
369 {
370 analysis.channel_buffers += 1;
371 }
372
373 if type_name.contains("thread_local") || type_name.contains("LocalKey") {
374 analysis.thread_local_storage += 1;
375 }
376
377 if type_name.contains("Atomic") {
378 analysis.atomic_operations += 1;
379 }
380
381 *thread_alloc_counts.entry(alloc.thread_id_u64).or_insert(0) += 1;
382 }
383
384 let max_thread_allocs = thread_alloc_counts.values().max().copied().unwrap_or(0);
385 let min_thread_allocs = thread_alloc_counts.values().min().copied().unwrap_or(0);
386 let thread_count = thread_alloc_counts.len();
387
388 if thread_count <= 1 {
389 analysis.lock_contention_risk = "None".to_string();
390 } else {
391 let imbalance_ratio = if min_thread_allocs > 0 {
392 max_thread_allocs as f64 / min_thread_allocs as f64
393 } else {
394 f64::MAX
395 };
396
397 if imbalance_ratio > 10.0 {
398 analysis.lock_contention_risk = "High".to_string();
399 } else if imbalance_ratio > 3.0 {
400 analysis.lock_contention_risk = "Medium".to_string();
401 } else {
402 analysis.lock_contention_risk = "Low".to_string();
403 }
404 }
405
406 analysis
407 }
408
409 pub fn get_unsafe_ffi_tracker(&self) -> Arc<crate::unsafe_ffi_tracker::UnsafeFFITracker> {
411 crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker()
413 }
414
415 pub fn get_unsafe_ffi_stats(&self) -> crate::unsafe_ffi_tracker::UnsafeFFIStats {
417 self.get_unsafe_ffi_tracker().get_stats()
419 }
420
421 pub fn analyze_circular_references(
423 &self,
424 allocations: &[AllocationInfo],
425 ) -> crate::circular_reference::CircularReferenceAnalysis {
426 crate::circular_reference::detect_circular_references(allocations)
427 }
428
429 pub fn analyze_borrow_patterns(
431 &self,
432 _allocations: &[AllocationInfo],
433 ) -> BorrowPatternAnalysis {
434 let analyzer = get_global_borrow_analyzer();
435 analyzer.analyze_borrow_patterns()
436 }
437
438 pub fn analyze_generic_types(&self, _allocations: &[AllocationInfo]) -> GenericStatistics {
440 let analyzer = GenericAnalyzer::new();
442 analyzer.get_generic_statistics()
443 }
444
445 pub fn analyze_async_patterns(&self, _allocations: &[AllocationInfo]) -> AsyncPatternAnalysis {
447 let analyzer = get_global_async_analyzer();
448 analyzer.analyze_async_patterns()
449 }
450
451 pub fn analyze_closure_patterns(
453 &self,
454 allocations: &[AllocationInfo],
455 ) -> ClosureAnalysisReport {
456 let analyzer = get_global_closure_analyzer();
457 analyzer.analyze_closure_patterns(allocations)
458 }
459
460 pub fn analyze_lifecycle_patterns(
462 &self,
463 _allocations: &[AllocationInfo],
464 ) -> LifecycleAnalysisReport {
465 let analyzer = get_global_lifecycle_analyzer();
466 analyzer.get_lifecycle_report()
467 }
468
469 pub fn analyze_memory_leaks(
471 &self,
472 allocations: &[AllocationInfo],
473 ) -> crate::analysis::detectors::DetectionResult {
474 let detector = crate::analysis::detectors::LeakDetector::new(
475 crate::analysis::detectors::LeakDetectorConfig::default(),
476 );
477 detector.detect(allocations)
478 }
479
480 pub fn analyze_use_after_free(
482 &self,
483 allocations: &[AllocationInfo],
484 ) -> crate::analysis::detectors::DetectionResult {
485 let detector = crate::analysis::detectors::UafDetector::new(
486 crate::analysis::detectors::UafDetectorConfig::default(),
487 );
488 detector.detect(allocations)
489 }
490
491 pub fn analyze_buffer_overflow(
493 &self,
494 allocations: &[AllocationInfo],
495 ) -> crate::analysis::detectors::DetectionResult {
496 let detector = crate::analysis::detectors::OverflowDetector::new(
497 crate::analysis::detectors::OverflowDetectorConfig::default(),
498 );
499 detector.detect(allocations)
500 }
501
502 pub fn analyze_safety_violations(
504 &self,
505 allocations: &[AllocationInfo],
506 ) -> crate::analysis::detectors::DetectionResult {
507 let detector = crate::analysis::detectors::SafetyDetector::new(
508 crate::analysis::detectors::SafetyDetectorConfig::default(),
509 );
510 detector.detect(allocations)
511 }
512
513 pub fn analyze_lifecycle_issues(
515 &self,
516 allocations: &[AllocationInfo],
517 ) -> crate::analysis::detectors::DetectionResult {
518 let detector = crate::analysis::detectors::LifecycleDetector::new(
519 crate::analysis::detectors::LifecycleDetectorConfig::default(),
520 );
521 detector.detect(allocations)
522 }
523
524 pub fn perform_comprehensive_analysis(
526 &self,
527 allocations: &[AllocationInfo],
528 stats: &MemoryStats,
529 ) -> ComprehensiveAnalysisReport {
530 let fragmentation = self.analyze_fragmentation(allocations);
531 let system_libs = self.analyze_system_libraries(allocations);
532 let concurrency = self.analyze_concurrency_safety(allocations);
533 let unsafe_stats = self.get_unsafe_ffi_stats();
534 let circular_refs = self.analyze_circular_references(allocations);
535
536 let borrow_analysis = self.analyze_borrow_patterns(allocations);
538 let generic_analysis = self.analyze_generic_types(allocations);
539 let async_analysis = self.analyze_async_patterns(allocations);
540 let closure_analysis = self.analyze_closure_patterns(allocations);
541 let lifecycle_analysis = self.analyze_lifecycle_patterns(allocations);
542
543 ComprehensiveAnalysisReport {
544 fragmentation_analysis: fragmentation,
545 system_library_stats: system_libs,
546 concurrency_analysis: concurrency,
547 unsafe_ffi_stats: unsafe_stats,
548 circular_reference_analysis: circular_refs,
549 borrow_analysis,
550 generic_analysis,
551 async_analysis,
552 closure_analysis,
553 lifecycle_analysis,
554 memory_stats: stats.clone(),
555 analysis_timestamp: std::time::SystemTime::now()
556 .duration_since(std::time::UNIX_EPOCH)
557 .unwrap_or_default()
558 .as_secs(),
559 }
560 }
561}
562
563impl Default for AnalysisManager {
564 fn default() -> Self {
565 Self::new()
566 }
567}
568
569#[derive(Debug, Clone)]
571pub struct ComprehensiveAnalysisReport {
572 pub fragmentation_analysis: FragmentationAnalysis,
574 pub system_library_stats: SystemLibraryStats,
576 pub concurrency_analysis: ConcurrencyAnalysis,
578 pub unsafe_ffi_stats: crate::unsafe_ffi_tracker::UnsafeFFIStats,
580 pub circular_reference_analysis: crate::circular_reference::CircularReferenceAnalysis,
582 pub borrow_analysis: BorrowPatternAnalysis,
584 pub generic_analysis: GenericStatistics,
586 pub async_analysis: AsyncPatternAnalysis,
588 pub closure_analysis: ClosureAnalysisReport,
590 pub lifecycle_analysis: LifecycleAnalysisReport,
592 pub memory_stats: MemoryStats,
594 pub analysis_timestamp: u64,
596}
597
598pub fn analyze_fragmentation(allocations: &[AllocationInfo]) -> FragmentationAnalysis {
603 let manager = AnalysisManager::new();
604 manager.analyze_fragmentation(allocations)
605}
606
607pub fn analyze_system_libraries(allocations: &[AllocationInfo]) -> SystemLibraryStats {
609 let manager = AnalysisManager::new();
610 manager.analyze_system_libraries(allocations)
611}
612
613pub fn analyze_concurrency_safety(allocations: &[AllocationInfo]) -> ConcurrencyAnalysis {
615 let manager = AnalysisManager::new();
616 manager.analyze_concurrency_safety(allocations)
617}
618
619pub fn get_global_unsafe_ffi_tracker() -> Arc<crate::unsafe_ffi_tracker::UnsafeFFITracker> {
621 crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker()
622}
623
624pub fn get_unsafe_ffi_stats() -> crate::unsafe_ffi_tracker::UnsafeFFIStats {
626 let manager = AnalysisManager::new();
627 manager.get_unsafe_ffi_stats()
628}
629
630pub fn perform_comprehensive_analysis(
632 allocations: &[AllocationInfo],
633 stats: &MemoryStats,
634) -> ComprehensiveAnalysisReport {
635 let manager = AnalysisManager::new();
636 manager.perform_comprehensive_analysis(allocations, stats)
637}
638
639#[cfg(test)]
643mod tests {
644 use super::*;
645 use crate::capture::types::AllocationInfo;
646
647 #[test]
648 fn test_analyze_fragmentation() {
649 let manager = AnalysisManager::new();
650 let allocations = vec![
655 AllocationInfo::new(0x1000, 1024),
656 AllocationInfo::new(0x2000, 512),
657 ];
658
659 let result = manager.analyze_fragmentation(&allocations);
660
661 assert!(
664 result.fragmentation_ratio > 0.5,
665 "fragmentation_ratio should be > 0.5, got {}",
666 result.fragmentation_ratio
667 );
668 assert_eq!(result.free_block_count, 1, "should have exactly 1 gap");
669 assert_eq!(
670 result.largest_free_block, 3072,
671 "largest gap should be 3072"
672 );
673 assert_eq!(
674 result.smallest_free_block, 3072,
675 "smallest gap should be 3072"
676 );
677 }
678
679 #[test]
680 fn test_analyze_fragmentation_no_gaps() {
681 let manager = AnalysisManager::new();
682 let allocations = vec![
684 AllocationInfo::new(0x1000, 256),
685 AllocationInfo::new(0x1100, 256),
686 ];
687
688 let result = manager.analyze_fragmentation(&allocations);
689 assert_eq!(
690 result.fragmentation_ratio, 0.0,
691 "no gaps means zero fragmentation"
692 );
693 assert_eq!(result.free_block_count, 0);
694 }
695
696 #[test]
697 fn test_analyze_system_libraries() {
698 let manager = AnalysisManager::new();
699
700 let mut alloc_vec = AllocationInfo::new(0x1000, 256);
702 alloc_vec.type_name = Some("Vec<String>".to_string());
703
704 let mut alloc_hashmap = AllocationInfo::new(0x2000, 512);
705 alloc_hashmap.type_name = Some("HashMap<K, V>".to_string());
706
707 let mut alloc_file = AllocationInfo::new(0x3000, 128);
708 alloc_file.type_name = Some("File".to_string());
709
710 let mut alloc_regex = AllocationInfo::new(0x4000, 64);
711 alloc_regex.type_name = Some("Regex".to_string());
712
713 let allocations = vec![alloc_vec, alloc_hashmap, alloc_file, alloc_regex];
714
715 let result = manager.analyze_system_libraries(&allocations);
716
717 assert_eq!(
718 result.std_collections.allocation_count, 2,
719 "Vec and HashMap"
720 );
721 assert_eq!(result.std_collections.total_bytes, 256 + 512);
722 assert_eq!(result.file_system.allocation_count, 1, "File");
723 assert_eq!(result.file_system.total_bytes, 128);
724 assert_eq!(result.regex_engine.allocation_count, 1, "Regex");
725 assert_eq!(result.regex_engine.total_bytes, 64);
726 assert_eq!(result.async_runtime.allocation_count, 0, "no async types");
727 }
728
729 #[test]
730 fn test_analyze_concurrency_safety() {
731 let manager = AnalysisManager::new();
732
733 let mut alloc_arc = AllocationInfo::new(0x1000, 64);
734 alloc_arc.type_name = Some("Arc<Mutex<i32>>".to_string());
735
736 let mut alloc_mutex = AllocationInfo::new(0x2000, 128);
737 alloc_mutex.type_name = Some("Mutex<String>".to_string());
738
739 let mut alloc_atomic = AllocationInfo::new(0x3000, 8);
740 alloc_atomic.type_name = Some("AtomicUsize".to_string());
741
742 let allocations = vec![alloc_arc, alloc_mutex, alloc_atomic];
743
744 let result = manager.analyze_concurrency_safety(&allocations);
745
746 assert_eq!(result.thread_safety_allocations, 2, "Arc and Mutex");
747 assert_eq!(result.arc_shared, 1, "Arc");
748 assert_eq!(result.atomic_operations, 1, "AtomicUsize");
749 assert_eq!(result.shared_memory_bytes, 64 + 128);
750 assert_eq!(result.lock_contention_risk, "None", "single thread");
751 }
752
753 #[test]
754 fn test_analyze_concurrency_safety_multi_thread() {
755 let manager = AnalysisManager::new();
756
757 let mut alloc_arc = AllocationInfo::new(0x1000, 64);
760 alloc_arc.type_name = Some("Arc<i32>".to_string());
761
762 let allocations = vec![alloc_arc];
763
764 let result = manager.analyze_concurrency_safety(&allocations);
765 assert_eq!(result.arc_shared, 1);
766 }
767
768 #[test]
769 fn test_get_unsafe_ffi_tracker() {
770 let manager = AnalysisManager::new();
771
772 let _tracker = manager.get_unsafe_ffi_tracker();
773
774 }
776
777 #[test]
778 fn test_get_unsafe_ffi_stats() {
779 let manager = AnalysisManager::new();
780
781 let stats = manager.get_unsafe_ffi_stats();
782
783 assert_eq!(stats.total_operations, 0);
785 assert_eq!(stats.ffi_calls, 0);
786 assert_eq!(stats.raw_pointer_operations, 0);
787 assert_eq!(stats.memory_violations, 0);
788 assert!(stats.operations.is_empty());
789 }
790
791 #[test]
792 fn test_analyze_circular_references() {
793 let manager = AnalysisManager::new();
794 let allocations = vec![
797 AllocationInfo::new(0x4000, 128),
798 AllocationInfo::new(0x5000, 256),
799 ];
800
801 let result = manager.analyze_circular_references(&allocations);
802 assert_eq!(result.total_smart_pointers, 0, "no smart pointer info");
803 assert_eq!(result.circular_references.len(), 0);
804 assert_eq!(result.pointers_in_cycles, 0);
805 assert_eq!(result.total_leaked_memory, 0);
806 }
807
808 #[test]
809 fn test_analyze_borrow_patterns() {
810 let manager = AnalysisManager::new();
811 let allocations = vec![AllocationInfo::new(0x7000, 1024)];
812
813 let result = manager.analyze_borrow_patterns(&allocations);
814
815 assert!(result.patterns.is_empty());
817 assert_eq!(result.total_events, 0);
818 assert!(result.analysis_timestamp > 0);
819 }
820
821 #[test]
822 fn test_analyze_generic_types() {
823 let manager = AnalysisManager::new();
824 let allocations = vec![AllocationInfo::new(0x8000, 256)];
825
826 let result = manager.analyze_generic_types(&allocations);
827
828 assert_eq!(result.total_instances, 0);
830 assert_eq!(result.unique_base_types, 0);
831 assert_eq!(result.total_instantiations, 0);
832 assert_eq!(result.constraint_violations, 0);
833 assert!(result.most_used_types.is_empty());
834 }
835
836 #[test]
837 fn test_analyze_async_patterns() {
838 let manager = AnalysisManager::new();
839 let allocations = vec![AllocationInfo::new(0x9000, 2048)];
840
841 let result = manager.analyze_async_patterns(&allocations);
842
843 assert!(result.patterns.is_empty());
845 assert_eq!(result.total_futures_analyzed, 0);
846 assert!(result.analysis_timestamp > 0);
847 }
848
849 #[test]
850 fn test_analyze_closure_patterns() {
851 let manager = AnalysisManager::new();
852 let allocations = vec![AllocationInfo::new(0xa000, 128)];
853
854 let result = manager.analyze_closure_patterns(&allocations);
855
856 assert!(result.detected_closures.is_empty());
858 assert_eq!(result.capture_statistics.total_closures, 0);
859 assert!(result.optimization_suggestions.is_empty());
860 assert!(result.lifetime_analysis.lifetime_patterns.is_empty());
861 assert!(result.analysis_timestamp > 0);
862 }
863
864 #[test]
865 fn test_analyze_lifecycle_patterns() {
866 let manager = AnalysisManager::new();
867 let allocations = vec![AllocationInfo::new(0xb000, 512)];
868
869 let result = manager.analyze_lifecycle_patterns(&allocations);
870
871 assert!(result.drop_events.is_empty());
873 assert!(result.raii_patterns.is_empty());
874 assert!(result.borrow_analysis.borrow_patterns.is_empty());
875 assert!(result.closure_captures.is_empty());
876 assert!(result.analysis_timestamp > 0);
877 }
878
879 #[test]
880 fn test_perform_comprehensive_analysis() {
881 let manager = AnalysisManager::new();
882 let allocations = vec![
883 AllocationInfo::new(0x1000, 1024),
884 AllocationInfo::new(0x2000, 512),
885 AllocationInfo::new(0x3000, 256),
886 ];
887 let stats = MemoryStats::new();
888
889 let result = manager.perform_comprehensive_analysis(&allocations, &stats);
890
891 assert!(
892 result.fragmentation_analysis.fragmentation_ratio >= 0.0
893 && result.fragmentation_analysis.fragmentation_ratio <= 1.0
894 );
895 assert_eq!(
896 result.system_library_stats.std_collections.allocation_count,
897 0
898 );
899 assert_eq!(result.concurrency_analysis.thread_safety_allocations, 0);
900 assert_eq!(result.unsafe_ffi_stats.total_operations, 0);
901 assert_eq!(result.circular_reference_analysis.total_smart_pointers, 0);
902 assert!(result.borrow_analysis.patterns.is_empty());
903 assert_eq!(result.generic_analysis.total_instances, 0);
904 assert!(result.async_analysis.patterns.is_empty());
905 assert!(result.closure_analysis.detected_closures.is_empty());
906 assert!(result.lifecycle_analysis.drop_events.is_empty());
907 assert_eq!(result.memory_stats.total_allocations, 0);
908 assert!(result.analysis_timestamp > 0);
909 }
910
911 #[test]
912 fn test_backward_compatibility_functions() {
913 let allocations = vec![AllocationInfo::new(0x1000, 1024)];
914
915 let frag_result = analyze_fragmentation(&allocations);
917 assert_eq!(frag_result.fragmentation_ratio, 0.0);
918
919 let lib_result = analyze_system_libraries(&allocations);
920 assert_eq!(lib_result.std_collections.allocation_count, 0);
921
922 let conc_result = analyze_concurrency_safety(&allocations);
923 assert_eq!(conc_result.thread_safety_allocations, 0);
924
925 let _tracker = get_global_unsafe_ffi_tracker();
926
927 let stats = get_unsafe_ffi_stats();
928 assert_eq!(stats.total_operations, 0);
929
930 let memory_stats = MemoryStats::new();
931 let comp_result = perform_comprehensive_analysis(&allocations, &memory_stats);
932 assert!(comp_result.analysis_timestamp > 0);
933 }
934
935 #[test]
936 fn test_empty_allocations_analysis() {
937 let manager = AnalysisManager::new();
938 let empty_allocations: Vec<AllocationInfo> = vec![];
939
940 let frag_result = manager.analyze_fragmentation(&empty_allocations);
942 assert_eq!(frag_result.fragmentation_ratio, 0.0);
943
944 let lib_result = manager.analyze_system_libraries(&empty_allocations);
945 assert_eq!(lib_result.std_collections.allocation_count, 0);
946
947 let conc_result = manager.analyze_concurrency_safety(&empty_allocations);
948 assert_eq!(conc_result.thread_safety_allocations, 0);
949
950 let circ_result = manager.analyze_circular_references(&empty_allocations);
951 assert_eq!(circ_result.total_smart_pointers, 0);
952 }
953
954 #[test]
955 fn test_large_allocation_list_analysis() {
956 let manager = AnalysisManager::new();
957 let mut allocations = Vec::new();
958
959 for i in 0..100 {
961 allocations.push(AllocationInfo::new(0x1000 + i * 0x1000, 1024 + i));
962 }
963
964 let stats = MemoryStats::new();
965 let result = manager.perform_comprehensive_analysis(&allocations, &stats);
966
967 assert!(result.analysis_timestamp > 0);
969 assert_eq!(result.memory_stats.total_allocations, 0); }
971}