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

100% Statements 20/20
100% Branches 20/20
100% Functions 2/2
100% Lines 20/20

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                                                              160x 5x       155x 5x       150x 10x       140x 3x       137x       74x       63x 30x       33x 6x       27x 2x       25x                               147x 124x         23x          
/**
 * 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 {
    // 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;
    }
 
    // 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;