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

100% Statements 13/13
85.71% Branches 12/14
100% Functions 4/4
100% Lines 13/13

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                                                15x 2x     13x   16x                           7x       7x             16x   16x 2x     14x   9x 9x       5x          
/**
 * ADR-029: the single formatter for a callback typedef's parameter list.
 *
 * The `.c` and the `.h` each used to build this string themselves, and they
 * disagreed: the header dropped `const` and array dimensions, so
 * `void (*onReceive_fp)(const Message*)` in the implementation met
 * `void (*onReceive_fp)(Message*)` in the header. Nothing caught it while the
 * `.c` did not include its own header; once it does (#1164), the two meet in
 * one translation unit and the compiler rejects the redeclaration.
 *
 * Both paths now format from here, so there is one answer to "what does this
 * typedef look like?" rather than two that happened to agree for simple cases.
 */
 
import type ICallbackTypedefParameter from "../types/ICallbackTypedefParameter";
 
class CallbackTypedefFormatter {
  /**
   * Format the parameter list between the parentheses of a callback typedef.
   */
  static formatParameterList(
    parameters: readonly ICallbackTypedefParameter[],
    isCppMode: boolean,
  ): string {
    if (parameters.length === 0) {
      return "void";
    }
 
    return parameters
      .map((parameter) =>
        CallbackTypedefFormatter.formatParameter(parameter, isCppMode),
      )
      .join(", ");
  }
 
  /**
   * Format a complete callback typedef declaration.
   */
  static format(
    returnType: string,
    typedefName: string,
    parameters: readonly ICallbackTypedefParameter[],
    isCppMode: boolean,
  ): string {
    const parameterList = CallbackTypedefFormatter.formatParameterList(
      parameters,
      isCppMode,
    );
    return `typedef ${returnType} (*${typedefName})(${parameterList});`;
  }
 
  private static formatParameter(
    parameter: ICallbackTypedefParameter,
    isCppMode: boolean,
  ): string {
    const constModifier = parameter.isConst ? "const " : "";
 
    if (parameter.isArray) {
      return `${constModifier}${parameter.type} ${parameter.name ?? ""}${parameter.arrayDims ?? ""}`;
    }
 
    if (parameter.isStruct) {
      // ADR-006: struct parameters become pointers in C, references in C++.
      const pointerOrReference = isCppMode ? "&" : "*";
      return `${constModifier}${parameter.type}${pointerOrReference}`;
    }
 
    // ADR-029: callback parameters are already function pointers.
    return parameter.type;
  }
}
 
export default CallbackTypedefFormatter;