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