All files / transpiler/output/codegen/helpers ParameterDereferenceResolver.ts

91.66% Statements 22/24
91.66% Branches 22/24
100% Functions 2/2
91.66% Lines 22/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                                                                      193x         193x 5x       188x 5x       183x 10x       173x 3x       170x       80x       90x 36x       54x 7x       47x 2x       45x                               180x 137x           43x           43x          
/**
 * Parameter Dereference Resolver
 *
 * Determines whether a parameter needs to be dereferenced when used as a value.
 * C-Next uses pass-by-reference for most types, but some types use pass-by-value:
 * - Callbacks (function pointers)
 * - Float types (f32, f64)
 * - Enum types
 * - Small unmodified primitives (optimization)
 * - Structs (use -> instead of dereference)
 * - Arrays (already pointers)
 * - Unknown types (external enums, typedefs)
 *
 * Issue #551, #558, #644, ADR-006, ADR-029
 */
 
import TParameterInfo from "../types/TParameterInfo";
import IParameterDereferenceDeps from "../types/IParameterDereferenceDeps";
 
/**
 * Static utility for resolving parameter dereference requirements
 */
class ParameterDereferenceResolver {
  /**
   * Determine if a parameter should be passed by value (no dereference needed)
   */
  static isPassByValue(
    paramInfo: TParameterInfo,
    deps: IParameterDereferenceDeps,
  ): boolean {
    // Issue #895: Primitive params that became pointers due to callback typedef
    // are NOT pass-by-value — when used as values (assignments, comparisons),
    // they need dereferencing (*buf) to get the actual value.
    // Issue #937: However, when forwarded to C functions expecting pointers,
    // the CallExprGenerator handles using the identifier directly.
    Iif (paramInfo.isCallbackPointerPrimitive) {
      return false; // Needs dereferencing when used as a value
    }
 
    // ADR-029: Callback parameters are function pointers
    if (paramInfo.isCallback) {
      return true;
    }
 
    // Float types use pass-by-value
    if (deps.isFloatType(paramInfo.baseType)) {
      return true;
    }
 
    // Enum types use pass-by-value
    if (deps.knownEnums.has(paramInfo.baseType)) {
      return true;
    }
 
    // ADR-045: String parameters are passed as char*
    if (paramInfo.isString) {
      return true;
    }
 
    // Issue #269: Small unmodified primitives use pass-by-value
    if (
      deps.currentFunctionName &&
      deps.isParameterPassByValue(deps.currentFunctionName, paramInfo.name)
    ) {
      return true;
    }
 
    // Structs use -> notation, not dereference
    if (paramInfo.isStruct) {
      return true;
    }
 
    // Arrays are already pointers
    if (paramInfo.isArray) {
      return true;
    }
 
    // Issue #551: Unknown types use pass-by-value
    if (!deps.isKnownPrimitive(paramInfo.baseType)) {
      return true;
    }
 
    // Known primitive that is pass-by-reference
    return false;
  }
 
  /**
   * Resolve a parameter identifier, applying dereference if needed
   *
   * @param id The parameter identifier
   * @param paramInfo Parameter information
   * @param deps Dependencies for resolution
   * @returns The resolved identifier (possibly with dereference)
   */
  static resolve(
    id: string,
    paramInfo: TParameterInfo,
    deps: IParameterDereferenceDeps,
  ): string {
    if (ParameterDereferenceResolver.isPassByValue(paramInfo, deps)) {
      return id;
    }
 
    // Issue #895: Callback-compatible primitives need dereferencing when
    // used as values (assignments, comparisons) because the C-Next type
    // (e.g., u8) became a pointer (uint8_t*) to match the callback typedef.
    Iif (paramInfo.forcePointerSemantics) {
      return `(*${id})`;
    }
 
    // Known primitive that is pass-by-reference needs dereference
    // Issue #558/#644: In C++ mode, primitives become references
    return deps.maybeDereference(id);
  }
}
 
export default ParameterDereferenceResolver;