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<_> = func
66            .parameters()
67            .iter()
68            .filter(|p| self.is_void_ptr(p.param_type()))
69            .collect();
70
71        if void_ptr_params.is_empty() {
72            return results;
73        }
74
75        // Detect pattern based on function signature
76        let pattern = self.detect_pattern(func, &void_ptr_params);
77
78        // Analyze each void* parameter
79        for param in void_ptr_params {
80            let mut info = VoidPtrInfo {
81                param_name: param.name().to_string(),
82                pattern: pattern.clone(),
83                inferred_types: Vec::new(),
84                constraints: Vec::new(),
85            };
86
87            // Analyze body for type casts and usage
88            self.analyze_body(func.body(), param.name(), &mut info);
89
90            results.push(info);
91        }
92
93        results
94    }
95
96    fn is_void_ptr(&self, ty: &HirType) -> bool {
97        matches!(ty, HirType::Pointer(inner) if matches!(inner.as_ref(), HirType::Void))
98    }
99
100    fn detect_pattern(
101        &self,
102        func: &HirFunction,
103        void_params: &[&decy_hir::HirParameter],
104    ) -> VoidPtrPattern {
105        let param_count = void_params.len();
106        let has_size_param = func
107            .parameters()
108            .iter()
109            .any(|p| p.name().contains("size") || p.name() == "n" || p.name() == "len");
110        let returns_int = matches!(func.return_type(), HirType::Int);
111
112        // Swap pattern: two void* + size
113        if param_count == 2 && has_size_param && func.name() == "swap" {
114            return VoidPtrPattern::Swap;
115        }
116
117        // Compare pattern: two void* returning int
118        if param_count == 2
119            && returns_int
120            && (func.name().contains("cmp") || func.name() == "compare")
121        {
122            return VoidPtrPattern::Compare;
123        }
124
125        // Copy pattern: dest + src + size
126        if param_count == 2 && has_size_param {
127            let names: Vec<&str> = void_params.iter().map(|p| p.name()).collect();
128            if names.contains(&"dest") || names.contains(&"src") || func.name().contains("copy") {
129                return VoidPtrPattern::Copy;
130            }
131        }
132
133        VoidPtrPattern::Generic
134    }
135
136    fn analyze_body(&self, stmts: &[HirStatement], param_name: &str, info: &mut VoidPtrInfo) {
137        for stmt in stmts {
138            self.analyze_statement(stmt, param_name, info);
139        }
140    }
141
142    fn analyze_statement(&self, stmt: &HirStatement, param_name: &str, info: &mut VoidPtrInfo) {
143        match stmt {
144            HirStatement::VariableDeclaration {
145                initializer: Some(init),
146                ..
147            } => {
148                self.analyze_expression(init, param_name, info);
149            }
150            HirStatement::DerefAssignment { target, value } => {
151                // Write through void* - implies mutable constraint
152                if self.expr_uses_param(target, param_name)
153                    && !info.constraints.contains(&TypeConstraint::Mutable)
154                {
155                    info.constraints.push(TypeConstraint::Mutable);
156                }
157                // DECY-097: If value is a dereference of a void* param, need Clone
158                if matches!(value, HirExpression::Dereference(_))
159                    && !info.constraints.contains(&TypeConstraint::Clone)
160                {
161                    info.constraints.push(TypeConstraint::Clone);
162                }
163                self.analyze_expression(target, param_name, info);
164                self.analyze_expression(value, param_name, info);
165            }
166            HirStatement::If {
167                condition,
168                then_block,
169                else_block,
170                ..
171            } => {
172                self.analyze_expression(condition, param_name, info);
173                self.analyze_body(then_block, param_name, info);
174                if let Some(else_stmts) = else_block {
175                    self.analyze_body(else_stmts, param_name, info);
176                }
177            }
178            HirStatement::While {
179                condition, body, ..
180            } => {
181                self.analyze_expression(condition, param_name, info);
182                self.analyze_body(body, param_name, info);
183            }
184            HirStatement::For { body, .. } => {
185                self.analyze_body(body, param_name, info);
186            }
187            HirStatement::Expression(expr) => {
188                self.analyze_expression(expr, param_name, info);
189            }
190            HirStatement::Return(Some(expr)) => {
191                self.analyze_expression(expr, param_name, info);
192            }
193            _ => {}
194        }
195    }
196
197    fn analyze_expression(&self, expr: &HirExpression, param_name: &str, info: &mut VoidPtrInfo) {
198        match expr {
199            HirExpression::Cast {
200                expr: inner,
201                target_type,
202            } => {
203                // Found a cast - extract the type
204                if self.expr_uses_param(inner, param_name) {
205                    if let HirType::Pointer(inner_type) = target_type {
206                        if !info.inferred_types.contains(inner_type) {
207                            info.inferred_types.push((**inner_type).clone());
208                        }
209                    }
210                }
211            }
212            HirExpression::BinaryOp { op, left, right } => {
213                // DECY-097: Detect comparison/equality operations for trait bounds
214                let uses_param = self.expr_uses_param(left, param_name)
215                    || self.expr_uses_param(right, param_name);
216                if uses_param {
217                    use decy_hir::BinaryOperator;
218                    match op {
219                        BinaryOperator::LessThan
220                        | BinaryOperator::GreaterThan
221                        | BinaryOperator::LessEqual
222                        | BinaryOperator::GreaterEqual => {
223                            if !info.constraints.contains(&TypeConstraint::PartialOrd) {
224                                info.constraints.push(TypeConstraint::PartialOrd);
225                            }
226                        }
227                        BinaryOperator::Equal | BinaryOperator::NotEqual => {
228                            if !info.constraints.contains(&TypeConstraint::PartialEq) {
229                                info.constraints.push(TypeConstraint::PartialEq);
230                            }
231                        }
232                        _ => {}
233                    }
234                }
235                self.analyze_expression(left, param_name, info);
236                self.analyze_expression(right, param_name, info);
237            }
238            HirExpression::Dereference(inner) => {
239                self.analyze_expression(inner, param_name, info);
240            }
241            HirExpression::FunctionCall { arguments, .. } => {
242                for arg in arguments {
243                    self.analyze_expression(arg, param_name, info);
244                }
245            }
246            _ => {}
247        }
248    }
249
250    fn expr_uses_param(&self, expr: &HirExpression, param_name: &str) -> bool {
251        match expr {
252            HirExpression::Variable(name) => name == param_name,
253            HirExpression::Cast { expr: inner, .. } => self.expr_uses_param(inner, param_name),
254            HirExpression::Dereference(inner) => self.expr_uses_param(inner, param_name),
255            _ => false,
256        }
257    }
258}
259
260impl Default for VoidPtrAnalyzer {
261    fn default() -> Self {
262        Self::new()
263    }
264}