All files / transpiler/output/codegen/assignment/handlers SimpleHandler.ts

82.35% Statements 28/34
72.41% Branches 21/29
100% Functions 4/4
82.35% Lines 28/34

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                                          229x                     229x 181x     48x 48x   48x 38x     10x 10x       10x 229x 229x 229x                     219x 85x     134x 134x   134x 46x     88x     88x                                                   229x     229x 229x 10x       219x 219x       219x        
/**
 * Handler for simple assignments (ADR-109).
 *
 * The fallback case: generates `target = value;` or `target op= value;`
 * Used when no special handling is needed.
 *
 * Issue #845: MISRA 10.3 - For compound assignments on narrower types (i8, i16,
 * u8, u16), expands to explicit cast: `target = (type)(target OP value);`
 * Also handles int-to-float conversions with explicit casts.
 */
import IAssignmentContext from "../IAssignmentContext";
import CodeGenState from "../../../../state/CodeGenState";
import type ICodeGenApi from "../../types/ICodeGenApi";
import NarrowingCastHelper from "../../helpers/NarrowingCastHelper.js";
import TypeResolver from "../../TypeResolver.js";
import TYPE_MAP from "../../types/TYPE_MAP.js";
import CppModeHelper from "../../helpers/CppModeHelper.js";
import COMPOUND_TO_BINARY from "../../types/COMPOUND_TO_BINARY.js";
 
/** Get typed generator reference */
function gen(): ICodeGenApi {
  return CodeGenState.generator as ICodeGenApi;
}
 
/**
 * Try to handle compound assignment on narrow types (MISRA 10.3).
 * Returns the generated code if handled, null otherwise.
 */
function tryHandleCompoundNarrowingCast(
  ctx: IAssignmentContext,
  target: string,
): string | null {
  if (!ctx.isCompound || !ctx.firstIdTypeInfo) {
    return null;
  }
 
  const baseType = ctx.firstIdTypeInfo.baseType;
  const promotedType = NarrowingCastHelper.getPromotedType(baseType);
 
  if (promotedType !== "int" || baseType === "int") {
    return null;
  }
 
  const binaryOp = COMPOUND_TO_BINARY[ctx.cOp];
  Iif (!binaryOp) {
    return null;
  }
 
  const cType = TYPE_MAP[baseType] ?? baseType;
  const expr = `(${target} ${binaryOp} ${ctx.generatedValue})`;
  const castExpr = CppModeHelper.cast(cType, expr);
  return `${target} = ${castExpr};`;
}
 
/**
 * Try to handle cross-type-category conversion (int <-> float).
 * Returns the generated code if handled, null otherwise.
 */
function tryHandleIntToFloatConversion(
  ctx: IAssignmentContext,
  target: string,
): string | null {
  if (ctx.isCompound || !ctx.firstIdTypeInfo || !ctx.valueCtx) {
    return null;
  }
 
  const targetType = ctx.firstIdTypeInfo.baseType;
  const valueType = TypeResolver.getExpressionType(ctx.valueCtx);
 
  if (!valueType) {
    return null;
  }
 
  Eif (
    !NarrowingCastHelper.isCrossTypeCategoryConversion(valueType, targetType)
  ) {
    return null;
  }
 
  if (
    !NarrowingCastHelper.isIntegerType(valueType) ||
    !NarrowingCastHelper.isFloatType(targetType)
  ) {
    return null;
  }
 
  const castedValue = NarrowingCastHelper.wrapIntToFloat(
    ctx.generatedValue,
    targetType,
  );
  return `${target} ${ctx.cOp} ${castedValue};`;
}
 
/**
 * Handle simple variable assignment.
 *
 * @example
 * x <- 5           =>  x = 5;
 * counter +<- 1    =>  counter += 1;
 * i16_val &<- 0xFF =>  i16_val = (int16_t)(i16_val & 0xFF);  // MISRA 10.3
 */
function handleSimpleAssignment(ctx: IAssignmentContext): string {
  const target = gen().generateAssignmentTarget(ctx.targetCtx);
 
  // Try compound assignment narrowing cast (MISRA 10.3)
  const compoundResult = tryHandleCompoundNarrowingCast(ctx, target);
  if (compoundResult) {
    return compoundResult;
  }
 
  // Try int-to-float conversion
  const conversionResult = tryHandleIntToFloatConversion(ctx, target);
  Iif (conversionResult) {
    return conversionResult;
  }
 
  return `${target} ${ctx.cOp} ${ctx.generatedValue};`;
}
 
export default handleSimpleAssignment;