Skip to main content

decy_codegen/
transform_gen.rs

1//! Transform code generation: annotated signatures, box/vec transforms.
2//! Split from func_gen.rs for PMAT File Health compliance.
3
4use super::*;
5use decy_hir::HirStatement;
6use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedType};
7
8impl CodeGenerator {
9    /// Generate a function signature with lifetime annotations.
10    ///
11    /// Takes an `AnnotatedSignature` with lifetime information and generates
12    /// the complete Rust function signature including lifetime parameters.
13    ///
14    /// # Examples
15    ///
16    /// ```
17    /// use decy_codegen::CodeGenerator;
18    /// use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedParameter, AnnotatedType, LifetimeParam};
19    /// use decy_hir::HirType;
20    ///
21    /// let sig = AnnotatedSignature {
22    ///     name: "get_first".to_string(),
23    ///     lifetimes: vec![LifetimeParam::standard(0)], // 'a
24    ///     parameters: vec![
25    ///         AnnotatedParameter {
26    ///             name: "items".to_string(),
27    ///             param_type: AnnotatedType::Reference {
28    ///                 inner: Box::new(AnnotatedType::Simple(HirType::Int)),
29    ///                 mutable: false,
30    ///                 lifetime: Some(LifetimeParam::standard(0)),
31    ///             },
32    ///         },
33    ///     ],
34    ///     return_type: AnnotatedType::Reference {
35    ///         inner: Box::new(AnnotatedType::Simple(HirType::Int)),
36    ///         mutable: false,
37    ///         lifetime: Some(LifetimeParam::standard(0)),
38    ///     },
39    /// };
40    ///
41    /// let codegen = CodeGenerator::new();
42    /// let rust_sig = codegen.generate_annotated_signature(&sig);
43    ///
44    /// assert!(rust_sig.contains("<'a>"));
45    /// assert!(rust_sig.contains("&'a i32"));
46    /// ```
47    pub fn generate_annotated_signature(&self, sig: &AnnotatedSignature) -> String {
48        self.generate_annotated_signature_with_func(sig, None)
49    }
50
51    /// Generate a function signature from an annotated signature with optional function body access.
52    ///
53    /// When `func` is provided, pointer arithmetic detection is enabled (DECY-123).
54    /// DECY-084: Also detects output parameters for transformation to return values.
55    pub fn generate_annotated_signature_with_func(
56        &self,
57        sig: &AnnotatedSignature,
58        func: Option<&HirFunction>,
59    ) -> String {
60        // DECY-241: Rename functions that conflict with Rust macros/keywords
61        let safe_name = match sig.name.as_str() {
62            "write" => "c_write",
63            "read" => "c_read",
64            "type" => "c_type",
65            "match" => "c_match",
66            "self" => "c_self",
67            "in" => "c_in",
68            name => name,
69        };
70        let mut result = format!("fn {}", safe_name);
71
72        // DECY-084/085: Detect output parameters for transformation
73        let (skip_output_params, output_param_types, output_is_fallible) =
74            Self::detect_output_params(func);
75
76        // DECY-072: Check if we have any non-slice reference parameters that need lifetimes
77        // Slices have elided lifetimes and don't need explicit lifetime parameters
78        let has_non_slice_references = sig.parameters.iter().any(|p| {
79            match &p.param_type {
80                AnnotatedType::Reference { inner, .. } => {
81                    // Check if this is NOT a slice (slice = Reference to Array with size=None)
82                    !matches!(&**inner, AnnotatedType::Simple(HirType::Array { size: None, .. }))
83                }
84                _ => false,
85            }
86        });
87
88        // Add lifetime parameters only if we have non-slice references
89        if !sig.lifetimes.is_empty() && has_non_slice_references {
90            let lifetime_params: Vec<String> =
91                sig.lifetimes.iter().map(|lt| lt.name.clone()).collect();
92            result.push_str(&format!("<{}>", lifetime_params.join(", ")));
93        }
94
95        // Add function parameters (DECY-084: filter out output params)
96        result.push('(');
97        let params: Vec<String> = sig
98            .parameters
99            .iter()
100            .filter(|p| !skip_output_params.contains(&p.name))
101            .map(|p| self.generate_annotated_param(p, func))
102            .collect();
103        result.push_str(&params.join(", "));
104        result.push(')');
105
106        // Generate return type
107        self.append_annotated_return_type(
108            &mut result,
109            sig,
110            func,
111            &output_param_types,
112            output_is_fallible,
113        );
114
115        result
116    }
117
118    /// Detect output parameters from a function for signature transformation.
119    /// Returns (skip_set, output_types, is_fallible).
120    fn detect_output_params(
121        func: Option<&HirFunction>,
122    ) -> (std::collections::HashSet<String>, Vec<HirType>, bool) {
123        use decy_analyzer::output_params::{OutputParamDetector, ParameterKind};
124        let mut skip_output_params = std::collections::HashSet::new();
125        let mut output_param_types: Vec<HirType> = Vec::new();
126        let mut output_is_fallible = false;
127
128        if let Some(f) = func {
129            let output_detector = OutputParamDetector::new();
130            let output_params = output_detector.detect(f);
131
132            // Count non-pointer parameters (inputs)
133            let input_param_count = f
134                .parameters()
135                .iter()
136                .filter(|p| !matches!(p.param_type(), HirType::Pointer(_)))
137                .count();
138
139            // Count potential output params for heuristic
140            let output_param_count =
141                output_params.iter().filter(|op| op.kind == ParameterKind::Output).count();
142
143            for op in &output_params {
144                if op.kind == ParameterKind::Output {
145                    // Heuristic: Only treat as output param if:
146                    // 1. There are other input parameters (output is derived from inputs)
147                    // 2. Or, the name suggests it's an output (result, out, output, ret, etc.)
148                    // 3. DECY-085: Or, there are multiple output params (void func with multiple outs)
149                    let is_output_name = Self::is_output_param_name(&op.name);
150
151                    if input_param_count > 0 || is_output_name || output_param_count >= 2 {
152                        skip_output_params.insert(op.name.clone());
153                        output_is_fallible = op.is_fallible;
154                        // DECY-085: Collect all output parameter types
155                        if let Some(param) = f.parameters().iter().find(|p| p.name() == op.name) {
156                            if let HirType::Pointer(inner) = param.param_type() {
157                                output_param_types.push((**inner).clone());
158                            }
159                        }
160                    }
161                }
162            }
163        }
164
165        (skip_output_params, output_param_types, output_is_fallible)
166    }
167
168    /// Check if a parameter name suggests it is an output parameter.
169    fn is_output_param_name(name: &str) -> bool {
170        let name_lower = name.to_lowercase();
171        name_lower.contains("result")
172            || name_lower.contains("out")
173            || name_lower.contains("ret")
174            || name_lower == "len"
175            || name_lower == "size"
176            || name_lower == "x"
177            || name_lower == "y"
178            || name_lower == "z"
179            || name_lower == "w"
180            || name_lower == "h"
181            || name_lower == "width"
182            || name_lower == "height"
183            || name_lower == "r"
184            || name_lower == "g"
185            || name_lower == "b"
186            || name_lower == "count"
187            || name_lower == "avg"
188    }
189
190    /// Generate a single annotated parameter string.
191    fn generate_annotated_param(
192        &self,
193        p: &decy_ownership::lifetime_gen::AnnotatedParameter,
194        func: Option<&HirFunction>,
195    ) -> String {
196        // Check if this is a slice parameter (Reference to Array with size=None)
197        let is_slice = match &p.param_type {
198            AnnotatedType::Reference { inner, .. } => match &**inner {
199                AnnotatedType::Simple(HirType::Array { size, .. }) => size.is_none(),
200                _ => false,
201            },
202            _ => false,
203        };
204
205        if is_slice {
206            // DECY-072: Slices don't need 'mut' prefix or explicit lifetimes
207            let type_str = match &p.param_type {
208                AnnotatedType::Reference { inner, mutable, .. } => {
209                    if let AnnotatedType::Simple(HirType::Array { element_type, .. }) =
210                        &**inner
211                    {
212                        if *mutable {
213                            format!("&mut [{}]", Self::map_type(element_type))
214                        } else {
215                            format!("&[{}]", Self::map_type(element_type))
216                        }
217                    } else {
218                        self.annotated_type_to_string(&p.param_type)
219                    }
220                }
221                _ => self.annotated_type_to_string(&p.param_type),
222            };
223            return format!("{}: {}", p.name, type_str);
224        }
225
226        // DECY-111: Transform pointer parameters to mutable references
227        // DECY-123: Skip transformation if pointer arithmetic is used
228        if let AnnotatedType::Simple(HirType::Pointer(inner)) = &p.param_type {
229            return self.generate_annotated_pointer_param(&p.name, inner, func);
230        }
231
232        // DECY-196: Handle unsized array parameters → slice references
233        if let AnnotatedType::Simple(HirType::Array { element_type, size: None }) =
234            &p.param_type
235        {
236            let element_str = Self::map_type(element_type);
237            return format!("{}: &mut [{}]", p.name, element_str);
238        }
239
240        // DECY-041: Add mut for all non-slice parameters to match C semantics
241        format!("mut {}: {}", p.name, self.annotated_type_to_string(&p.param_type))
242    }
243
244    /// Generate an annotated pointer parameter (reference, raw pointer, slice, or &str).
245    fn generate_annotated_pointer_param(
246        &self,
247        name: &str,
248        inner: &HirType,
249        func: Option<&HirFunction>,
250    ) -> String {
251        // DECY-135: const char* → &str transformation
252        if let Some(f) = func {
253            if let Some(orig_param) =
254                f.parameters().iter().find(|fp| fp.name() == name)
255            {
256                if orig_param.is_const_char_pointer() {
257                    return format!("mut {}: &str", name);
258                }
259            }
260        }
261        // DECY-134: Check for string iteration pattern FIRST
262        if let Some(f) = func {
263            if self.is_string_iteration_param(f, name) {
264                let is_mutable = self.is_parameter_deref_modified(f, name);
265                if is_mutable {
266                    return format!("{}: &mut [u8]", name);
267                } else {
268                    return format!("{}: &[u8]", name);
269                }
270            }
271        }
272        // DECY-123: If we have function body access, check for pointer arithmetic
273        if let Some(f) = func {
274            if self.uses_pointer_arithmetic(f, name) {
275                let inner_type = Self::map_type(inner);
276                return format!("mut {}: *mut {}", name, inner_type);
277            }
278        }
279        // DECY-168: void* parameters should stay as raw pointers
280        if matches!(*inner, HirType::Void) {
281            return format!("{}: *mut ()", name);
282        }
283        // Transform *mut T → &mut T for safety
284        let inner_type = Self::map_type(inner);
285        format!("{}: &mut {}", name, inner_type)
286    }
287
288    /// Append return type for annotated signature.
289    fn append_annotated_return_type(
290        &self,
291        result: &mut String,
292        sig: &AnnotatedSignature,
293        func: Option<&HirFunction>,
294        output_param_types: &[HirType],
295        output_is_fallible: bool,
296    ) {
297        // Special handling for main function (DECY-AUDIT-001)
298        let return_type_str = self.annotated_type_to_string(&sig.return_type);
299        if sig.name == "main" && return_type_str == "i32" {
300            return;
301        }
302
303        // DECY-084/085: Generate return type considering output parameters
304        if !output_param_types.is_empty() {
305            let out_type_str = if output_param_types.len() == 1 {
306                Self::map_type(&output_param_types[0])
307            } else {
308                let type_strs: Vec<String> =
309                    output_param_types.iter().map(Self::map_type).collect();
310                format!("({})", type_strs.join(", "))
311            };
312
313            if output_is_fallible {
314                result.push_str(&format!(" -> Result<{}, i32>", out_type_str));
315            } else {
316                result.push_str(&format!(" -> {}", out_type_str));
317            }
318        } else {
319            // DECY-142: Check for Vec return type (malloc'd array returns)
320            if let Some(f) = func {
321                if let Some(vec_element_type) = self.detect_vec_return(f) {
322                    let element_type_str = Self::map_type(&vec_element_type);
323                    result.push_str(&format!(" -> Vec<{}>", element_type_str));
324                    return;
325                }
326            }
327            // Add return type if not void
328            if return_type_str != "()" {
329                result.push_str(&format!(" -> {}", return_type_str));
330            }
331        }
332    }
333
334    /// Convert an `AnnotatedType` to Rust type string with lifetime annotations.
335    ///
336    /// # Examples
337    ///
338    /// ```
339    /// use decy_codegen::CodeGenerator;
340    /// use decy_ownership::lifetime_gen::{AnnotatedType, LifetimeParam};
341    /// use decy_hir::HirType;
342    ///
343    /// let codegen = CodeGenerator::new();
344    ///
345    /// // Simple type
346    /// let simple = AnnotatedType::Simple(HirType::Int);
347    /// assert_eq!(codegen.annotated_type_to_string(&simple), "i32");
348    ///
349    /// // Reference with lifetime
350    /// let ref_type = AnnotatedType::Reference {
351    ///     inner: Box::new(AnnotatedType::Simple(HirType::Int)),
352    ///     mutable: false,
353    ///     lifetime: Some(LifetimeParam::standard(0)),
354    /// };
355    /// assert_eq!(codegen.annotated_type_to_string(&ref_type), "&'a i32");
356    /// ```
357    #[allow(clippy::only_used_in_recursion)]
358    pub fn annotated_type_to_string(&self, annotated_type: &AnnotatedType) -> String {
359        match annotated_type {
360            AnnotatedType::Simple(hir_type) => Self::map_type(hir_type),
361            AnnotatedType::Reference { inner, mutable, lifetime } => {
362                // DECY-072: Special case for slices: &Vec<T> → &[T]
363                // Check if inner is a Vec type
364                if let AnnotatedType::Simple(HirType::Vec(element_type)) = &**inner {
365                    let element_str = Self::map_type(element_type);
366                    if *mutable {
367                        return format!("&mut [{}]", element_str);
368                    } else {
369                        return format!("&[{}]", element_str);
370                    }
371                }
372
373                let mut result = String::from("&");
374
375                // Add lifetime if present
376                if let Some(lt) = lifetime {
377                    result.push_str(&lt.name);
378                    result.push(' ');
379                }
380
381                // Add mutability
382                if *mutable {
383                    result.push_str("mut ");
384                }
385
386                // Add inner type
387                result.push_str(&self.annotated_type_to_string(inner));
388
389                result
390            }
391        }
392    }
393
394    /// Generate a default return statement for a type.
395    ///
396    /// # Examples
397    ///
398    /// ```
399    /// use decy_codegen::CodeGenerator;
400    /// use decy_hir::HirType;
401    ///
402    /// let codegen = CodeGenerator::new();
403    /// assert!(codegen.generate_return(&HirType::Int).contains("return 0"));
404    /// ```
405    pub fn generate_return(&self, return_type: &HirType) -> String {
406        match return_type {
407            HirType::Void => String::new(),
408            HirType::Bool => "    return false;".to_string(),
409            HirType::Int => "    return 0;".to_string(),
410            HirType::UnsignedInt => "    return 0;".to_string(), // DECY-158
411            HirType::Float => "    return 0.0;".to_string(),
412            HirType::Double => "    return 0.0;".to_string(),
413            HirType::Char => "    return 0;".to_string(),
414            HirType::SignedChar => "    return 0;".to_string(), // DECY-250
415            HirType::Pointer(_) => "    return std::ptr::null_mut();".to_string(),
416            HirType::Box(inner) => {
417                format!("    return Box::new({});", Self::default_value_for_type(inner))
418            }
419            HirType::Vec(_) => "    return Vec::new();".to_string(),
420            HirType::Option(_) => "    return None;".to_string(),
421            HirType::Reference { .. } => {
422                // References in return position need concrete values from parameters
423                // This should be handled by lifetime-annotated code generation
424                // using generate_function_with_lifetimes() instead
425                String::new()
426            }
427            HirType::Struct(name) => {
428                format!("    return {}::default();", name)
429            }
430            HirType::Enum(name) => {
431                format!("    return {}::default();", name)
432            }
433            HirType::Array { element_type, size } => {
434                if let Some(n) = size {
435                    format!("    return [{}; {}];", Self::default_value_for_type(element_type), n)
436                } else {
437                    // Unsized arrays in return position don't make sense
438                    String::new()
439                }
440            }
441            HirType::FunctionPointer { .. } => {
442                // Function pointers in return position need concrete function values
443                // This should be handled by the function body
444                String::new()
445            }
446            HirType::StringLiteral => r#"    return "";"#.to_string(),
447            HirType::OwnedString => "    return String::new();".to_string(),
448            HirType::StringReference => r#"    return "";"#.to_string(),
449            HirType::Union(_) => {
450                // Unions will be transformed to enums
451                // Return statement depends on the specific enum variant
452                String::new()
453            }
454            // DECY-172: Type aliases return 0
455            HirType::TypeAlias(name) => match name.as_str() {
456                "size_t" => "    return 0usize;".to_string(),
457                "ssize_t" | "ptrdiff_t" => "    return 0isize;".to_string(),
458                _ => "    return 0;".to_string(),
459            },
460        }
461    }
462
463    /// Generate a complete function from HIR.
464    ///
465    /// # Examples
466    ///
467    /// ```
468    /// use decy_codegen::CodeGenerator;
469    /// use decy_hir::{HirFunction, HirType, HirParameter};
470    ///
471    /// let func = HirFunction::new(
472    ///     "add".to_string(),
473    ///     HirType::Int,
474    ///     vec![
475    ///         HirParameter::new("a".to_string(), HirType::Int),
476    ///         HirParameter::new("b".to_string(), HirType::Int),
477    ///     ],
478    /// );
479    ///
480    /// let codegen = CodeGenerator::new();
481    /// let code = codegen.generate_function(&func);
482    ///
483    /// assert!(code.contains("fn add(mut a: i32, mut b: i32) -> i32"));
484    /// assert!(code.contains("{"));
485    /// assert!(code.contains("}"));
486    /// ```
487    pub fn generate_function(&self, func: &HirFunction) -> String {
488        // DECY-211: CUDA __global__ kernels -> extern "C" FFI wrapper
489        if func.cuda_qualifier() == Some(decy_hir::HirCudaQualifier::Global) {
490            return self.generate_cuda_kernel_ffi(func);
491        }
492        // DECY-211: CUDA __device__ functions -> comment noting device-only
493        if func.cuda_qualifier() == Some(decy_hir::HirCudaQualifier::Device) {
494            let sig = self.generate_signature(func);
495            return format!(
496                "// CUDA __device__ function — runs on GPU only, not transpiled\n// {}\n",
497                sig
498            );
499        }
500
501        let mut code = String::new();
502
503        // DECY-072 GREEN: Build mapping of length params -> array params for body transformation
504        use decy_ownership::dataflow::DataflowAnalyzer;
505        let analyzer = DataflowAnalyzer::new();
506        let graph = analyzer.analyze(func);
507
508        let mut length_to_array: std::collections::HashMap<String, String> =
509            std::collections::HashMap::new();
510
511        // DECY-113: Only map length params with length-like names
512        // DECY-162: Don't map length params when array uses pointer arithmetic (stays raw pointer)
513        for (idx, param) in func.parameters().iter().enumerate() {
514            if let Some(true) = graph.is_array_parameter(param.name()) {
515                // DECY-162: Skip if array param uses pointer arithmetic
516                // Raw pointers don't have .len(), so we keep the size param as-is
517                if self.uses_pointer_arithmetic(func, param.name()) {
518                    continue;
519                }
520
521                // This is an array parameter - map the next param to this array
522                // but only if it has a length-like name
523                if idx + 1 < func.parameters().len() {
524                    let next_param = &func.parameters()[idx + 1];
525                    if matches!(next_param.param_type(), HirType::Int) {
526                        let param_name = next_param.name().to_lowercase();
527                        if param_name.contains("len")
528                            || param_name.contains("size")
529                            || param_name.contains("count")
530                            || param_name == "n"
531                            || param_name == "num"
532                        {
533                            length_to_array
534                                .insert(next_param.name().to_string(), param.name().to_string());
535                        }
536                    }
537                }
538            }
539        }
540
541        // Generate signature
542        code.push_str(&self.generate_signature(func));
543        code.push_str(" {\n");
544
545        // Initialize type context for tracking variable types across statements
546        let mut ctx = TypeContext::from_function(func);
547
548        // DECY-129/DECY-148: Update context to reflect pointer-to-reference transformations
549        // When pointer params are transformed to &mut T in signature, context must match
550        // DECY-148: Distinguish array params (slices) from struct pointer params (references)
551        for param in func.parameters() {
552            if let HirType::Pointer(inner) = param.param_type() {
553                // Check if this pointer uses pointer arithmetic (keep as raw pointer)
554                if !self.uses_pointer_arithmetic(func, param.name()) {
555                    // DECY-148: Check if this is an ARRAY parameter
556                    let is_array_param = graph.is_array_parameter(param.name()).unwrap_or(false);
557
558                    if is_array_param {
559                        // Array parameter → register as slice (Reference to Array)
560                        ctx.add_variable(
561                            param.name().to_string(),
562                            HirType::Reference {
563                                inner: Box::new(HirType::Array {
564                                    element_type: inner.clone(),
565                                    size: None, // Slice (unsized array)
566                                }),
567                                mutable: true,
568                            },
569                        );
570                    } else {
571                        // Struct pointer → register as Reference to inner type
572                        let is_mutable = self.is_parameter_deref_modified(func, param.name());
573                        ctx.add_variable(
574                            param.name().to_string(),
575                            HirType::Reference { inner: inner.clone(), mutable: is_mutable },
576                        );
577                    }
578                }
579            }
580        }
581
582        // DECY-142: Detect Vec-return functions for correct return type handling
583        let effective_return_type = if let Some(element_type) = self.detect_vec_return(func) {
584            HirType::Vec(Box::new(element_type))
585        } else {
586            func.return_type().clone()
587        };
588
589        // Generate body statements if present
590        if func.body().is_empty() {
591            // Generate stub body with return statement
592            let return_stmt = self.generate_return(func.return_type());
593            if !return_stmt.is_empty() {
594                code.push_str(&return_stmt);
595                code.push('\n');
596            }
597        } else {
598            // Generate actual body statements with persistent context
599            for stmt in func.body() {
600                code.push_str("    ");
601                let stmt_code = self.generate_statement_with_context(
602                    stmt,
603                    Some(func.name()),
604                    &mut ctx,
605                    Some(&effective_return_type),
606                );
607
608                // DECY-072 GREEN: Replace length parameter references with arr.len() calls
609                let transformed = self.transform_length_refs(&stmt_code, &length_to_array);
610                code.push_str(&transformed);
611                code.push('\n');
612            }
613        }
614
615        code.push('}');
616        code
617    }
618
619    /// Generate a complete function from HIR with struct definitions for type inference.
620    ///
621    /// This is useful for testing when struct fields need proper type inference.
622    /// DECY-165: Enables proper raw pointer detection for struct field access.
623    pub fn generate_function_with_structs(
624        &self,
625        func: &HirFunction,
626        structs: &[decy_hir::HirStruct],
627    ) -> String {
628        // DECY-221: CUDA kernel/device functions bypass normal codegen
629        if func.cuda_qualifier() == Some(decy_hir::HirCudaQualifier::Global) {
630            return self.generate_cuda_kernel_ffi(func);
631        }
632        if func.cuda_qualifier() == Some(decy_hir::HirCudaQualifier::Device) {
633            let sig = self.generate_signature(func);
634            return format!("// CUDA __device__ function — GPU only\n// {}\n", sig);
635        }
636
637        let mut code = String::new();
638
639        // Generate signature
640        code.push_str(&self.generate_signature(func));
641        code.push_str(" {\n");
642
643        // Initialize type context with function parameters AND struct definitions
644        let mut ctx = TypeContext::from_function(func);
645
646        // DECY-165: Add struct definitions to context for field type lookup
647        for struct_def in structs {
648            ctx.add_struct(struct_def);
649        }
650
651        // DECY-129/DECY-148: Update context to reflect pointer-to-reference transformations
652        // When pointer params are transformed to &mut T in signature, context must match
653        use decy_ownership::dataflow::DataflowAnalyzer;
654        let analyzer = DataflowAnalyzer::new();
655        let graph = analyzer.analyze(func);
656
657        for param in func.parameters() {
658            if let HirType::Pointer(inner) = param.param_type() {
659                // Only transform if the pointer is not used for pointer arithmetic
660                if !self.uses_pointer_arithmetic(func, param.name()) {
661                    // Check if it's an array parameter → use &[T] or &mut [T]
662                    if graph.is_array_parameter(param.name()) == Some(true) {
663                        // Use slice reference type
664                        ctx.add_variable(
665                            param.name().to_string(),
666                            HirType::Reference {
667                                inner: Box::new(HirType::Vec(inner.clone())),
668                                mutable: self.is_parameter_deref_modified(func, param.name()),
669                            },
670                        );
671                    } else {
672                        // Single pointer → reference
673                        ctx.add_variable(
674                            param.name().to_string(),
675                            HirType::Reference {
676                                inner: inner.clone(),
677                                mutable: self.is_parameter_deref_modified(func, param.name()),
678                            },
679                        );
680                    }
681                }
682            }
683        }
684
685        // Generate body statements
686        if !func.body().is_empty() {
687            for stmt in func.body() {
688                code.push_str("    ");
689                let stmt_code = self.generate_statement_with_context(
690                    stmt,
691                    Some(func.name()),
692                    &mut ctx,
693                    Some(func.return_type()),
694                );
695                code.push_str(&stmt_code);
696                code.push('\n');
697            }
698        }
699
700        code.push('}');
701        code
702    }
703
704    /// Generate a complete function from HIR with lifetime annotations.
705    ///
706    /// Takes both the HIR function and its annotated signature to generate
707    /// Rust code with proper lifetime annotations.
708    ///
709    /// # Examples
710    ///
711    /// ```
712    /// use decy_codegen::CodeGenerator;
713    /// use decy_hir::{HirFunction, HirType, HirParameter};
714    /// use decy_ownership::lifetime_gen::{AnnotatedSignature, AnnotatedParameter, AnnotatedType, LifetimeParam};
715    ///
716    /// let func = HirFunction::new(
717    ///     "identity".to_string(),
718    ///     HirType::Reference {
719    ///         inner: Box::new(HirType::Int),
720    ///         mutable: false,
721    ///     },
722    ///     vec![
723    ///         HirParameter::new("x".to_string(), HirType::Reference {
724    ///             inner: Box::new(HirType::Int),
725    ///             mutable: false,
726    ///         }),
727    ///     ],
728    /// );
729    ///
730    /// let sig = AnnotatedSignature {
731    ///     name: "identity".to_string(),
732    ///     lifetimes: vec![LifetimeParam::standard(0)],
733    ///     parameters: vec![
734    ///         AnnotatedParameter {
735    ///             name: "x".to_string(),
736    ///             param_type: AnnotatedType::Reference {
737    ///                 inner: Box::new(AnnotatedType::Simple(HirType::Int)),
738    ///                 mutable: false,
739    ///                 lifetime: Some(LifetimeParam::standard(0)),
740    ///             },
741    ///         },
742    ///     ],
743    ///     return_type: AnnotatedType::Reference {
744    ///         inner: Box::new(AnnotatedType::Simple(HirType::Int)),
745    ///         mutable: false,
746    ///         lifetime: Some(LifetimeParam::standard(0)),
747    ///     },
748    /// };
749    ///
750    /// let codegen = CodeGenerator::new();
751    /// let code = codegen.generate_function_with_lifetimes(&func, &sig);
752    ///
753    /// assert!(code.contains("<'a>"));
754    /// assert!(code.contains("&'a i32"));
755    /// ```
756    pub fn generate_function_with_lifetimes(
757        &self,
758        func: &HirFunction,
759        sig: &AnnotatedSignature,
760    ) -> String {
761        self.generate_function_with_lifetimes_and_structs(func, sig, &[], &[], &[], &[], &[])
762    }
763
764    /// Generate a complete function from HIR with lifetime annotations and struct definitions.
765    ///
766    /// Takes the HIR function, its annotated signature, struct definitions, and all function
767    /// signatures for call site reference mutability.
768    ///
769    /// # Arguments
770    /// * `func` - The HIR function to generate
771    /// * `sig` - The annotated signature with lifetime annotations
772    /// * `structs` - Struct definitions for field type awareness
773    /// * `all_functions` - All function signatures for DECY-117 call site mutability
774    /// * `slice_func_args` - DECY-116: func_name -> [(array_idx, len_idx)] for call site transformation
775    /// * `string_iter_funcs` - DECY-134b: func_name -> [(param_idx, is_mutable)] for string iteration
776    /// * `globals` - DECY-220/233: Global variable names and types for unsafe access and type inference
777    #[allow(clippy::too_many_arguments)]
778    pub fn generate_function_with_lifetimes_and_structs(
779        &self,
780        func: &HirFunction,
781        sig: &AnnotatedSignature,
782        structs: &[decy_hir::HirStruct],
783        all_functions: &[(String, Vec<HirType>)],
784        slice_func_args: &[(String, Vec<(usize, usize)>)],
785        string_iter_funcs: &[(String, Vec<(usize, bool)>)],
786        globals: &[(String, HirType)],
787    ) -> String {
788        contract_pre_host_transpilation!();
789        // DECY-221: CUDA kernel/device functions bypass normal codegen
790        if func.cuda_qualifier() == Some(decy_hir::HirCudaQualifier::Global) {
791            return self.generate_cuda_kernel_ffi(func);
792        }
793        if func.cuda_qualifier() == Some(decy_hir::HirCudaQualifier::Device) {
794            let sig_str = self.generate_signature(func);
795            return format!(
796                "// CUDA __device__ function — runs on GPU only, not transpiled\n// {}\n",
797                sig_str
798            );
799        }
800
801        let mut code = String::new();
802
803        // Generate signature with lifetimes
804        // DECY-123: Pass function for pointer arithmetic detection
805        code.push_str(&self.generate_annotated_signature_with_func(sig, Some(func)));
806        code.push_str(" {\n");
807
808        // DECY-041: Initialize type context with function parameters for pointer arithmetic
809        let mut ctx = TypeContext::from_function(func);
810
811        // DECY-220/233: Register global variables for unsafe access tracking and type inference
812        for (name, var_type) in globals {
813            ctx.add_global(name.clone());
814            ctx.add_variable(name.clone(), var_type.clone());
815        }
816
817        // DECY-134: Track string iteration params for index-based body generation
818        let mut string_iter_index_decls = Vec::new();
819
820        // DECY-111: Transform pointer parameters to references in the context
821        // DECY-123/124: Only transform if NOT using pointer arithmetic
822        // This prevents unsafe blocks from being generated for reference dereferences
823        // DECY-148: Use DataflowAnalyzer to determine which params are array params
824        use decy_ownership::dataflow::DataflowAnalyzer;
825        let analyzer = DataflowAnalyzer::new();
826        let graph = analyzer.analyze(func);
827
828        for param in func.parameters() {
829            // DECY-138: Check for const char* → &str transformation FIRST
830            // This enables proper string iteration pattern codegen
831            if param.is_const_char_pointer() {
832                ctx.add_variable(param.name().to_string(), HirType::StringReference);
833            } else if let HirType::Pointer(inner) = param.param_type() {
834                // DECY-134: Check for string iteration pattern FIRST
835                if self.is_string_iteration_param(func, param.name()) {
836                    // Register as Vec type in context (slice in generated code)
837                    ctx.add_variable(param.name().to_string(), HirType::Vec(inner.clone()));
838                    // Register string iteration param with index variable
839                    let idx_var = format!("{}_idx", param.name());
840                    ctx.add_string_iter_param(param.name().to_string(), idx_var.clone());
841                    // Add index declaration to generate at function start
842                    string_iter_index_decls.push(format!("    let mut {}: usize = 0;", idx_var));
843                } else if self.uses_pointer_arithmetic(func, param.name()) {
844                    // DECY-124: Keep as pointer in context if pointer arithmetic is used
845                    // This ensures proper unsafe wrapping_add/wrapping_sub codegen
846                    // Keep as pointer - codegen will generate unsafe blocks
847                    ctx.add_variable(param.name().to_string(), param.param_type().clone());
848                } else {
849                    // DECY-148: Check if this is an ARRAY parameter (detected by dataflow analysis)
850                    let is_array_param = graph.is_array_parameter(param.name()).unwrap_or(false);
851
852                    if is_array_param {
853                        // DECY-146: Array parameter → register as slice (Reference to Array)
854                        // This enables proper .as_ptr()/.as_mut_ptr() generation
855                        ctx.add_variable(
856                            param.name().to_string(),
857                            HirType::Reference {
858                                inner: Box::new(HirType::Array {
859                                    element_type: inner.clone(),
860                                    size: None, // Slice (unsized array)
861                                }),
862                                mutable: true,
863                            },
864                        );
865                    } else {
866                        // DECY-148: Non-array struct pointer → register as Reference to inner type
867                        // This enables proper `&mut T as *mut _` coercion on return
868                        let is_mutable = self.is_parameter_deref_modified(func, param.name());
869                        ctx.add_variable(
870                            param.name().to_string(),
871                            HirType::Reference { inner: inner.clone(), mutable: is_mutable },
872                        );
873                    }
874                }
875            }
876        }
877
878        // DECY-134: Generate index variable declarations for string iteration params
879        for decl in &string_iter_index_decls {
880            code.push_str(decl);
881            code.push('\n');
882        }
883
884        // Add struct definitions to context for field type lookup
885        for struct_def in structs {
886            ctx.add_struct(struct_def);
887        }
888
889        // DECY-117: Add all function signatures for call site reference mutability
890        for (func_name, param_types) in all_functions {
891            ctx.add_function(func_name.clone(), param_types.clone());
892        }
893
894        // DECY-116: Add slice function arg mappings for call site transformation
895        for (func_name, arg_mappings) in slice_func_args {
896            ctx.add_slice_func_args(func_name.clone(), arg_mappings.clone());
897        }
898
899        // DECY-134b: Add string iteration function info for call site transformation
900        for (func_name, params) in string_iter_funcs {
901            ctx.add_string_iter_func(func_name.clone(), params.clone());
902        }
903
904        // DECY-142: Detect Vec-return functions for correct return type handling
905        let effective_return_type = if let Some(element_type) = self.detect_vec_return(func) {
906            HirType::Vec(Box::new(element_type))
907        } else {
908            func.return_type().clone()
909        };
910
911        // Generate body statements if present
912        if func.body().is_empty() {
913            // Generate stub body with return statement
914            let return_stmt = self.generate_return(func.return_type());
915            if !return_stmt.is_empty() {
916                code.push_str(&return_stmt);
917                code.push('\n');
918            }
919        } else {
920            // Generate actual body statements with type context and return type
921            for stmt in func.body() {
922                code.push_str("    ");
923                code.push_str(&self.generate_statement_with_context(
924                    stmt,
925                    Some(func.name()),
926                    &mut ctx,
927                    Some(&effective_return_type),
928                ));
929                code.push('\n');
930            }
931        }
932
933        code.push('}');
934        code
935    }
936
937    /// Generate a function with Box transformations applied.
938    ///
939    /// This method analyzes the function for malloc/free patterns and
940    /// transforms them into safe `Box::new()` expressions.
941    ///
942    /// # Examples
943    ///
944    /// ```
945    /// use decy_codegen::CodeGenerator;
946    /// use decy_hir::{HirFunction, HirType, HirStatement, HirExpression};
947    /// use decy_analyzer::patterns::PatternDetector;
948    ///
949    /// let func = HirFunction::new_with_body(
950    ///     "test".to_string(),
951    ///     HirType::Void,
952    ///     vec![],
953    ///     vec![
954    ///         HirStatement::VariableDeclaration {
955    ///             name: "ptr".to_string(),
956    ///             var_type: HirType::Pointer(Box::new(HirType::Int)),
957    ///             initializer: Some(HirExpression::FunctionCall {
958    ///                 function: "malloc".to_string(),
959    ///                 arguments: vec![HirExpression::IntLiteral(100)],
960    ///             }),
961    ///         },
962    ///     ],
963    /// );
964    ///
965    /// let codegen = CodeGenerator::new();
966    /// let detector = PatternDetector::new();
967    /// let candidates = detector.find_box_candidates(&func);
968    /// let code = codegen.generate_function_with_box_transform(&func, &candidates);
969    ///
970    /// assert!(code.contains("Box::new"));
971    /// ```
972    pub fn generate_function_with_box_transform(
973        &self,
974        func: &HirFunction,
975        candidates: &[decy_analyzer::patterns::BoxCandidate],
976    ) -> String {
977        let mut code = String::new();
978
979        // Generate signature
980        code.push_str(&self.generate_signature(func));
981        code.push_str(" {\n");
982
983        // Generate body statements if present
984        if func.body().is_empty() {
985            // Generate stub body with return statement
986            let return_stmt = self.generate_return(func.return_type());
987            if !return_stmt.is_empty() {
988                code.push_str(&return_stmt);
989                code.push('\n');
990            }
991        } else {
992            // Generate body statements with Box transformations
993            for (idx, stmt) in func.body().iter().enumerate() {
994                // Check if this statement should be transformed
995                let transformed_stmt =
996                    if let Some(candidate) = candidates.iter().find(|c| c.malloc_index == idx) {
997                        self.box_transformer.transform_statement(stmt, candidate)
998                    } else {
999                        stmt.clone()
1000                    };
1001
1002                code.push_str("    ");
1003                code.push_str(
1004                    &self.generate_statement_for_function(&transformed_stmt, Some(func.name())),
1005                );
1006                code.push('\n');
1007            }
1008        }
1009
1010        code.push('}');
1011        code
1012    }
1013
1014    /// Generate a function with Vec transformations applied.
1015    ///
1016    /// This method analyzes the function for malloc(n * sizeof(T)) patterns and
1017    /// transforms them into safe `Vec::with_capacity(n)` expressions.
1018    pub fn generate_function_with_vec_transform(
1019        &self,
1020        func: &HirFunction,
1021        candidates: &[decy_analyzer::patterns::VecCandidate],
1022    ) -> String {
1023        let mut code = String::new();
1024
1025        // Generate signature
1026        code.push_str(&self.generate_signature(func));
1027        code.push_str(" {\n");
1028
1029        // Generate body statements if present
1030        if func.body().is_empty() {
1031            // Generate stub body with return statement
1032            let return_stmt = self.generate_return(func.return_type());
1033            if !return_stmt.is_empty() {
1034                code.push_str(&return_stmt);
1035                code.push('\n');
1036            }
1037        } else {
1038            // Generate body statements with Vec transformations
1039            for (idx, stmt) in func.body().iter().enumerate() {
1040                // Check if this statement should be transformed
1041                let transformed_stmt =
1042                    if let Some(candidate) = candidates.iter().find(|c| c.malloc_index == idx) {
1043                        self.transform_vec_statement(stmt, candidate)
1044                    } else {
1045                        stmt.clone()
1046                    };
1047
1048                code.push_str("    ");
1049                code.push_str(
1050                    &self.generate_statement_for_function(&transformed_stmt, Some(func.name())),
1051                );
1052                code.push('\n');
1053            }
1054        }
1055
1056        code.push('}');
1057        code
1058    }
1059
1060    /// Transform a statement to use Vec instead of malloc for array patterns.
1061    pub(crate) fn transform_vec_statement(
1062        &self,
1063        stmt: &HirStatement,
1064        candidate: &decy_analyzer::patterns::VecCandidate,
1065    ) -> HirStatement {
1066        match stmt {
1067            HirStatement::VariableDeclaration { name, var_type, initializer: _ } => {
1068                // Get the element type from the pointer
1069                let element_type = if let HirType::Pointer(inner) = var_type {
1070                    (**inner).clone()
1071                } else {
1072                    // Fallback: keep original type
1073                    return stmt.clone();
1074                };
1075
1076                // Transform type to Vec
1077                let vec_type = HirType::Vec(Box::new(element_type));
1078
1079                // Transform initializer: malloc(n * sizeof(T)) → Vec::with_capacity(n)
1080                let vec_initializer = if let Some(capacity_expr) = &candidate.capacity_expr {
1081                    Some(HirExpression::FunctionCall {
1082                        function: "Vec::with_capacity".to_string(),
1083                        arguments: vec![capacity_expr.clone()],
1084                    })
1085                } else {
1086                    // No capacity expression - use Vec::new()
1087                    Some(HirExpression::FunctionCall {
1088                        function: "Vec::new".to_string(),
1089                        arguments: vec![],
1090                    })
1091                };
1092
1093                HirStatement::VariableDeclaration {
1094                    name: name.clone(),
1095                    var_type: vec_type,
1096                    initializer: vec_initializer,
1097                }
1098            }
1099            HirStatement::Assignment { target: _, value: _ } => {
1100                // Similar transformation for assignments
1101                // For now, keep the original statement
1102                // Future: handle ptr = malloc(n * sizeof(T)) assignments
1103                stmt.clone()
1104            }
1105            _ => stmt.clone(),
1106        }
1107    }
1108
1109    /// Generate a function with both Box and Vec transformations applied.
1110    ///
1111    /// This method combines both Box and Vec transformations,
1112    /// applying them to their respective patterns.
1113    pub fn generate_function_with_box_and_vec_transform(
1114        &self,
1115        func: &HirFunction,
1116        box_candidates: &[decy_analyzer::patterns::BoxCandidate],
1117        vec_candidates: &[decy_analyzer::patterns::VecCandidate],
1118    ) -> String {
1119        let mut code = String::new();
1120
1121        // Generate signature
1122        code.push_str(&self.generate_signature(func));
1123        code.push_str(" {\n");
1124
1125        // Generate body statements if present
1126        if func.body().is_empty() {
1127            // Generate stub body with return statement
1128            let return_stmt = self.generate_return(func.return_type());
1129            if !return_stmt.is_empty() {
1130                code.push_str(&return_stmt);
1131                code.push('\n');
1132            }
1133        } else {
1134            // Generate body statements with both transformations
1135            for (idx, stmt) in func.body().iter().enumerate() {
1136                // Check Vec candidates first (more specific pattern)
1137                let transformed_stmt = if let Some(vec_candidate) =
1138                    vec_candidates.iter().find(|c| c.malloc_index == idx)
1139                {
1140                    self.transform_vec_statement(stmt, vec_candidate)
1141                } else if let Some(box_candidate) =
1142                    box_candidates.iter().find(|c| c.malloc_index == idx)
1143                {
1144                    self.box_transformer.transform_statement(stmt, box_candidate)
1145                } else {
1146                    stmt.clone()
1147                };
1148
1149                code.push_str("    ");
1150                code.push_str(
1151                    &self.generate_statement_for_function(&transformed_stmt, Some(func.name())),
1152                );
1153                code.push('\n');
1154            }
1155        }
1156
1157        code.push('}');
1158        code
1159    }
1160}