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