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 | 3242x 3242x 3240x 6893x 3233x 3242x 3242x 3240x 744x 744x 13x 3242x 744x 589x 155x 155x 11x 11x 11x | /**
* Which functions are used as ADR-029 callbacks, across the whole program.
*
* A function assigned to a callback typedef must keep the typedef's parameter
* shape, so it may not take #268 auto-const or ADR-006 pass-by-value. That makes
* "is this function used as a callback?" a fact the generated signature depends
* on — and the use can be in a different file from the declaration, so it is a
* cross-file fact.
*
* It was accumulated instead. `FunctionCallAnalyzer` recorded it as a side
* effect while analyzing each file during rendering, into a mutable static that
* `CodeGenState.reset()` deliberately skipped so the entries would survive —
* which means a file rendered early saw fewer callbacks than one rendered late,
* and its signatures were decided on a partial answer. #1511 derived it over
* every tree before anything renders, and #1452 removed the static.
*
* #1825: what remained was running that analyzer over every tree, diagnostics
* discarded, for the map it filled as a side effect -- from the orchestration
* layer, because `PARSE/` may not import `TRANSPILE/`. 1.3 now records where
* each file names what may be a function (`CallbackUseCollector`), and the rule
* that decides which of those uses is a callback is here, its one owner.
*
* #1544: a function is recognized wherever it is declared. Both recognition
* rules once gated on the functions the USING file declares, so a callback
* target in another file was missed and took ordinary parameter rules --
* emitting a signature that no longer matched the typedef it was assigned to,
* at transpile exit 0.
*/
import type SymbolTable from "../3-Declare/SymbolTable";
import type IFileSymbols from "../../types/IFileSymbols";
import type TCallbackUse from "../../types/TCallbackUse";
class CallbackCompatibility {
/**
* @param files every file's `IFileSymbols`, in declaration order
* @param symbolTable the C and C++ header symbols, for the typedefs
* @returns function name to the callback typedef it is used as
*/
static derive(
files: ReadonlyArray<IFileSymbols>,
symbolTable: SymbolTable,
): ReadonlyMap<string, string> {
// #1544: what the PROGRAM declares. The map decides a generated signature
// and the wiring may sit in any file, so recognition needs the same
// whole-program scope the fact has. Read from the symbols, which carry the
// one encoding of a function's name.
const programFunctions = new Set<string>();
for (const file of files) {
for (const symbol of file.symbols) {
if (symbol.kind === "function") {
programFunctions.add(symbol.fullyQualifiedCName);
}
}
}
// In declaration order and source order: a later use of a function wins
// the typedef an earlier one recorded.
const callbacks = new Map<string, string>();
for (const file of files) {
for (const use of file.callbackUses) {
const typedef = CallbackCompatibility.callbackTypedefOf(
use,
symbolTable,
);
if (typedef !== null && programFunctions.has(use.functionName)) {
callbacks.set(use.functionName, typedef);
}
}
}
return callbacks;
}
/**
* The C function-pointer typedef a use assigns its function to, or null
* when the use is not a callback position.
*/
private static callbackTypedefOf(
use: TCallbackUse,
symbolTable: SymbolTable,
): string | null {
if (use.kind === "initializer") {
return symbolTable.isCFunctionPointerTypedef(use.typeName)
? use.typeName
: null;
}
// Issue #895: an argument to a C function whose parameter at that
// position is a function pointer typedef.
const cFunc = symbolTable.getCSymbol(use.callee);
if (cFunc?.kind !== "function" || !cFunc.parameters) return null;
const param = cFunc.parameters[use.argIndex];
Iif (!param) return null;
return symbolTable.isCFunctionPointerTypedef(param.type)
? param.type
: null;
}
}
export default CallbackCompatibility;
|