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 | 47x 1944x 1944x 1944x 362x 1944x 12x 12x 9x 9x | /**
* ADR-051's `safe_div` / `safe_mod` calls, and which argument they write to.
*
* #1322: two rules ask the same thing of these calls and they are not the same
* rule. ADR-051 governs their SHAPE -- four arguments, the first a variable to
* receive the quotient (E0884/E0885). ADR-013 governs const-ness, and the
* first argument is written through, so a `const` there is an assignment to a
* const exactly as `K <- 1` is (E0877).
*
* The fact both need -- "argument 0 of this call is an output parameter" -- is
* a property of these two builtins and belongs in one place. Before it was
* shared, the const rule could not see the site at all: it walks assignment
* targets, and this is a call argument. `safe_div(K, 10, 2, 0)` emitted `&K`
* into a non-const pointer parameter, which gcc rejects with
* `discards 'const' qualifier`, at exit 0.
*/
import * as Parser from "../../../PARSE/2-Parse/grammar/CNextParser";
import ExpressionUnwrapper from "../../../utils/ExpressionUnwrapper";
/** The two ADR-051 builtins, which share a signature. */
const SAFE_DIVISION = new Set(["safe_div", "safe_mod"]);
class SafeDivision {
/**
* The call this postfix expression is, when it is one of ADR-051's, with the
* arguments as written. Null for anything else.
*
* The name must be a bare primary identifier followed by exactly one call
* op: `safe_div(...)`. A member access that happens to end in the same name
* is a different function.
*/
static callOf(ctx: Parser.PostfixExpressionContext): {
name: string;
args: Parser.ExpressionContext[];
} | null {
const primary = ctx.primaryExpression();
const ops = ctx.postfixOp();
if (!primary || ops.length !== 1) return null;
const name = primary.IDENTIFIER()?.getText();
if (name === undefined || !SAFE_DIVISION.has(name)) return null;
Iif (ops[0].LPAREN() === null) return null;
return { name, args: ops[0].argumentList()?.expression() ?? [] };
}
/**
* The name the call writes its result to, or null when the first argument is
* not a plain variable name. ADR-051 needs a storage location: the helper
* takes its address.
*/
static outputName(args: readonly Parser.ExpressionContext[]): string | null {
const first = args[0];
return first === undefined
? null
: ExpressionUnwrapper.getSimpleIdentifier(first);
}
}
export default SafeDivision;
|