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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | 29x 28x 1x 28x 6x 6x 24x 17x 7x 6x 6x 6x 6x 2x 4x 4x 2x 2x 2x 2x 17x 17x 7x 10x 7x 3x 4x 2x 2x 3x 1x 1x 1x 1x | /**
* SizeofResolver - Handles sizeof expression generation
*
* Extracted from CodeGenerator to reduce complexity.
* Uses CodeGenState for all state access.
*
* ADR-023: sizeof expression handling with safety checks:
* - E0601: sizeof on array parameter is error (returns pointer size)
* - E0602: Side effects in sizeof are error (MISRA C:2012 Rule 13.6)
*/
import * as Parser from "../../../logic/parser/grammar/CNextParser";
import CodeGenState from "../CodeGenState";
import ExpressionUnwrapper from "../utils/ExpressionUnwrapper";
/**
* Callbacks for operations that require CodeGenerator context.
* These are the minimal dependencies that can't be replaced with CodeGenState.
*/
interface ISizeofCallbacks {
generateType: (ctx: Parser.TypeContext) => string;
generateExpression: (ctx: Parser.ExpressionContext) => string;
hasSideEffects: (ctx: Parser.ExpressionContext) => boolean;
}
/**
* Resolves sizeof expressions to C code.
*/
export default class SizeofResolver {
/**
* Generate sizeof expression.
* sizeof(type) -> sizeof(c_type)
* sizeof(variable) -> sizeof(variable)
*/
static generate(
ctx: Parser.SizeofExpressionContext,
callbacks: ISizeofCallbacks,
): string {
// Check if it's sizeof(type) or sizeof(expression)
// Note: Due to grammar ambiguity, sizeof(variable) may parse as sizeof(type)
// when the variable name matches userType (just an identifier)
if (ctx.type()) {
return this.sizeofType(ctx.type()!, callbacks);
}
return this.sizeofExpression(ctx.expression()!, callbacks);
}
/**
* Handle sizeof(type) - may actually be sizeof(variable) due to grammar ambiguity
*/
private static sizeofType(
typeCtx: Parser.TypeContext,
callbacks: ISizeofCallbacks,
): string {
// qualifiedType matches IDENTIFIER.IDENTIFIER, could be struct.member
if (typeCtx.qualifiedType()) {
const result = this.sizeofQualifiedType(typeCtx.qualifiedType()!);
if (result) return result;
// Fall through to generateType for actual type references (Scope.Type)
}
// userType is just IDENTIFIER, could be a variable reference
if (typeCtx.userType()) {
return this.sizeofUserType(typeCtx.getText());
}
// It's a primitive or other type - generate normally
return `sizeof(${callbacks.generateType(typeCtx)})`;
}
/**
* Handle sizeof(qualified.type) - may be struct.member access
* Returns null if this is actually a type reference (Scope.Type)
*/
private static sizeofQualifiedType(
qualifiedCtx: Parser.QualifiedTypeContext,
): string | null {
const identifiers = qualifiedCtx.IDENTIFIER();
const firstName = identifiers[0].getText();
const memberName = identifiers[1].getText();
// Check if first identifier is a local variable (struct instance)
if (CodeGenState.localVariables.has(firstName)) {
return `sizeof(${firstName}.${memberName})`;
}
// Check if first identifier is a parameter (struct parameter)
const paramInfo = CodeGenState.currentParameters.get(firstName);
if (paramInfo) {
const sep = paramInfo.isStruct ? "->" : ".";
return `sizeof(${firstName}${sep}${memberName})`;
}
// Check if first identifier is a global variable
// If not a scope or enum, it's likely a global struct variable
Iif (
!CodeGenState.isKnownScope(firstName) &&
!CodeGenState.isKnownEnum(firstName)
) {
return `sizeof(${firstName}.${memberName})`;
}
// It's an actual type reference (Scope.Type), return null to fall through
return null;
}
/**
* Handle sizeof(identifier) - could be variable or type name
*/
private static sizeofUserType(varName: string): string {
// Check if it's a known parameter
const paramInfo = CodeGenState.currentParameters.get(varName);
if (paramInfo) {
return this.sizeofParameter(varName, paramInfo);
}
// Check if it's a known local variable, struct type, or enum type
// For all these cases, generate sizeof(name) directly
// Unknown identifiers are also treated as variables for safety
return `sizeof(${varName})`;
}
/**
* Handle sizeof on a parameter - validates and generates appropriate code
*/
private static sizeofParameter(
varName: string,
paramInfo: { isArray?: boolean; isCallback?: boolean; isStruct?: boolean },
): string {
// E0601: Array parameters decay to pointers
if (paramInfo.isArray) {
this.throwArrayParamSizeofError(varName);
}
// For pass-by-reference parameters (non-array, non-callback, non-struct),
// use pointer dereference
if (!paramInfo.isCallback && !paramInfo.isStruct) {
return `sizeof(*${varName})`;
}
return `sizeof(${varName})`;
}
/**
* Throw E0601 error for sizeof on array parameter
*/
private static throwArrayParamSizeofError(varName: string): never {
throw new Error(
`Error[E0601]: sizeof() on array parameter '${varName}' returns pointer size. ` +
`Use ${varName}.length for element count or sizeof(elementType) * ${varName}.length for bytes`,
);
}
/**
* Handle sizeof(expression) with validation
*/
private static sizeofExpression(
expr: Parser.ExpressionContext,
callbacks: ISizeofCallbacks,
): string {
// E0601: Check if expression is an array parameter
const varName = ExpressionUnwrapper.getSimpleIdentifier(expr);
Iif (varName) {
const paramInfo = CodeGenState.currentParameters.get(varName);
if (paramInfo?.isArray) {
this.throwArrayParamSizeofError(varName);
}
}
// E0602: Check for side effects
Iif (callbacks.hasSideEffects(expr)) {
throw new Error(
`Error[E0602]: sizeof() operand must not have side effects (MISRA C:2012 Rule 13.6)`,
);
}
return `sizeof(${callbacks.generateExpression(expr)})`;
}
}
|