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 | 9x 1x 8x 8x 2x 28x 2x 93x 17x 76x 26x 26x 4x | /**
* MemberAccessValidator - Shared validation for member access patterns
*
* Extracted from CodeGenerator.generateMemberAccess() and PostfixExpressionGenerator
* to eliminate cross-file duplication of:
* - Write-only register member checks (ADR-013)
* - Self-referential scope access checks (ADR-016/057)
*/
class MemberAccessValidator {
/**
* ADR-013: Validate that a register member is not write-only when reading.
* @param registerKey - underscore-joined key (e.g., "GPIO7_DR")
* @param memberName - member being accessed (e.g., "DR")
* @param displayName - dot-notation for error (e.g., "GPIO7.DR")
* @param registerMemberAccess - map of register member access modifiers
* @param isAssignmentTarget - true to skip check (write context)
*/
static validateRegisterReadAccess(
registerKey: string,
memberName: string,
displayName: string,
registerMemberAccess: ReadonlyMap<string, string>,
isAssignmentTarget: boolean,
): void {
if (isAssignmentTarget) {
return;
}
const accessMod = registerMemberAccess.get(registerKey);
if (accessMod === "wo") {
throw new Error(
`cannot read from write-only register member '${memberName}' ` +
`(${displayName} has 'wo' access modifier)`,
);
}
}
/**
* ADR-016/057: Validate not referencing own scope by name.
* @param scopeName - scope being accessed
* @param memberName - member after scope (for error message)
* @param currentScope - active scope context (null = not in a scope)
*/
static validateNotSelfScopeReference(
scopeName: string,
memberName: string,
currentScope: string | null,
): void {
if (currentScope && scopeName === currentScope) {
throw new Error(
`Error: Cannot reference own scope '${scopeName}' by name. Use 'this.${memberName}' instead of '${scopeName}.${memberName}'`,
);
}
}
/**
* ADR-016/057: Validate that a global entity (enum or register) is accessed
* with 'global.' prefix when inside a scope that doesn't own the entity.
*
* @param entityName - The entity being accessed (e.g., "Color", "GPIO")
* @param memberName - The member after the entity (e.g., "Red", "PIN0")
* @param entityType - "enum" or "register" (for error message)
* @param currentScope - Active scope context (null = not in a scope)
* @param isGlobalAccess - Whether the access used 'global.' prefix
*/
static validateGlobalEntityAccess(
entityName: string,
memberName: string,
entityType: string,
currentScope: string | null,
isGlobalAccess: boolean,
): void {
if (isGlobalAccess) {
return;
}
if (currentScope) {
const belongsToCurrentScope = entityName.startsWith(currentScope + "_");
if (!belongsToCurrentScope) {
throw new Error(
`Error: Use 'global.${entityName}.${memberName}' to access ${entityType} '${entityName}' from inside scope '${currentScope}'`,
);
}
}
}
}
export default MemberAccessValidator;
|