Skip to main content

decy_analyzer/
void_ptr_analysis.rs

1//! Void pointer analysis for generic type inference.
2//!
3//! Analyzes void* usage patterns to infer generic type parameters
4//! for transformation to Rust generics.
5
6use decy_hir::{HirExpression, HirFunction, HirStatement, HirType};
7
8/// Pattern type detected for void* usage.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum VoidPtrPattern {
11    /// Generic data pointer (unknown pattern)
12    Generic,
13    /// Swap pattern: two void* + size parameter
14    Swap,
15    /// Compare pattern: two void* returning int
16    Compare,
17    /// Copy pattern: dest void* + src void* + size
18    Copy,
19}
20
21/// Type constraint inferred from void* usage.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum TypeConstraint {
24    /// Must be readable (shared reference)
25    Readable,
26    /// Must be mutable (exclusive reference)
27    Mutable,
28    /// Must implement Copy (for memcpy-style operations)
29    Copy,
30    /// Must implement Clone
31    Clone,
32    /// Must implement PartialOrd (for compare operations)
33    PartialOrd,
34    /// Must implement PartialEq (for equality comparisons)
35    PartialEq,
36}
37
38/// Analysis result for a void* parameter.
39#[derive(Debug, Clone)]
40pub struct VoidPtrInfo {
41    /// Parameter name
42    pub param_name: String,
43    /// Detected pattern
44    pub pattern: VoidPtrPattern,
45    /// Inferred concrete types from casts
46    pub inferred_types: Vec<HirType>,
47    /// Type constraints from usage
48    pub constraints: Vec<TypeConstraint>,
49}
50
51/// Analyzer for void* usage patterns.
52pub struct VoidPtrAnalyzer;
53
54impl VoidPtrAnalyzer {
55    /// Create a new void pointer analyzer.
56    pub fn new() -> Self {
57        Self
58    }
59
60    /// Analyze a function for void* usage patterns.
61    pub fn analyze(&self, func: &HirFunction) -> Vec<VoidPtrInfo> {
62        let mut results = Vec::new();
63
64        // Find void* parameters
65        let void_ptr_params: Vec<_> =
66            func.parameters().iter().filter(|p| self.is_void_ptr(p.param_type())).collect();
67
68        if void_ptr_params.is_empty() {
69            return results;
70        }
71
72        // Detect pattern based on function signature
73        let pattern = self.detect_pattern(func, &void_ptr_params);
74
75        // Analyze each void* parameter
76        for param in void_ptr_params {
77            let mut info = VoidPtrInfo {
78                param_name: param.name().to_string(),
79                pattern: pattern.clone(),
80                inferred_types: Vec::new(),
81                constraints: Vec::new(),
82            };
83
84            // Analyze body for type casts and usage
85            self.analyze_body(func.body(), param.name(), &mut info);
86
87            results.push(info);
88        }
89
90        results
91    }
92
93    fn is_void_ptr(&self, ty: &HirType) -> bool {
94        matches!(ty, HirType::Pointer(inner) if matches!(inner.as_ref(), HirType::Void))
95    }
96
97    fn detect_pattern(
98        &self,
99        func: &HirFunction,
100        void_params: &[&decy_hir::HirParameter],
101    ) -> VoidPtrPattern {
102        let param_count = void_params.len();
103        let has_size_param = func
104            .parameters()
105            .iter()
106            .any(|p| p.name().contains("size") || p.name() == "n" || p.name() == "len");
107        let returns_int = matches!(func.return_type(), HirType::Int);
108
109        // Swap pattern: two void* + size
110        if param_count == 2 && has_size_param && func.name() == "swap" {
111            return VoidPtrPattern::Swap;
112        }
113
114        // Compare pattern: two void* returning int
115        if param_count == 2
116            && returns_int
117            && (func.name().contains("cmp") || func.name() == "compare")
118        {
119            return VoidPtrPattern::Compare;
120        }
121
122        // Copy pattern: dest + src + size
123        if param_count == 2 && has_size_param {
124            let names: Vec<&str> = void_params.iter().map(|p| p.name()).collect();
125            if names.contains(&"dest") || names.contains(&"src") || func.name().contains("copy") {
126                return VoidPtrPattern::Copy;
127            }
128        }
129
130        VoidPtrPattern::Generic
131    }
132
133    fn analyze_body(&self, stmts: &[HirStatement], param_name: &str, info: &mut VoidPtrInfo) {
134        for stmt in stmts {
135            self.analyze_statement(stmt, param_name, info);
136        }
137    }
138
139    fn analyze_statement(&self, stmt: &HirStatement, param_name: &str, info: &mut VoidPtrInfo) {
140        match stmt {
141            HirStatement::VariableDeclaration { initializer: Some(init), .. } => {
142                self.analyze_expression(init, param_name, info);
143            }
144            HirStatement::DerefAssignment { target, value } => {
145                // Write through void* - implies mutable constraint
146                if self.expr_uses_param(target, param_name)
147                    && !info.constraints.contains(&TypeConstraint::Mutable)
148                {
149                    info.constraints.push(TypeConstraint::Mutable);
150                }
151                // DECY-097: If value is a dereference of a void* param, need Clone
152                if matches!(value, HirExpression::Dereference(_))
153                    && !info.constraints.contains(&TypeConstraint::Clone)
154                {
155                    info.constraints.push(TypeConstraint::Clone);
156                }
157                self.analyze_expression(target, param_name, info);
158                self.analyze_expression(value, param_name, info);
159            }
160            HirStatement::If { condition, then_block, else_block, .. } => {
161                self.analyze_expression(condition, param_name, info);
162                self.analyze_body(then_block, param_name, info);
163                if let Some(else_stmts) = else_block {
164                    self.analyze_body(else_stmts, param_name, info);
165                }
166            }
167            HirStatement::While { condition, body, .. } => {
168                self.analyze_expression(condition, param_name, info);
169                self.analyze_body(body, param_name, info);
170            }
171            HirStatement::For { body, .. } => {
172                self.analyze_body(body, param_name, info);
173            }
174            HirStatement::Expression(expr) => {
175                self.analyze_expression(expr, param_name, info);
176            }
177            HirStatement::Return(Some(expr)) => {
178                self.analyze_expression(expr, param_name, info);
179            }
180            _ => {}
181        }
182    }
183
184    fn analyze_expression(&self, expr: &HirExpression, param_name: &str, info: &mut VoidPtrInfo) {
185        match expr {
186            HirExpression::Cast { expr: inner, target_type } => {
187                // Found a cast - extract the type
188                if self.expr_uses_param(inner, param_name) {
189                    if let HirType::Pointer(inner_type) = target_type {
190                        if !info.inferred_types.contains(inner_type) {
191                            info.inferred_types.push((**inner_type).clone());
192                        }
193                    }
194                }
195            }
196            HirExpression::BinaryOp { op, left, right } => {
197                // DECY-097: Detect comparison/equality operations for trait bounds
198                let uses_param = self.expr_uses_param(left, param_name)
199                    || self.expr_uses_param(right, param_name);
200                if uses_param {
201                    use decy_hir::BinaryOperator;
202                    match op {
203                        BinaryOperator::LessThan
204                        | BinaryOperator::GreaterThan
205                        | BinaryOperator::LessEqual
206                        | BinaryOperator::GreaterEqual => {
207                            if !info.constraints.contains(&TypeConstraint::PartialOrd) {
208                                info.constraints.push(TypeConstraint::PartialOrd);
209                            }
210                        }
211                        BinaryOperator::Equal | BinaryOperator::NotEqual => {
212                            if !info.constraints.contains(&TypeConstraint::PartialEq) {
213                                info.constraints.push(TypeConstraint::PartialEq);
214                            }
215                        }
216                        _ => {}
217                    }
218                }
219                self.analyze_expression(left, param_name, info);
220                self.analyze_expression(right, param_name, info);
221            }
222            HirExpression::Dereference(inner) => {
223                self.analyze_expression(inner, param_name, info);
224            }
225            HirExpression::FunctionCall { arguments, .. } => {
226                for arg in arguments {
227                    self.analyze_expression(arg, param_name, info);
228                }
229            }
230            _ => {}
231        }
232    }
233
234    fn expr_uses_param(&self, expr: &HirExpression, param_name: &str) -> bool {
235        match expr {
236            HirExpression::Variable(name) => name == param_name,
237            HirExpression::Cast { expr: inner, .. } => self.expr_uses_param(inner, param_name),
238            HirExpression::Dereference(inner) => self.expr_uses_param(inner, param_name),
239            _ => false,
240        }
241    }
242}
243
244impl Default for VoidPtrAnalyzer {
245    fn default() -> Self {
246        Self::new()
247    }
248}