fix(swift): match legacy runtime names by format, not a _Tt substring
analyze_swift_types treated any symbol containing `_Tt` as a Swift observation, and get_objc_protocols treated any symbol containing `_TtP` as a protocol, so Objective-C method labels and message-send shims for selectors such as `_TtReset` or `_TtPing` were reported as Swift names or protocols. Recognize an embedded legacy runtime name only when `_Tt` is followed by nominal kind markers and an identifier length or the `s` module, owned by the Swift classifier and reused by protocol discovery. Fixes #5576 Fixes #5580 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c2858d2aa0
commit
ffe4441522
3 files changed
+53
-3
No files matched your search
@@ -6,6 +6,19 @@ const LEGACY_CATEGORIES = [
|
||||
["_TtE", "extensions"],
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* A legacy Swift runtime name (`_TtC5Hello3Foo`, `_TtPs5Error_`, `_TtGC…`)
|
||||
* embedded in a symbol: `_Tt`, an optional generic `G`, nominal kinds, then a
|
||||
* decimal identifier length or the standard-library module `s`. Objective-C
|
||||
* selectors that merely contain `_Tt` (`_TtReset`, `_TtPing`) do not match.
|
||||
*/
|
||||
const LEGACY_RUNTIME_NAME = /_TtG?[CVOPE]+(?:[1-9]|s)/u;
|
||||
const LEGACY_PROTOCOL_NAME = /_TtP(?:[1-9]|s)/u;
|
||||
|
||||
/** Recognize a symbol that embeds a legacy Swift runtime protocol name. */
|
||||
export const containsLegacySwiftProtocolName = (name: string): boolean =>
|
||||
LEGACY_PROTOCOL_NAME.test(name);
|
||||
|
||||
/** Supported procedure categories derived from Swift symbol encodings. */
|
||||
export type SwiftTypeCategory = (typeof LEGACY_CATEGORIES)[number][1] | "other";
|
||||
|
||||
@@ -25,7 +38,7 @@ export const classifySwiftSymbol = (
|
||||
): { readonly category: SwiftTypeCategory | null } | undefined => {
|
||||
const prefix = /^_?(?:\$[sS]|_T0)/u.exec(name);
|
||||
if (prefix === null) {
|
||||
if (!name.includes("_Tt")) return undefined;
|
||||
if (!LEGACY_RUNTIME_NAME.test(name)) return undefined;
|
||||
return {
|
||||
category:
|
||||
LEGACY_CATEGORIES.find(([prefix]) => name.startsWith(prefix))?.[1] ??
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { categorizeSwiftTypes } from "./symbolAnalysis.js";
|
||||
import {
|
||||
categorizeSwiftTypes,
|
||||
discoverObjcProtocols,
|
||||
} from "./symbolAnalysis.js";
|
||||
|
||||
describe("modern Swift category evidence", () => {
|
||||
it.each([
|
||||
@@ -167,3 +170,36 @@ describe("Swift alias ambiguity", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("Objective-C labels that merely contain _Tt", () => {
|
||||
const labels = (selector: string) => [
|
||||
{ address: "0x1", name: `-[Widget ${selector}]` },
|
||||
{ address: "0x2", name: `_objc_msgSend$${selector}` },
|
||||
];
|
||||
|
||||
it.each(["_TtReset", "_TtPing"])(
|
||||
"are not Swift observations or protocols: %s",
|
||||
(selector) => {
|
||||
expect(categorizeSwiftTypes(labels(selector))).toMatchObject({
|
||||
total: 0,
|
||||
unclassified: [],
|
||||
});
|
||||
expect(discoverObjcProtocols(labels(selector))).toEqual({
|
||||
count: 0,
|
||||
protocols: [],
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps embedded legacy Swift runtime names", () => {
|
||||
expect(
|
||||
discoverObjcProtocols([
|
||||
{ address: "0x1", name: "_OBJC_PROTOCOL_$__TtP5Hello5Proto_" },
|
||||
{ address: "0x2", name: "_TtPs5Error_" },
|
||||
]),
|
||||
).toMatchObject({ count: 2 });
|
||||
expect(
|
||||
categorizeSwiftTypes([{ address: "0x1", name: "-[_TtC5Hello3Foo bar]" }]),
|
||||
).toMatchObject({ total: 1 });
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import type { JsonValue } from "./jsonValue.js";
|
||||
import type { AddressedName } from "./hopperValues.js";
|
||||
import {
|
||||
classifySwiftSymbol,
|
||||
containsLegacySwiftProtocolName,
|
||||
isSwiftMangledSymbolName,
|
||||
type SwiftTypeCategory,
|
||||
} from "./swiftSymbolClassification.js";
|
||||
@@ -48,7 +49,7 @@ export const discoverObjcProtocols = (
|
||||
names.filter(
|
||||
({ name }) =>
|
||||
name.includes(OBJC_PROTOCOL_MARKER) ||
|
||||
name.includes("_TtP") ||
|
||||
containsLegacySwiftProtocolName(name) ||
|
||||
(name.endsWith("Mp") &&
|
||||
classifySwiftSymbol(name)?.category === "protocols"),
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user