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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | 412x 4x 408x 48x 360x 200x 160x 9x 151x 5x 146x 143x 3x 48x 59x 48x 3x 45x 4x 41x 200x 200x 9x 9x 148x 148x 148x 3x 3x 205x 205x 82x 123x | /**
* ParameterSignatureBuilder - Stateless builder for C/C++ parameter signatures
*
* Takes a normalized IParameterInput and produces the final parameter string.
* All decisions (const, pass-by-value, etc.) are pre-computed in the input.
*
* This is the single source of truth for parameter formatting, used by both:
* - CodeGenerator (via ParameterInputAdapter.fromAST)
* - BaseHeaderGenerator (via ParameterInputAdapter.fromSymbol)
*/
import IParameterInput from "../types/IParameterInput";
/**
* Static helper class for building C/C++ parameter signature strings.
*/
class ParameterSignatureBuilder {
/**
* Build a parameter signature string from normalized input.
*
* @param param - Normalized parameter input (all decisions pre-computed)
* @param refSuffix - '*' for C mode (pointer), '&' for C++ mode (reference)
* @returns The formatted parameter string (e.g., "const uint32_t* value")
*/
static build(param: IParameterInput, refSuffix: string): string {
// Callback parameters: just typedef name and param name
if (param.isCallback && param.callbackTypedefName) {
return `${param.callbackTypedefName} ${param.name}`;
}
// Array parameters with dimensions
if (
param.isArray &&
param.arrayDimensions &&
param.arrayDimensions.length > 0
) {
return this._buildArrayParam(param);
}
// Pass-by-value parameters (ISR, float, enum, small primitives)
if (param.isPassByValue) {
return this._buildPassByValueParam(param);
}
// Non-array string: string<N> -> const char* name
if (param.isString && !param.isArray) {
return this._buildStringParam(param);
}
// Issue #995: Opaque handles are always pass-by-reference with pointer syntax
if (param.isOpaqueHandle) {
return this._buildRefParam(param, refSuffix);
}
// Known struct or known primitive: pass by reference
if (param.isPassByReference) {
return this._buildRefParam(param, refSuffix);
}
// Unknown types: pass by value (standard C semantics)
return this._buildUnknownParam(param);
}
/**
* Build array parameter signature.
* Examples:
* - u32[10] arr -> const uint32_t arr[10]
* - u8[4][4] matrix -> const uint8_t matrix[4][4]
* - string<32>[5] names -> const char names[5][33]
* - string[5] names -> char* names[5] (unbounded string array)
*/
private static _buildArrayParam(param: IParameterInput): string {
const constPrefix = this._getConstPrefix(param);
const dims = param.arrayDimensions!.map((d) => `[${d}]`).join("");
// Unbounded string arrays use char* (array of char pointers)
if (param.isUnboundedString) {
return `${constPrefix}char* ${param.name}${dims}`;
}
// Bounded string arrays use char (dimensions include capacity)
if (param.isString) {
return `${constPrefix}char ${param.name}${dims}`;
}
return `${constPrefix}${param.mappedType} ${param.name}${dims}`;
}
/**
* Build pass-by-value parameter signature.
* Used for: ISR, f32, f64, enums, small unmodified primitives.
* Example: float value, ISR handler, Status s
*/
private static _buildPassByValueParam(param: IParameterInput): string {
const constMod = param.isConst ? "const " : "";
return `${constMod}${param.mappedType} ${param.name}`;
}
/**
* Build non-array string parameter signature.
* string<N> -> const char* name (with auto-const if unmodified)
*/
private static _buildStringParam(param: IParameterInput): string {
const constPrefix = this._getConstPrefix(param);
return `${constPrefix}char* ${param.name}`;
}
/**
* Build pass-by-reference parameter signature.
* C mode: const Point* p
* C++ mode: const Point& p (unless forcePointerSyntax or isOpaqueHandle)
*
* Issue #895: When forcePointerSyntax is set, always use pointer syntax
* because C callback typedefs expect pointers, not C++ references.
* Issue #995: Opaque handles must use pointer syntax because C APIs
* expect pointers to incomplete struct types (e.g., widget_t*).
*/
private static _buildRefParam(
param: IParameterInput,
refSuffix: string,
): string {
const constPrefix = this._getConstPrefix(param);
// Issue #895/#995: Override refSuffix for callback-compatible or opaque handle params
const actualSuffix =
param.forcePointerSyntax || param.isOpaqueHandle ? "*" : refSuffix;
return `${constPrefix}${param.mappedType}${actualSuffix} ${param.name}`;
}
/**
* Build unknown type parameter (pass by value, standard C semantics).
*/
private static _buildUnknownParam(param: IParameterInput): string {
const constMod = param.isConst ? "const " : "";
return `${constMod}${param.mappedType} ${param.name}`;
}
/**
* Get const prefix combining explicit const, auto-const, and forced const.
* Priority: forceConst > isConst > isAutoConst
* Issue #895: forceConst preserves const from callback typedef signature.
* Issue #995: Opaque handles suppress auto-const (they must be passed to
* C APIs that expect non-const pointers).
*/
private static _getConstPrefix(param: IParameterInput): string {
// Issue #995: Opaque handles never get auto-const — they're passed to C APIs
// expecting mutable pointers (e.g., LVGL's lv_obj_t)
const effectiveAutoConst = param.isOpaqueHandle ? false : param.isAutoConst;
// Any source of const results in "const " prefix
if (param.forceConst || param.isConst || effectiveAutoConst) {
return "const ";
}
return "";
}
}
export default ParameterSignatureBuilder;
|