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

81.81% Statements 27/33
72.41% Branches 21/29
100% Functions 3/3
81.81% Lines 27/33

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                                                    267x 219x     48x 48x   48x 38x     10x 10x       10x 267x 267x 267x                     257x 89x     168x 168x   168x 67x     101x     101x                                                   267x         267x 267x 10x       257x 257x       257x        
/**
 * 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 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";
 
/**
 * 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 = CodeGenState.requireGenerator().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;