codeprism_lang_rust/
analysis.rs

1//! Rust-specific analysis capabilities
2
3use crate::types::{Edge, Node, NodeKind, Span};
4use std::collections::HashMap;
5
6/// Analyzer for Rust-specific language features
7pub struct RustAnalyzer {
8    nodes: Vec<Node>,
9    edges: Vec<Edge>,
10    /// Map from function/scope ID to nodes within that scope
11    scope_map: HashMap<crate::types::NodeId, Vec<crate::types::NodeId>>,
12}
13
14impl RustAnalyzer {
15    /// Create a new Rust analyzer
16    pub fn new(nodes: Vec<Node>, edges: Vec<Edge>) -> Self {
17        let mut analyzer = Self {
18            nodes,
19            edges,
20            scope_map: HashMap::new(),
21        };
22        analyzer.build_scope_map();
23        analyzer
24    }
25
26    /// Build a map of scopes to their contained nodes
27    fn build_scope_map(&mut self) {
28        for edge in &self.edges {
29            if matches!(edge.kind, crate::types::EdgeKind::Contains) {
30                self.scope_map
31                    .entry(edge.source)
32                    .or_default()
33                    .push(edge.target);
34            }
35        }
36    }
37
38    /// Comprehensive analysis of all Rust-specific patterns
39    pub fn analyze_all(&self) -> RustAnalysisResult {
40        RustAnalysisResult {
41            ownership_patterns: self.analyze_ownership_patterns(),
42            performance_issues: self.analyze_performance_patterns(),
43            safety_issues: self.analyze_safety_patterns(),
44            concurrency_issues: self.analyze_concurrency_patterns(),
45            trait_implementations: self.analyze_trait_implementations(),
46            unsafe_usage: self.analyze_unsafe_usage(),
47            lifetime_usage: self.analyze_lifetime_usage(),
48            macro_usage: self.analyze_macro_usage(),
49        }
50    }
51
52    /// Analyze ownership patterns in the code
53    pub fn analyze_ownership_patterns(&self) -> Vec<OwnershipPattern> {
54        let mut patterns = Vec::new();
55
56        for node in &self.nodes {
57            match &node.kind {
58                NodeKind::Function | NodeKind::Method => {
59                    patterns.extend(self.detect_ownership_antipatterns(node));
60                    patterns.extend(self.detect_unnecessary_clones(node));
61                    patterns.extend(self.detect_inefficient_borrowing(node));
62                    patterns.extend(self.detect_move_semantics_issues(node));
63                }
64                NodeKind::Variable => {
65                    patterns.extend(self.analyze_variable_ownership(node));
66                }
67                _ => {}
68            }
69        }
70
71        patterns
72    }
73
74    /// Analyze performance-related patterns
75    pub fn analyze_performance_patterns(&self) -> Vec<PerformanceIssue> {
76        let mut issues = Vec::new();
77
78        for node in &self.nodes {
79            match &node.kind {
80                NodeKind::Function | NodeKind::Method => {
81                    issues.extend(self.detect_allocation_patterns(node));
82                    issues.extend(self.detect_string_inefficiencies(node));
83                    issues.extend(self.detect_iterator_inefficiencies(node));
84                    issues.extend(self.detect_collection_inefficiencies(node));
85                }
86                NodeKind::Call => {
87                    issues.extend(self.analyze_call_performance(node));
88                }
89                _ => {}
90            }
91        }
92
93        issues
94    }
95
96    /// Analyze safety-related patterns
97    pub fn analyze_safety_patterns(&self) -> Vec<SafetyIssue> {
98        let mut issues = Vec::new();
99
100        for node in &self.nodes {
101            match &node.kind {
102                NodeKind::Function | NodeKind::Method => {
103                    if self.is_unsafe_function(node) {
104                        issues.extend(self.analyze_unsafe_function(node));
105                    }
106                    issues.extend(self.detect_ffi_patterns(node));
107                    issues.extend(self.detect_memory_safety_issues(node));
108                }
109                _ => {}
110            }
111        }
112
113        issues
114    }
115
116    /// Analyze concurrency-related patterns
117    pub fn analyze_concurrency_patterns(&self) -> Vec<ConcurrencyIssue> {
118        let mut issues = Vec::new();
119
120        for node in &self.nodes {
121            match &node.kind {
122                NodeKind::Function | NodeKind::Method => {
123                    issues.extend(self.analyze_async_patterns(node));
124                    issues.extend(self.detect_deadlock_potential(node));
125                    issues.extend(self.analyze_thread_safety(node));
126                    issues.extend(self.analyze_channel_usage(node));
127                }
128                NodeKind::Struct | NodeKind::Enum => {
129                    issues.extend(self.analyze_send_sync_traits(node));
130                }
131                _ => {}
132            }
133        }
134
135        issues
136    }
137
138    // Ownership Pattern Detection Methods
139
140    /// Detect ownership antipatterns in a function
141    fn detect_ownership_antipatterns(&self, function_node: &Node) -> Vec<OwnershipPattern> {
142        let mut patterns = Vec::new();
143
144        // Check function signature for ownership issues
145        if let Some(signature) = &function_node.signature {
146            // Detect unnecessary owned parameters
147            if signature.contains("String") && !signature.contains("&str") {
148                patterns.push(OwnershipPattern {
149                    pattern_type: OwnershipPatternType::UnnecessaryOwned,
150                    location: function_node.span.clone(),
151                    description: "Function takes owned String when &str would suffice".to_string(),
152                    suggestion: Some(
153                        "Consider using &str parameter for read-only string access".to_string(),
154                    ),
155                    severity: Severity::Medium,
156                });
157            }
158
159            // Detect multiple mutable borrows pattern
160            let mut_borrow_count = signature.matches("&mut").count();
161            if mut_borrow_count > 1 {
162                patterns.push(OwnershipPattern {
163                    pattern_type: OwnershipPatternType::MultipleMutableBorrows,
164                    location: function_node.span.clone(),
165                    description: format!(
166                        "Function has {} mutable borrows, potential for borrowing conflicts",
167                        mut_borrow_count
168                    ),
169                    suggestion: Some(
170                        "Consider refactoring to reduce mutable borrows or use interior mutability"
171                            .to_string(),
172                    ),
173                    severity: Severity::High,
174                });
175            }
176        }
177
178        patterns
179    }
180
181    /// Detect unnecessary clone operations
182    fn detect_unnecessary_clones(&self, function_node: &Node) -> Vec<OwnershipPattern> {
183        let mut patterns = Vec::new();
184
185        // Look for calls within this function that might be unnecessary clones
186        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
187            for &node_id in scope_nodes {
188                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
189                    if matches!(call_node.kind, NodeKind::Call) && call_node.name.contains("clone")
190                    {
191                        patterns.push(OwnershipPattern {
192                            pattern_type: OwnershipPatternType::UnnecessaryClone,
193                            location: call_node.span.clone(),
194                            description: "Potential unnecessary clone() call".to_string(),
195                            suggestion: Some(
196                                "Check if borrowing would work instead of cloning".to_string(),
197                            ),
198                            severity: Severity::Medium,
199                        });
200                    }
201                }
202            }
203        }
204
205        patterns
206    }
207
208    /// Detect inefficient borrowing patterns
209    fn detect_inefficient_borrowing(&self, function_node: &Node) -> Vec<OwnershipPattern> {
210        let mut patterns = Vec::new();
211
212        // Analyze function metadata for borrowing patterns
213        if let Some(metadata) = function_node.metadata.as_object() {
214            if let Some(params) = metadata.get("parameters").and_then(|p| p.as_array()) {
215                for param in params {
216                    if let Some(param_obj) = param.as_object() {
217                        if let Some(ownership) = param_obj.get("ownership").and_then(|o| o.as_str())
218                        {
219                            if ownership == "borrowed" {
220                                if let Some(usage) =
221                                    param_obj.get("usage_pattern").and_then(|u| u.as_str())
222                                {
223                                    if usage == "stored" {
224                                        patterns.push(OwnershipPattern {
225                                            pattern_type: OwnershipPatternType::InefficientBorrowing,
226                                            location: function_node.span.clone(),
227                                            description: "Borrowed parameter is stored, consider taking ownership".to_string(),
228                                            suggestion: Some("Take ownership of the parameter if it needs to be stored".to_string()),
229                                            severity: Severity::Medium,
230                                        });
231                                    }
232                                }
233                            }
234                        }
235                    }
236                }
237            }
238        }
239
240        patterns
241    }
242
243    /// Detect move semantics issues
244    fn detect_move_semantics_issues(&self, function_node: &Node) -> Vec<OwnershipPattern> {
245        let mut patterns = Vec::new();
246
247        // Check for potential move after use patterns
248        if let Some(signature) = &function_node.signature {
249            if signature.contains("self")
250                && !signature.contains("&self")
251                && !signature.contains("&mut self")
252            {
253                patterns.push(OwnershipPattern {
254                    pattern_type: OwnershipPatternType::PotentialMoveError,
255                    location: function_node.span.clone(),
256                    description: "Method takes self by value, object will be moved".to_string(),
257                    suggestion: Some(
258                        "Consider if borrowing (&self or &mut self) would be more appropriate"
259                            .to_string(),
260                    ),
261                    severity: Severity::Low,
262                });
263            }
264        }
265
266        patterns
267    }
268
269    /// Analyze variable ownership patterns
270    fn analyze_variable_ownership(&self, variable_node: &Node) -> Vec<OwnershipPattern> {
271        let mut patterns = Vec::new();
272
273        // Check if variable name suggests it should be a reference
274        if variable_node.name.ends_with("_ref") || variable_node.name.starts_with("ref_") {
275            patterns.push(OwnershipPattern {
276                pattern_type: OwnershipPatternType::InconsistentNaming,
277                location: variable_node.span.clone(),
278                description: "Variable name suggests reference but type might be owned".to_string(),
279                suggestion: Some(
280                    "Ensure naming convention matches ownership semantics".to_string(),
281                ),
282                severity: Severity::Low,
283            });
284        }
285
286        patterns
287    }
288
289    // Performance Analysis Methods
290
291    /// Detect allocation patterns that might be inefficient
292    fn detect_allocation_patterns(&self, function_node: &Node) -> Vec<PerformanceIssue> {
293        let mut issues = Vec::new();
294
295        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
296            for &node_id in scope_nodes {
297                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
298                    if matches!(call_node.kind, NodeKind::Call) {
299                        // Detect Vec::new() in loops (should check actual loop context)
300                        if call_node.name.contains("Vec::new") || call_node.name.contains("vec!") {
301                            issues.push(PerformanceIssue {
302                                issue_type: PerformanceIssueType::FrequentAllocations,
303                                location: call_node.span.clone(),
304                                description: "Vector allocation detected - ensure not in hot path"
305                                    .to_string(),
306                                suggestion: Some(
307                                    "Consider pre-allocating with capacity or reusing allocations"
308                                        .to_string(),
309                                ),
310                                impact: PerformanceImpact::Medium,
311                            });
312                        }
313
314                        // Detect HashMap::new() without capacity
315                        if call_node.name.contains("HashMap::new") {
316                            issues.push(PerformanceIssue {
317                                issue_type: PerformanceIssueType::UnoptimizedCollections,
318                                location: call_node.span.clone(),
319                                description: "HashMap created without initial capacity".to_string(),
320                                suggestion: Some(
321                                    "Use HashMap::with_capacity() if size is known".to_string(),
322                                ),
323                                impact: PerformanceImpact::Medium,
324                            });
325                        }
326                    }
327                }
328            }
329        }
330
331        issues
332    }
333
334    /// Detect string manipulation inefficiencies
335    fn detect_string_inefficiencies(&self, function_node: &Node) -> Vec<PerformanceIssue> {
336        let mut issues = Vec::new();
337
338        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
339            let mut string_pushes = 0;
340
341            for &node_id in scope_nodes {
342                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
343                    if matches!(call_node.kind, NodeKind::Call) {
344                        // Count string push operations
345                        if call_node.name.contains("push_str") || call_node.name.contains("push") {
346                            string_pushes += 1;
347                        }
348                    }
349                }
350            }
351
352            // If we have multiple string push operations, it's a performance issue
353            if string_pushes >= 3 {
354                issues.push(PerformanceIssue {
355                    issue_type: PerformanceIssueType::StringConcatenation,
356                    location: function_node.span.clone(),
357                    description: format!(
358                        "Multiple string operations detected: {} push operations",
359                        string_pushes
360                    ),
361                    suggestion: Some(
362                        "Consider using String::with_capacity() or format! macro".to_string(),
363                    ),
364                    impact: PerformanceImpact::Medium,
365                });
366            }
367        }
368
369        // Fallback: Check entire function content for string patterns if scope_map is empty
370        if !self.scope_map.contains_key(&function_node.id)
371            || self.scope_map.get(&function_node.id).unwrap().is_empty()
372        {
373            let mut push_str_count = 0;
374
375            for node in &self.nodes {
376                if matches!(node.kind, NodeKind::Call) && node.name.contains("push_str") {
377                    push_str_count += 1;
378                }
379            }
380
381            if push_str_count >= 3 {
382                issues.push(PerformanceIssue {
383                    issue_type: PerformanceIssueType::StringConcatenation,
384                    location: function_node.span.clone(),
385                    description: format!(
386                        "Multiple string operations detected: {} push_str calls",
387                        push_str_count
388                    ),
389                    suggestion: Some(
390                        "Consider using String::with_capacity() or format! macro".to_string(),
391                    ),
392                    impact: PerformanceImpact::Medium,
393                });
394            }
395        }
396
397        issues
398    }
399
400    /// Detect iterator chain inefficiencies
401    fn detect_iterator_inefficiencies(&self, function_node: &Node) -> Vec<PerformanceIssue> {
402        let mut issues = Vec::new();
403
404        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
405            for &node_id in scope_nodes {
406                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
407                    if matches!(call_node.kind, NodeKind::Call) {
408                        // Detect collect() followed by into_iter()
409                        if call_node.name.contains("collect") {
410                            issues.push(PerformanceIssue {
411                                issue_type: PerformanceIssueType::IteratorChains,
412                                location: call_node.span.clone(),
413                                description:
414                                    "collect() call may be unnecessary if chaining iterators"
415                                        .to_string(),
416                                suggestion: Some(
417                                    "Consider avoiding intermediate collection if possible"
418                                        .to_string(),
419                                ),
420                                impact: PerformanceImpact::Medium,
421                            });
422                        }
423                    }
424                }
425            }
426        }
427
428        issues
429    }
430
431    /// Detect collection usage inefficiencies
432    fn detect_collection_inefficiencies(&self, function_node: &Node) -> Vec<PerformanceIssue> {
433        let mut issues = Vec::new();
434
435        if let Some(signature) = &function_node.signature {
436            // Detect Vec<T> parameters when slice would work
437            if signature.contains("Vec<") && !signature.contains("&mut") {
438                issues.push(PerformanceIssue {
439                    issue_type: PerformanceIssueType::UnoptimizedCollections,
440                    location: function_node.span.clone(),
441                    description: "Function takes Vec<T> when &[T] slice might suffice".to_string(),
442                    suggestion: Some(
443                        "Consider using slice (&[T]) for read-only access".to_string(),
444                    ),
445                    impact: PerformanceImpact::Low,
446                });
447            }
448        }
449
450        issues
451    }
452
453    /// Analyze performance implications of specific calls
454    fn analyze_call_performance(&self, call_node: &Node) -> Vec<PerformanceIssue> {
455        let mut issues = Vec::new();
456
457        // Detect expensive operations
458        if call_node.name.contains("sort") && !call_node.name.contains("sort_unstable") {
459            issues.push(PerformanceIssue {
460                issue_type: PerformanceIssueType::SuboptimalAlgorithms,
461                location: call_node.span.clone(),
462                description: "Using stable sort when unstable sort might be sufficient".to_string(),
463                suggestion: Some(
464                    "Consider sort_unstable() for better performance if stability not required"
465                        .to_string(),
466                ),
467                impact: PerformanceImpact::Low,
468            });
469        }
470
471        issues
472    }
473
474    // Safety Analysis Methods
475
476    /// Check if a function is marked as unsafe
477    fn is_unsafe_function(&self, function_node: &Node) -> bool {
478        // Check function signature for unsafe keyword
479        if let Some(signature) = &function_node.signature {
480            if signature.contains("unsafe") {
481                return true;
482            }
483        }
484
485        // Check function name for unsafe
486        if function_node.name.contains("unsafe") {
487            return true;
488        }
489
490        // Check if it's a method with unsafe in metadata
491        if matches!(function_node.kind, NodeKind::Method) {
492            if let Some(metadata) = function_node.metadata.as_object() {
493                if let Some(unsafe_flag) = metadata.get("unsafe").and_then(|u| u.as_bool()) {
494                    if unsafe_flag {
495                        return true;
496                    }
497                }
498                if let Some(modifiers) = metadata.get("modifiers").and_then(|m| m.as_array()) {
499                    for modifier in modifiers {
500                        if let Some(mod_str) = modifier.as_str() {
501                            if mod_str == "unsafe" {
502                                return true;
503                            }
504                        }
505                    }
506                }
507            }
508        }
509
510        false
511    }
512
513    /// Analyze unsafe function usage
514    fn analyze_unsafe_function(&self, function_node: &Node) -> Vec<SafetyIssue> {
515        let mut issues = Vec::new();
516
517        issues.push(SafetyIssue {
518            issue_type: SafetyIssueType::UnsafeFunction,
519            location: function_node.span.clone(),
520            description: "Unsafe function requires careful review".to_string(),
521            rationale: None,
522            mitigation: Some(
523                "Document safety invariants and ensure all callers uphold them".to_string(),
524            ),
525            risk_level: RiskLevel::High,
526        });
527
528        // Check for common unsafe patterns in function scope
529        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
530            for &node_id in scope_nodes {
531                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
532                    if matches!(call_node.kind, NodeKind::Call) {
533                        // Raw pointer dereference
534                        if call_node.name.contains("*") && call_node.name.contains("raw") {
535                            issues.push(SafetyIssue {
536                                issue_type: SafetyIssueType::RawPointerDereference,
537                                location: call_node.span.clone(),
538                                description: "Raw pointer dereference detected".to_string(),
539                                rationale: None,
540                                mitigation: Some(
541                                    "Ensure pointer is valid and properly aligned".to_string(),
542                                ),
543                                risk_level: RiskLevel::Critical,
544                            });
545                        }
546                    }
547                }
548            }
549        }
550
551        issues
552    }
553
554    /// Detect FFI-related safety patterns
555    fn detect_ffi_patterns(&self, function_node: &Node) -> Vec<SafetyIssue> {
556        let mut issues = Vec::new();
557
558        // Check signature for FFI patterns
559        if let Some(signature) = &function_node.signature {
560            // Detect extern "C" functions
561            if signature.contains("extern") && signature.contains("\"C\"") {
562                issues.push(SafetyIssue {
563                    issue_type: SafetyIssueType::FFIBoundary,
564                    location: function_node.span.clone(),
565                    description: "FFI function boundary requires careful handling".to_string(),
566                    rationale: None,
567                    mitigation: Some(
568                        "Validate all parameters and handle C-style errors properly".to_string(),
569                    ),
570                    risk_level: RiskLevel::High,
571                });
572            }
573
574            // Detect CString usage (common in FFI)
575            if signature.contains("CString") || signature.contains("CStr") {
576                issues.push(SafetyIssue {
577                    issue_type: SafetyIssueType::FFIBoundary,
578                    location: function_node.span.clone(),
579                    description: "C string handling requires null termination validation"
580                        .to_string(),
581                    rationale: None,
582                    mitigation: Some(
583                        "Ensure proper null termination and UTF-8 validation".to_string(),
584                    ),
585                    risk_level: RiskLevel::Medium,
586                });
587            }
588
589            // Detect C-style raw pointers (common in FFI)
590            if signature.contains("*const") || signature.contains("*mut") {
591                // Look for typical FFI patterns
592                if signature.contains("i8")
593                    || signature.contains("c_char")
594                    || signature.contains("c_void")
595                {
596                    issues.push(SafetyIssue {
597                        issue_type: SafetyIssueType::FFIBoundary,
598                        location: function_node.span.clone(),
599                        description: "Function uses C-style raw pointers typical of FFI"
600                            .to_string(),
601                        rationale: None,
602                        mitigation: Some(
603                            "Validate pointer parameters and handle null pointers safely"
604                                .to_string(),
605                        ),
606                        risk_level: RiskLevel::High,
607                    });
608                }
609            }
610        }
611
612        // Check metadata for FFI information
613        if let Some(metadata) = function_node.metadata.as_object() {
614            if let Some(function_type) = metadata.get("function_type").and_then(|t| t.as_str()) {
615                if function_type == "extern" {
616                    issues.push(SafetyIssue {
617                        issue_type: SafetyIssueType::FFIBoundary,
618                        location: function_node.span.clone(),
619                        description: "Extern function requires FFI safety considerations"
620                            .to_string(),
621                        rationale: None,
622                        mitigation: Some(
623                            "Ensure proper parameter validation and error handling".to_string(),
624                        ),
625                        risk_level: RiskLevel::High,
626                    });
627                }
628            }
629        }
630
631        // Check for uses of CString/CStr in the function scope
632        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
633            for &node_id in scope_nodes {
634                if let Some(use_node) = self.nodes.iter().find(|n| n.id == node_id) {
635                    if matches!(use_node.kind, NodeKind::Use)
636                        && (use_node.name.contains("CString") || use_node.name.contains("CStr"))
637                    {
638                        issues.push(SafetyIssue {
639                            issue_type: SafetyIssueType::FFIBoundary,
640                            location: use_node.span.clone(),
641                            description: "C string types used - typical of FFI code".to_string(),
642                            rationale: None,
643                            mitigation: Some(
644                                "Ensure proper null termination and UTF-8 validation".to_string(),
645                            ),
646                            risk_level: RiskLevel::Medium,
647                        });
648                    }
649                }
650            }
651        }
652
653        issues
654    }
655
656    /// Detect memory safety issues
657    fn detect_memory_safety_issues(&self, function_node: &Node) -> Vec<SafetyIssue> {
658        let mut issues = Vec::new();
659
660        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
661            for &node_id in scope_nodes {
662                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
663                    if matches!(call_node.kind, NodeKind::Call) {
664                        // Memory allocation/deallocation
665                        if call_node.name.contains("alloc") || call_node.name.contains("dealloc") {
666                            issues.push(SafetyIssue {
667                                issue_type: SafetyIssueType::ManualMemoryManagement,
668                                location: call_node.span.clone(),
669                                description: "Manual memory management detected".to_string(),
670                                rationale: None,
671                                mitigation: Some("Ensure matching allocation/deallocation and consider RAII patterns".to_string()),
672                                risk_level: RiskLevel::High,
673                            });
674                        }
675
676                        // Transmute usage
677                        if call_node.name.contains("transmute") {
678                            issues.push(SafetyIssue {
679                                issue_type: SafetyIssueType::TypeTransmutation,
680                                location: call_node.span.clone(),
681                                description: "Type transmutation is extremely dangerous".to_string(),
682                                rationale: None,
683                                mitigation: Some("Validate size and alignment requirements, consider safer alternatives".to_string()),
684                                risk_level: RiskLevel::Critical,
685                            });
686                        }
687                    }
688                }
689            }
690        }
691
692        // Fallback: Check for transmute calls globally if scope_map is empty
693        if !self.scope_map.contains_key(&function_node.id)
694            || self.scope_map.get(&function_node.id).unwrap().is_empty()
695        {
696            for node in &self.nodes {
697                if matches!(node.kind, NodeKind::Call) && node.name.contains("transmute") {
698                    issues.push(SafetyIssue {
699                        issue_type: SafetyIssueType::TypeTransmutation,
700                        location: function_node.span.clone(),
701                        description: "Type transmutation is extremely dangerous".to_string(),
702                        rationale: None,
703                        mitigation: Some(
704                            "Validate size and alignment requirements, consider safer alternatives"
705                                .to_string(),
706                        ),
707                        risk_level: RiskLevel::Critical,
708                    });
709                }
710            }
711        }
712
713        issues
714    }
715
716    // Concurrency Analysis Methods
717
718    /// Analyze async/await usage patterns
719    fn analyze_async_patterns(&self, function_node: &Node) -> Vec<ConcurrencyIssue> {
720        let mut issues = Vec::new();
721
722        if let Some(signature) = &function_node.signature {
723            if signature.contains("async") {
724                // Check for blocking operations in async functions
725                if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
726                    for &node_id in scope_nodes {
727                        if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
728                            if matches!(call_node.kind, NodeKind::Call) {
729                                // Blocking operations
730                                if call_node.name.contains("block_on")
731                                    || call_node.name.contains("wait")
732                                {
733                                    issues.push(ConcurrencyIssue {
734                                        issue_type: ConcurrencyIssueType::AsyncAntipattern,
735                                        location: call_node.span.clone(),
736                                        description: "Blocking operation in async function".to_string(),
737                                        suggestion: Some("Use async alternatives or spawn_blocking for CPU-bound work".to_string()),
738                                        severity: ConcurrencySeverity::High,
739                                    });
740                                }
741
742                                // Missing .await
743                                if call_node.name.contains("async")
744                                    && !call_node.name.contains(".await")
745                                {
746                                    issues.push(ConcurrencyIssue {
747                                        issue_type: ConcurrencyIssueType::MissingAwait,
748                                        location: call_node.span.clone(),
749                                        description: "Async call without .await".to_string(),
750                                        suggestion: Some(
751                                            "Add .await to async function call".to_string(),
752                                        ),
753                                        severity: ConcurrencySeverity::High,
754                                    });
755                                }
756                            }
757                        }
758                    }
759                }
760            }
761        }
762
763        issues
764    }
765
766    /// Detect potential deadlock situations
767    fn detect_deadlock_potential(&self, function_node: &Node) -> Vec<ConcurrencyIssue> {
768        let mut issues = Vec::new();
769
770        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
771            let mut mutex_calls = Vec::new();
772
773            for &node_id in scope_nodes {
774                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
775                    if matches!(call_node.kind, NodeKind::Call) && call_node.name.contains("lock") {
776                        mutex_calls.push(call_node);
777                    }
778                }
779            }
780
781            // Multiple mutex locks in same function
782            if mutex_calls.len() > 1 {
783                issues.push(ConcurrencyIssue {
784                    issue_type: ConcurrencyIssueType::DeadlockPotential,
785                    location: function_node.span.clone(),
786                    description: format!(
787                        "Function acquires {} locks, potential deadlock risk",
788                        mutex_calls.len()
789                    ),
790                    suggestion: Some(
791                        "Ensure consistent lock ordering or use try_lock with timeouts".to_string(),
792                    ),
793                    severity: ConcurrencySeverity::High,
794                });
795            }
796        }
797
798        // Fallback: Check for multiple lock calls globally if scope_map is empty
799        if !self.scope_map.contains_key(&function_node.id)
800            || self.scope_map.get(&function_node.id).unwrap().is_empty()
801        {
802            let lock_calls: Vec<&Node> = self
803                .nodes
804                .iter()
805                .filter(|n| matches!(n.kind, NodeKind::Call) && n.name.contains("lock"))
806                .collect();
807
808            if lock_calls.len() > 1 {
809                issues.push(ConcurrencyIssue {
810                    issue_type: ConcurrencyIssueType::DeadlockPotential,
811                    location: function_node.span.clone(),
812                    description: format!(
813                        "Multiple mutex locks detected ({}), potential deadlock risk",
814                        lock_calls.len()
815                    ),
816                    suggestion: Some(
817                        "Ensure consistent lock ordering or use try_lock with timeouts".to_string(),
818                    ),
819                    severity: ConcurrencySeverity::High,
820                });
821            }
822        }
823
824        issues
825    }
826
827    /// Analyze thread safety patterns
828    fn analyze_thread_safety(&self, function_node: &Node) -> Vec<ConcurrencyIssue> {
829        let mut issues = Vec::new();
830
831        // Check for non-Send/Sync types in function signature
832        if let Some(signature) = &function_node.signature {
833            // This is a simplified check - in practice, would need type resolution
834            if signature.contains("Rc<") || signature.contains("RefCell<") {
835                issues.push(ConcurrencyIssue {
836                    issue_type: ConcurrencyIssueType::ThreadSafetyViolation,
837                    location: function_node.span.clone(),
838                    description: "Function uses non-thread-safe types (Rc, RefCell)".to_string(),
839                    suggestion: Some(
840                        "Consider Arc and Mutex for thread-safe alternatives".to_string(),
841                    ),
842                    severity: ConcurrencySeverity::Medium,
843                });
844            }
845        }
846
847        // Check for non-thread-safe types used within the function scope
848        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
849            for &node_id in scope_nodes {
850                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
851                    if matches!(call_node.kind, NodeKind::Call) {
852                        // Detect Rc::new or RefCell::new calls
853                        if call_node.name.contains("Rc::new")
854                            || call_node.name.contains("RefCell::new")
855                        {
856                            issues.push(ConcurrencyIssue {
857                                issue_type: ConcurrencyIssueType::ThreadSafetyViolation,
858                                location: call_node.span.clone(),
859                                description: "Non-thread-safe type used (Rc/RefCell)".to_string(),
860                                suggestion: Some(
861                                    "Consider Arc and Mutex for thread-safe alternatives"
862                                        .to_string(),
863                                ),
864                                severity: ConcurrencySeverity::Medium,
865                            });
866                        }
867                    }
868                }
869            }
870        }
871
872        // Also check if function scope uses non-thread-safe types from use statements
873        for use_node in &self.nodes {
874            if matches!(use_node.kind, NodeKind::Use)
875                && (use_node.name.contains("std::rc::Rc")
876                    || use_node.name.contains("std::cell::RefCell"))
877            {
878                // If this use is in the same module as the function, it's a potential issue
879                issues.push(ConcurrencyIssue {
880                    issue_type: ConcurrencyIssueType::ThreadSafetyViolation,
881                    location: function_node.span.clone(),
882                    description: "Module imports non-thread-safe types (Rc, RefCell)".to_string(),
883                    suggestion: Some(
884                        "Consider Arc and Mutex for thread-safe alternatives".to_string(),
885                    ),
886                    severity: ConcurrencySeverity::Low,
887                });
888            }
889        }
890
891        issues
892    }
893
894    /// Analyze channel usage patterns
895    fn analyze_channel_usage(&self, function_node: &Node) -> Vec<ConcurrencyIssue> {
896        let mut issues = Vec::new();
897
898        if let Some(scope_nodes) = self.scope_map.get(&function_node.id) {
899            for &node_id in scope_nodes {
900                if let Some(call_node) = self.nodes.iter().find(|n| n.id == node_id) {
901                    if matches!(call_node.kind, NodeKind::Call) {
902                        // Unbounded channel creation
903                        if call_node.name.contains("unbounded") {
904                            issues.push(ConcurrencyIssue {
905                                issue_type: ConcurrencyIssueType::UnboundedChannel,
906                                location: call_node.span.clone(),
907                                description: "Unbounded channel can lead to memory growth"
908                                    .to_string(),
909                                suggestion: Some(
910                                    "Consider bounded channels with appropriate capacity"
911                                        .to_string(),
912                                ),
913                                severity: ConcurrencySeverity::Medium,
914                            });
915                        }
916                    }
917                }
918            }
919        }
920
921        issues
922    }
923
924    /// Analyze Send/Sync trait implementations for types
925    fn analyze_send_sync_traits(&self, type_node: &Node) -> Vec<ConcurrencyIssue> {
926        let mut issues = Vec::new();
927
928        // Look for manual Send/Sync implementations
929        let type_name = &type_node.name;
930        for node in &self.nodes {
931            if matches!(node.kind, NodeKind::Impl)
932                && node.name.contains(type_name)
933                && (node.name.contains("Send") || node.name.contains("Sync"))
934            {
935                issues.push(ConcurrencyIssue {
936                    issue_type: ConcurrencyIssueType::ManualSendSync,
937                    location: node.span.clone(),
938                    description: "Manual Send/Sync implementation requires careful review"
939                        .to_string(),
940                    suggestion: Some("Ensure thread safety guarantees are maintained".to_string()),
941                    severity: ConcurrencySeverity::High,
942                });
943            }
944        }
945
946        issues
947    }
948
949    /// Analyze trait implementations
950    pub fn analyze_trait_implementations(&self) -> Vec<TraitImplementation> {
951        let mut implementations = Vec::new();
952
953        for node in &self.nodes {
954            if matches!(node.kind, NodeKind::Impl) {
955                // Parse impl name to extract trait and type information
956                if node.name.contains(" for ") {
957                    let parts: Vec<&str> = node.name.split(" for ").collect();
958                    if parts.len() == 2 {
959                        implementations.push(TraitImplementation {
960                            trait_name: parts[0].to_string(),
961                            type_name: parts[1].to_string(),
962                            impl_node: node.clone(),
963                        });
964                    }
965                }
966            }
967        }
968
969        implementations
970    }
971
972    /// Analyze unsafe code usage
973    pub fn analyze_unsafe_usage(&self) -> Vec<UnsafeUsage> {
974        let mut unsafe_usages = Vec::new();
975
976        for node in &self.nodes {
977            if matches!(node.kind, NodeKind::Function | NodeKind::Method) {
978                if let Some(signature) = &node.signature {
979                    if signature.contains("unsafe") {
980                        unsafe_usages.push(UnsafeUsage {
981                            location: node.span.clone(),
982                            usage_type: UnsafeType::Function,
983                            description: format!("Unsafe function: {}", node.name),
984                        });
985                    }
986                }
987            }
988        }
989
990        unsafe_usages
991    }
992
993    /// Analyze lifetime usage
994    pub fn analyze_lifetime_usage(&self) -> Vec<LifetimeUsage> {
995        let mut lifetime_usages = Vec::new();
996
997        for node in &self.nodes {
998            if matches!(node.kind, NodeKind::Lifetime) {
999                lifetime_usages.push(LifetimeUsage {
1000                    name: node.name.clone(),
1001                    location: node.span.clone(),
1002                    scope: self.find_lifetime_scope(node),
1003                });
1004            }
1005        }
1006
1007        lifetime_usages
1008    }
1009
1010    /// Find all macros used in the code
1011    pub fn analyze_macro_usage(&self) -> Vec<MacroUsage> {
1012        let mut macro_usages = Vec::new();
1013
1014        for node in &self.nodes {
1015            if matches!(node.kind, NodeKind::Call) && node.name.ends_with('!') {
1016                macro_usages.push(MacroUsage {
1017                    name: node.name.clone(),
1018                    location: node.span.clone(),
1019                    macro_type: MacroType::Invocation,
1020                });
1021            }
1022        }
1023
1024        macro_usages
1025    }
1026
1027    /// Find the scope of a lifetime parameter
1028    fn find_lifetime_scope(&self, _lifetime_node: &Node) -> LifetimeScope {
1029        // Placeholder - would analyze where the lifetime is used
1030        LifetimeScope::Function
1031    }
1032}
1033
1034// Result Types
1035
1036/// Comprehensive Rust analysis result
1037#[derive(Debug, Clone)]
1038pub struct RustAnalysisResult {
1039    pub ownership_patterns: Vec<OwnershipPattern>,
1040    pub performance_issues: Vec<PerformanceIssue>,
1041    pub safety_issues: Vec<SafetyIssue>,
1042    pub concurrency_issues: Vec<ConcurrencyIssue>,
1043    pub trait_implementations: Vec<TraitImplementation>,
1044    pub unsafe_usage: Vec<UnsafeUsage>,
1045    pub lifetime_usage: Vec<LifetimeUsage>,
1046    pub macro_usage: Vec<MacroUsage>,
1047}
1048
1049/// Represents an ownership pattern found in the code
1050#[derive(Debug, Clone)]
1051pub struct OwnershipPattern {
1052    pub pattern_type: OwnershipPatternType,
1053    pub location: Span,
1054    pub description: String,
1055    pub suggestion: Option<String>,
1056    pub severity: Severity,
1057}
1058
1059/// Types of ownership patterns
1060#[derive(Debug, Clone)]
1061pub enum OwnershipPatternType {
1062    UnnecessaryClone,
1063    InefficientBorrowing,
1064    PotentialMoveError,
1065    OptimalOwnership,
1066    UnnecessaryOwned,
1067    MultipleMutableBorrows,
1068    InconsistentNaming,
1069}
1070
1071/// Performance issue found in the code
1072#[derive(Debug, Clone)]
1073pub struct PerformanceIssue {
1074    pub issue_type: PerformanceIssueType,
1075    pub location: Span,
1076    pub description: String,
1077    pub suggestion: Option<String>,
1078    pub impact: PerformanceImpact,
1079}
1080
1081/// Types of performance issues
1082#[derive(Debug, Clone)]
1083pub enum PerformanceIssueType {
1084    FrequentAllocations,
1085    StringConcatenation,
1086    IteratorChains,
1087    UnoptimizedCollections,
1088    SuboptimalAlgorithms,
1089}
1090
1091/// Performance impact levels
1092#[derive(Debug, Clone)]
1093pub enum PerformanceImpact {
1094    Low,
1095    Medium,
1096    High,
1097    Critical,
1098}
1099
1100/// Safety issue found in the code
1101#[derive(Debug, Clone)]
1102pub struct SafetyIssue {
1103    pub issue_type: SafetyIssueType,
1104    pub location: Span,
1105    pub description: String,
1106    pub rationale: Option<String>,
1107    pub mitigation: Option<String>,
1108    pub risk_level: RiskLevel,
1109}
1110
1111/// Types of safety issues
1112#[derive(Debug, Clone)]
1113pub enum SafetyIssueType {
1114    UnsafeFunction,
1115    RawPointerDereference,
1116    FFIBoundary,
1117    ManualMemoryManagement,
1118    TypeTransmutation,
1119}
1120
1121/// Risk levels for safety issues
1122#[derive(Debug, Clone)]
1123pub enum RiskLevel {
1124    Low,
1125    Medium,
1126    High,
1127    Critical,
1128}
1129
1130/// Concurrency issue found in the code
1131#[derive(Debug, Clone)]
1132pub struct ConcurrencyIssue {
1133    pub issue_type: ConcurrencyIssueType,
1134    pub location: Span,
1135    pub description: String,
1136    pub suggestion: Option<String>,
1137    pub severity: ConcurrencySeverity,
1138}
1139
1140/// Types of concurrency issues
1141#[derive(Debug, Clone)]
1142pub enum ConcurrencyIssueType {
1143    AsyncAntipattern,
1144    MissingAwait,
1145    DeadlockPotential,
1146    ThreadSafetyViolation,
1147    UnboundedChannel,
1148    ManualSendSync,
1149}
1150
1151/// Severity levels for concurrency issues
1152#[derive(Debug, Clone)]
1153pub enum ConcurrencySeverity {
1154    Low,
1155    Medium,
1156    High,
1157    Critical,
1158}
1159
1160/// General severity levels
1161#[derive(Debug, Clone)]
1162pub enum Severity {
1163    Low,
1164    Medium,
1165    High,
1166    Critical,
1167}
1168
1169/// Represents a trait implementation
1170#[derive(Debug, Clone)]
1171pub struct TraitImplementation {
1172    pub trait_name: String,
1173    pub type_name: String,
1174    pub impl_node: Node,
1175}
1176
1177/// Represents unsafe code usage
1178#[derive(Debug, Clone)]
1179pub struct UnsafeUsage {
1180    pub location: Span,
1181    pub usage_type: UnsafeType,
1182    pub description: String,
1183}
1184
1185/// Types of unsafe code usage
1186#[derive(Debug, Clone)]
1187pub enum UnsafeType {
1188    Function,
1189    Block,
1190    Trait,
1191    Impl,
1192}
1193
1194/// Represents lifetime usage in the code
1195#[derive(Debug, Clone)]
1196pub struct LifetimeUsage {
1197    pub name: String,
1198    pub location: Span,
1199    pub scope: LifetimeScope,
1200}
1201
1202/// Scope where a lifetime is used
1203#[derive(Debug, Clone)]
1204pub enum LifetimeScope {
1205    Function,
1206    Struct,
1207    Trait,
1208    Impl,
1209}
1210
1211/// Represents macro usage
1212#[derive(Debug, Clone)]
1213pub struct MacroUsage {
1214    pub name: String,
1215    pub location: Span,
1216    pub macro_type: MacroType,
1217}
1218
1219/// Types of macro usage
1220#[derive(Debug, Clone)]
1221pub enum MacroType {
1222    Definition,
1223    Invocation,
1224}