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<std::thread::ThreadId, usize> =
345 std::collections::HashMap::new();
346
347 for alloc in allocations {
348 let type_name = alloc.type_name.as_deref().unwrap_or("");
349
350 if type_name.contains("Arc<")
351 || type_name.contains("Mutex<")
352 || type_name.contains("RwLock<")
353 {
354 analysis.thread_safety_allocations += 1;
355 analysis.shared_memory_bytes += alloc.size;
356 }
357
358 if type_name.contains("Arc<") {
359 analysis.arc_shared += 1;
360 }
361
362 if type_name.contains("mpsc")
363 || type_name.contains("channel")
364 || type_name.contains("Sender")
365 || type_name.contains("Receiver")
366 {
367 analysis.channel_buffers += 1;
368 }
369
370 if type_name.contains("thread_local") || type_name.contains("LocalKey") {
371 analysis.thread_local_storage += 1;
372 }
373
374 if type_name.contains("Atomic") {
375 analysis.atomic_operations += 1;
376 }
377
378 *thread_alloc_counts.entry(alloc.thread_id).or_insert(0) += 1;
379 }
380
381 let max_thread_allocs = thread_alloc_counts.values().max().copied().unwrap_or(0);
382 let min_thread_allocs = thread_alloc_counts.values().min().copied().unwrap_or(0);
383 let thread_count = thread_alloc_counts.len();
384
385 if thread_count <= 1 {
386 analysis.lock_contention_risk = "None".to_string();
387 } else {
388 let imbalance_ratio = if min_thread_allocs > 0 {
389 max_thread_allocs as f64 / min_thread_allocs as f64
390 } else {
391 f64::MAX
392 };
393
394 if imbalance_ratio > 10.0 {
395 analysis.lock_contention_risk = "High".to_string();
396 } else if imbalance_ratio > 3.0 {
397 analysis.lock_contention_risk = "Medium".to_string();
398 } else {
399 analysis.lock_contention_risk = "Low".to_string();
400 }
401 }
402
403 analysis
404 }
405
406 pub fn get_unsafe_ffi_tracker(&self) -> Arc<crate::unsafe_ffi_tracker::UnsafeFFITracker> {
408 crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker()
410 }
411
412 pub fn get_unsafe_ffi_stats(&self) -> crate::unsafe_ffi_tracker::UnsafeFFIStats {
414 self.get_unsafe_ffi_tracker().get_stats()
416 }
417
418 pub fn analyze_circular_references(
420 &self,
421 allocations: &[AllocationInfo],
422 ) -> crate::circular_reference::CircularReferenceAnalysis {
423 crate::circular_reference::detect_circular_references(allocations)
424 }
425
426 pub fn analyze_borrow_patterns(
428 &self,
429 _allocations: &[AllocationInfo],
430 ) -> BorrowPatternAnalysis {
431 let analyzer = get_global_borrow_analyzer();
432 analyzer.analyze_borrow_patterns()
433 }
434
435 pub fn analyze_generic_types(&self, _allocations: &[AllocationInfo]) -> GenericStatistics {
437 let analyzer = GenericAnalyzer::new();
439 analyzer.get_generic_statistics()
440 }
441
442 pub fn analyze_async_patterns(&self, _allocations: &[AllocationInfo]) -> AsyncPatternAnalysis {
444 let analyzer = get_global_async_analyzer();
445 analyzer.analyze_async_patterns()
446 }
447
448 pub fn analyze_closure_patterns(
450 &self,
451 allocations: &[AllocationInfo],
452 ) -> ClosureAnalysisReport {
453 let analyzer = get_global_closure_analyzer();
454 analyzer.analyze_closure_patterns(allocations)
455 }
456
457 pub fn analyze_lifecycle_patterns(
459 &self,
460 _allocations: &[AllocationInfo],
461 ) -> LifecycleAnalysisReport {
462 let analyzer = get_global_lifecycle_analyzer();
463 analyzer.get_lifecycle_report()
464 }
465
466 pub fn analyze_memory_leaks(
468 &self,
469 allocations: &[AllocationInfo],
470 ) -> crate::analysis::detectors::DetectionResult {
471 let detector = crate::analysis::detectors::LeakDetector::new(
472 crate::analysis::detectors::LeakDetectorConfig::default(),
473 );
474 detector.detect(allocations)
475 }
476
477 pub fn analyze_use_after_free(
479 &self,
480 allocations: &[AllocationInfo],
481 ) -> crate::analysis::detectors::DetectionResult {
482 let detector = crate::analysis::detectors::UafDetector::new(
483 crate::analysis::detectors::UafDetectorConfig::default(),
484 );
485 detector.detect(allocations)
486 }
487
488 pub fn analyze_buffer_overflow(
490 &self,
491 allocations: &[AllocationInfo],
492 ) -> crate::analysis::detectors::DetectionResult {
493 let detector = crate::analysis::detectors::OverflowDetector::new(
494 crate::analysis::detectors::OverflowDetectorConfig::default(),
495 );
496 detector.detect(allocations)
497 }
498
499 pub fn analyze_safety_violations(
501 &self,
502 allocations: &[AllocationInfo],
503 ) -> crate::analysis::detectors::DetectionResult {
504 let detector = crate::analysis::detectors::SafetyDetector::new(
505 crate::analysis::detectors::SafetyDetectorConfig::default(),
506 );
507 detector.detect(allocations)
508 }
509
510 pub fn analyze_lifecycle_issues(
512 &self,
513 allocations: &[AllocationInfo],
514 ) -> crate::analysis::detectors::DetectionResult {
515 let detector = crate::analysis::detectors::LifecycleDetector::new(
516 crate::analysis::detectors::LifecycleDetectorConfig::default(),
517 );
518 detector.detect(allocations)
519 }
520
521 pub fn perform_comprehensive_analysis(
523 &self,
524 allocations: &[AllocationInfo],
525 stats: &MemoryStats,
526 ) -> ComprehensiveAnalysisReport {
527 let fragmentation = self.analyze_fragmentation(allocations);
528 let system_libs = self.analyze_system_libraries(allocations);
529 let concurrency = self.analyze_concurrency_safety(allocations);
530 let unsafe_stats = self.get_unsafe_ffi_stats();
531 let circular_refs = self.analyze_circular_references(allocations);
532
533 let borrow_analysis = self.analyze_borrow_patterns(allocations);
535 let generic_analysis = self.analyze_generic_types(allocations);
536 let async_analysis = self.analyze_async_patterns(allocations);
537 let closure_analysis = self.analyze_closure_patterns(allocations);
538 let lifecycle_analysis = self.analyze_lifecycle_patterns(allocations);
539
540 ComprehensiveAnalysisReport {
541 fragmentation_analysis: fragmentation,
542 system_library_stats: system_libs,
543 concurrency_analysis: concurrency,
544 unsafe_ffi_stats: unsafe_stats,
545 circular_reference_analysis: circular_refs,
546 borrow_analysis,
547 generic_analysis,
548 async_analysis,
549 closure_analysis,
550 lifecycle_analysis,
551 memory_stats: stats.clone(),
552 analysis_timestamp: std::time::SystemTime::now()
553 .duration_since(std::time::UNIX_EPOCH)
554 .unwrap_or_default()
555 .as_secs(),
556 }
557 }
558}
559
560impl Default for AnalysisManager {
561 fn default() -> Self {
562 Self::new()
563 }
564}
565
566#[derive(Debug, Clone)]
568pub struct ComprehensiveAnalysisReport {
569 pub fragmentation_analysis: FragmentationAnalysis,
571 pub system_library_stats: SystemLibraryStats,
573 pub concurrency_analysis: ConcurrencyAnalysis,
575 pub unsafe_ffi_stats: crate::unsafe_ffi_tracker::UnsafeFFIStats,
577 pub circular_reference_analysis: crate::circular_reference::CircularReferenceAnalysis,
579 pub borrow_analysis: BorrowPatternAnalysis,
581 pub generic_analysis: GenericStatistics,
583 pub async_analysis: AsyncPatternAnalysis,
585 pub closure_analysis: ClosureAnalysisReport,
587 pub lifecycle_analysis: LifecycleAnalysisReport,
589 pub memory_stats: MemoryStats,
591 pub analysis_timestamp: u64,
593}
594
595pub fn analyze_fragmentation(allocations: &[AllocationInfo]) -> FragmentationAnalysis {
600 let manager = AnalysisManager::new();
601 manager.analyze_fragmentation(allocations)
602}
603
604pub fn analyze_system_libraries(allocations: &[AllocationInfo]) -> SystemLibraryStats {
606 let manager = AnalysisManager::new();
607 manager.analyze_system_libraries(allocations)
608}
609
610pub fn analyze_concurrency_safety(allocations: &[AllocationInfo]) -> ConcurrencyAnalysis {
612 let manager = AnalysisManager::new();
613 manager.analyze_concurrency_safety(allocations)
614}
615
616pub fn get_global_unsafe_ffi_tracker() -> Arc<crate::unsafe_ffi_tracker::UnsafeFFITracker> {
618 crate::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker()
619}
620
621pub fn get_unsafe_ffi_stats() -> crate::unsafe_ffi_tracker::UnsafeFFIStats {
623 let manager = AnalysisManager::new();
624 manager.get_unsafe_ffi_stats()
625}
626
627pub fn perform_comprehensive_analysis(
629 allocations: &[AllocationInfo],
630 stats: &MemoryStats,
631) -> ComprehensiveAnalysisReport {
632 let manager = AnalysisManager::new();
633 manager.perform_comprehensive_analysis(allocations, stats)
634}
635
636#[cfg(test)]
640mod tests {
641 use super::*;
642 use crate::capture::types::AllocationInfo;
643
644 #[test]
645 fn test_analyze_fragmentation() {
646 let manager = AnalysisManager::new();
647 let allocations = vec![
652 AllocationInfo::new(0x1000, 1024),
653 AllocationInfo::new(0x2000, 512),
654 ];
655
656 let result = manager.analyze_fragmentation(&allocations);
657
658 assert!(
661 result.fragmentation_ratio > 0.5,
662 "fragmentation_ratio should be > 0.5, got {}",
663 result.fragmentation_ratio
664 );
665 assert_eq!(result.free_block_count, 1, "should have exactly 1 gap");
666 assert_eq!(
667 result.largest_free_block, 3072,
668 "largest gap should be 3072"
669 );
670 assert_eq!(
671 result.smallest_free_block, 3072,
672 "smallest gap should be 3072"
673 );
674 }
675
676 #[test]
677 fn test_analyze_fragmentation_no_gaps() {
678 let manager = AnalysisManager::new();
679 let allocations = vec![
681 AllocationInfo::new(0x1000, 256),
682 AllocationInfo::new(0x1100, 256),
683 ];
684
685 let result = manager.analyze_fragmentation(&allocations);
686 assert_eq!(
687 result.fragmentation_ratio, 0.0,
688 "no gaps means zero fragmentation"
689 );
690 assert_eq!(result.free_block_count, 0);
691 }
692
693 #[test]
694 fn test_analyze_system_libraries() {
695 let manager = AnalysisManager::new();
696
697 let mut alloc_vec = AllocationInfo::new(0x1000, 256);
699 alloc_vec.type_name = Some("Vec<String>".to_string());
700
701 let mut alloc_hashmap = AllocationInfo::new(0x2000, 512);
702 alloc_hashmap.type_name = Some("HashMap<K, V>".to_string());
703
704 let mut alloc_file = AllocationInfo::new(0x3000, 128);
705 alloc_file.type_name = Some("File".to_string());
706
707 let mut alloc_regex = AllocationInfo::new(0x4000, 64);
708 alloc_regex.type_name = Some("Regex".to_string());
709
710 let allocations = vec![alloc_vec, alloc_hashmap, alloc_file, alloc_regex];
711
712 let result = manager.analyze_system_libraries(&allocations);
713
714 assert_eq!(
715 result.std_collections.allocation_count, 2,
716 "Vec and HashMap"
717 );
718 assert_eq!(result.std_collections.total_bytes, 256 + 512);
719 assert_eq!(result.file_system.allocation_count, 1, "File");
720 assert_eq!(result.file_system.total_bytes, 128);
721 assert_eq!(result.regex_engine.allocation_count, 1, "Regex");
722 assert_eq!(result.regex_engine.total_bytes, 64);
723 assert_eq!(result.async_runtime.allocation_count, 0, "no async types");
724 }
725
726 #[test]
727 fn test_analyze_concurrency_safety() {
728 let manager = AnalysisManager::new();
729
730 let mut alloc_arc = AllocationInfo::new(0x1000, 64);
731 alloc_arc.type_name = Some("Arc<Mutex<i32>>".to_string());
732
733 let mut alloc_mutex = AllocationInfo::new(0x2000, 128);
734 alloc_mutex.type_name = Some("Mutex<String>".to_string());
735
736 let mut alloc_atomic = AllocationInfo::new(0x3000, 8);
737 alloc_atomic.type_name = Some("AtomicUsize".to_string());
738
739 let allocations = vec![alloc_arc, alloc_mutex, alloc_atomic];
740
741 let result = manager.analyze_concurrency_safety(&allocations);
742
743 assert_eq!(result.thread_safety_allocations, 2, "Arc and Mutex");
744 assert_eq!(result.arc_shared, 1, "Arc");
745 assert_eq!(result.atomic_operations, 1, "AtomicUsize");
746 assert_eq!(result.shared_memory_bytes, 64 + 128);
747 assert_eq!(result.lock_contention_risk, "None", "single thread");
748 }
749
750 #[test]
751 fn test_analyze_concurrency_safety_multi_thread() {
752 let manager = AnalysisManager::new();
753
754 let mut alloc_arc = AllocationInfo::new(0x1000, 64);
757 alloc_arc.type_name = Some("Arc<i32>".to_string());
758
759 let allocations = vec![alloc_arc];
760
761 let result = manager.analyze_concurrency_safety(&allocations);
762 assert_eq!(result.arc_shared, 1);
763 }
764
765 #[test]
766 fn test_get_unsafe_ffi_tracker() {
767 let manager = AnalysisManager::new();
768
769 let _tracker = manager.get_unsafe_ffi_tracker();
770
771 }
773
774 #[test]
775 fn test_get_unsafe_ffi_stats() {
776 let manager = AnalysisManager::new();
777
778 let stats = manager.get_unsafe_ffi_stats();
779
780 assert_eq!(stats.total_operations, 0);
782 assert_eq!(stats.ffi_calls, 0);
783 assert_eq!(stats.raw_pointer_operations, 0);
784 assert_eq!(stats.memory_violations, 0);
785 assert!(stats.operations.is_empty());
786 }
787
788 #[test]
789 fn test_analyze_circular_references() {
790 let manager = AnalysisManager::new();
791 let allocations = vec![
794 AllocationInfo::new(0x4000, 128),
795 AllocationInfo::new(0x5000, 256),
796 ];
797
798 let result = manager.analyze_circular_references(&allocations);
799 assert_eq!(result.total_smart_pointers, 0, "no smart pointer info");
800 assert_eq!(result.circular_references.len(), 0);
801 assert_eq!(result.pointers_in_cycles, 0);
802 assert_eq!(result.total_leaked_memory, 0);
803 }
804
805 #[test]
806 fn test_analyze_borrow_patterns() {
807 let manager = AnalysisManager::new();
808 let allocations = vec![AllocationInfo::new(0x7000, 1024)];
809
810 let result = manager.analyze_borrow_patterns(&allocations);
811
812 assert!(result.patterns.is_empty());
814 assert_eq!(result.total_events, 0);
815 assert!(result.analysis_timestamp > 0);
816 }
817
818 #[test]
819 fn test_analyze_generic_types() {
820 let manager = AnalysisManager::new();
821 let allocations = vec![AllocationInfo::new(0x8000, 256)];
822
823 let result = manager.analyze_generic_types(&allocations);
824
825 assert_eq!(result.total_instances, 0);
827 assert_eq!(result.unique_base_types, 0);
828 assert_eq!(result.total_instantiations, 0);
829 assert_eq!(result.constraint_violations, 0);
830 assert!(result.most_used_types.is_empty());
831 }
832
833 #[test]
834 fn test_analyze_async_patterns() {
835 let manager = AnalysisManager::new();
836 let allocations = vec![AllocationInfo::new(0x9000, 2048)];
837
838 let result = manager.analyze_async_patterns(&allocations);
839
840 assert!(result.patterns.is_empty());
842 assert_eq!(result.total_futures_analyzed, 0);
843 assert!(result.analysis_timestamp > 0);
844 }
845
846 #[test]
847 fn test_analyze_closure_patterns() {
848 let manager = AnalysisManager::new();
849 let allocations = vec![AllocationInfo::new(0xa000, 128)];
850
851 let result = manager.analyze_closure_patterns(&allocations);
852
853 assert!(result.detected_closures.is_empty());
855 assert_eq!(result.capture_statistics.total_closures, 0);
856 assert!(result.optimization_suggestions.is_empty());
857 assert!(result.lifetime_analysis.lifetime_patterns.is_empty());
858 assert!(result.analysis_timestamp > 0);
859 }
860
861 #[test]
862 fn test_analyze_lifecycle_patterns() {
863 let manager = AnalysisManager::new();
864 let allocations = vec![AllocationInfo::new(0xb000, 512)];
865
866 let result = manager.analyze_lifecycle_patterns(&allocations);
867
868 assert!(result.drop_events.is_empty());
870 assert!(result.raii_patterns.is_empty());
871 assert!(result.borrow_analysis.borrow_patterns.is_empty());
872 assert!(result.closure_captures.is_empty());
873 assert!(result.analysis_timestamp > 0);
874 }
875
876 #[test]
877 fn test_perform_comprehensive_analysis() {
878 let manager = AnalysisManager::new();
879 let allocations = vec![
880 AllocationInfo::new(0x1000, 1024),
881 AllocationInfo::new(0x2000, 512),
882 AllocationInfo::new(0x3000, 256),
883 ];
884 let stats = MemoryStats::new();
885
886 let result = manager.perform_comprehensive_analysis(&allocations, &stats);
887
888 assert!(
889 result.fragmentation_analysis.fragmentation_ratio >= 0.0
890 && result.fragmentation_analysis.fragmentation_ratio <= 1.0
891 );
892 assert_eq!(
893 result.system_library_stats.std_collections.allocation_count,
894 0
895 );
896 assert_eq!(result.concurrency_analysis.thread_safety_allocations, 0);
897 assert_eq!(result.unsafe_ffi_stats.total_operations, 0);
898 assert_eq!(result.circular_reference_analysis.total_smart_pointers, 0);
899 assert!(result.borrow_analysis.patterns.is_empty());
900 assert_eq!(result.generic_analysis.total_instances, 0);
901 assert!(result.async_analysis.patterns.is_empty());
902 assert!(result.closure_analysis.detected_closures.is_empty());
903 assert!(result.lifecycle_analysis.drop_events.is_empty());
904 assert_eq!(result.memory_stats.total_allocations, 0);
905 assert!(result.analysis_timestamp > 0);
906 }
907
908 #[test]
909 fn test_backward_compatibility_functions() {
910 let allocations = vec![AllocationInfo::new(0x1000, 1024)];
911
912 let frag_result = analyze_fragmentation(&allocations);
914 assert_eq!(frag_result.fragmentation_ratio, 0.0);
915
916 let lib_result = analyze_system_libraries(&allocations);
917 assert_eq!(lib_result.std_collections.allocation_count, 0);
918
919 let conc_result = analyze_concurrency_safety(&allocations);
920 assert_eq!(conc_result.thread_safety_allocations, 0);
921
922 let _tracker = get_global_unsafe_ffi_tracker();
923
924 let stats = get_unsafe_ffi_stats();
925 assert_eq!(stats.total_operations, 0);
926
927 let memory_stats = MemoryStats::new();
928 let comp_result = perform_comprehensive_analysis(&allocations, &memory_stats);
929 assert!(comp_result.analysis_timestamp > 0);
930 }
931
932 #[test]
933 fn test_empty_allocations_analysis() {
934 let manager = AnalysisManager::new();
935 let empty_allocations: Vec<AllocationInfo> = vec![];
936
937 let frag_result = manager.analyze_fragmentation(&empty_allocations);
939 assert_eq!(frag_result.fragmentation_ratio, 0.0);
940
941 let lib_result = manager.analyze_system_libraries(&empty_allocations);
942 assert_eq!(lib_result.std_collections.allocation_count, 0);
943
944 let conc_result = manager.analyze_concurrency_safety(&empty_allocations);
945 assert_eq!(conc_result.thread_safety_allocations, 0);
946
947 let circ_result = manager.analyze_circular_references(&empty_allocations);
948 assert_eq!(circ_result.total_smart_pointers, 0);
949 }
950
951 #[test]
952 fn test_large_allocation_list_analysis() {
953 let manager = AnalysisManager::new();
954 let mut allocations = Vec::new();
955
956 for i in 0..100 {
958 allocations.push(AllocationInfo::new(0x1000 + i * 0x1000, 1024 + i));
959 }
960
961 let stats = MemoryStats::new();
962 let result = manager.perform_comprehensive_analysis(&allocations, &stats);
963
964 assert!(result.analysis_timestamp > 0);
966 assert_eq!(result.memory_stats.total_allocations, 0); }
968}