fix(parsers): preserve format boundaries and query occurrence identity

Normalize parsed facts at their owning boundaries across PE exports and certificates, ELF section names, GPU bundles, IL2CPP generic types, dyld slice selection, source maps, environment replay, and JavaScript mapped arguments. Preserve partial facts and explicit unsupported cases; clarify the corresponding documentation.

Validation: 831 affected tests passed with one existing skip across 23 files; build, typecheck/lint, documentation, formatting, and 2133-file test discovery passed. Format controls are synthetic; real Unity, GPU, and ARM-device execution is unverified.

Fixes #6709
Fixes #6688
Fixes #6719
Fixes #6718
Fixes #6704
Fixes #6703
Fixes #6692
Fixes #6723
Fixes #6687
Fixes #6726
Fixes #6696
Fixes #6691
Fixes #6727
This commit is contained in:
morluto committed 2026-10-23 22:01:16 +08:00
1 parent 4193bc5bf8
commit 5f702dd6cc
60 files changed
+2069 -211

No files matched your search

+70 -5
View File
@@ -87,6 +87,59 @@ export const createTypeNamer = (
const name = join(parts.reverse(), "+");
return namespace === "" ? name : join([namespace, name], ".");
}
function* genericDefinitionName(
index: number,
args: readonly string[],
): Generator<void, string> {
if (!Number.isInteger(index) || index < 0 || index >= metadata.types.length)
fail(`type definition ${index} is out of range`);
const chain: number[] = [];
const seen = new Set<number>();
for (let at = index; at !== -1;) {
if (seen.has(at)) fail(`cyclic declaring type at ${at}`);
if (++work % 256 === 0) yield;
const type = metadata.types[at];
if (type === undefined)
return fail(`type definition ${at} is out of range`);
seen.add(at);
chain.push(at);
at = type.declaring_type;
}
let previousArgumentCount = 0;
const parts: string[] = [];
for (const typeIndex of chain.reverse()) {
if (++work % 256 === 0) yield;
const type = metadata.types[typeIndex]!;
const argumentCount = facts.genericTypeArgumentCounts[typeIndex];
if (
argumentCount === undefined ||
argumentCount < previousArgumentCount ||
argumentCount > args.length
)
return fail(
`generic argument count does not match nested type definition ${typeIndex}`,
);
const componentArguments = args.slice(
previousArgumentCount,
argumentCount,
);
previousArgumentCount = argumentCount;
const name = type.name.replace(/`\d+$/u, "");
parts.push(
componentArguments.length === 0
? name
: join([name, "<", join(componentArguments, ", "), ">"]),
);
}
if (previousArgumentCount !== args.length)
fail(
`generic argument count ${args.length} does not match nested type definition ${index}`,
);
const name = join(parts, "+");
const namespace = metadata.types[chain[0]!]!.namespace;
return namespace === "" ? name : join([namespace, name], ".");
}
const byAddress = new Map<bigint, string>();
const active = new Set<bigint>();
const byrefBit = version >= 29 ? 29 : 30;
@@ -145,10 +198,22 @@ export const createTypeNamer = (
}
}
function* generic(data: bigint, depth: number): Generator<void, string> {
const definition =
version >= 27
? yield* name(pointer(data, "generic class type"), depth + 1)
: yield* definitionName(u32(data, "generic class definition"));
let definitionIndex: number;
if (version >= 27) {
const definitionType = pointer(data, "generic class type");
const definitionData = pointer(
definitionType,
"generic class definition",
);
const definitionKind =
(u32(definitionType + 8n, "generic class type attributes") >>> 16) &
0xff;
if (definitionKind !== 0x11 && definitionKind !== 0x12)
fail("generic class type is not a class or value type definition");
definitionIndex = Number(
BigInt.asIntN(32, definitionData & 0xffff_ffffn),
);
} else definitionIndex = u32(data, "generic class definition");
const instance = pointer(data + 8n, "generic class instance");
const count = u32(instance, "generic argument count");
const argv = pointer(instance + 8n, "generic arguments");
@@ -167,7 +232,7 @@ export const createTypeNamer = (
guard(bytes);
args.push(argument);
}
return join([definition.replace(/`\d+$/u, ""), "<", join(args, ", "), ">"]);
return yield* genericDefinitionName(definitionIndex, args);
}
return name;
};