Skip to content

fix(objc): a struct links the types its members are declared with - #3174

Merged
colbymchenry merged 1 commit into
mainfrom
claude/fix-objc-member-types
Nov 1, 2026
Merged

colbymchenry merged 1 commit into
mainfrom
claude/fix-objc-member-types

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Summary

An Objective-C struct now links the types its members are declared with, and an alias what it names, as C and C++ do since #3144. On GNUstep's libs-base 1.6.2 had 153 such relations and main 0. No benchmark repo has Objective-C, so REG couldn't see it.

Third of a stack of four, on top of #3173.

Root cause

#2394 removed the false extends that linked a struct to its members' types. #3144 put references in its place, gated on c and cpp.

The fix

Extraction writes the same member and alias references for objc, in the wasm extractor, which is all Objective-C has.

Resolution is name matching, which already knows Objective-C's rules (a type an .m defines is its own), with two limits in the spirit of the C++ lookup:

  • only a type can be named there, so a function or a variable of the name is no candidate, and no other strategy sees the ref;
  • a class's node in some other .m, an @implementation or a category, yields to a header's, the class's own first. GNUstep's NSString has 14 class nodes, in test files too.

Explore treats these edges as it does C's: no window per member, and out of the rank walk.

A header that reads as C and names an Objective-C type stays unlinked, as on 1.6.2: id in ObjFW's ObjFWRT.h, 18 refs over the five repos.

Validation

Windows 11, main 4499d00.

Tests. All 6 new tests fail on main, and the explore test fails on the tools.ts line alone. All pass. 4 mutations each fail a test.

A/B against main.

Repo Result
libs-base +421, nothing lost or moved
ObjFW +114, nothing lost or moved
FLEX +38, nothing lost or moved
SDWebImage +29, nothing lost or moved
hammerspoon +20, nothing lost or moved
rocksdb, redis, leveldb, gin, flask nothing from this commit

Against 1.6.2 on libs-base. 140 of its 153 hold at the same site with the same type: 50 on the same node, 90 on a header's where 1.6.2 had a category in an .m. The other 13 are members of unnamed structs in test functions, which main names (main::vector), and they link there too.

Read. 74 against source over the five repos, every one a true relation. A framework class lands on a category of it where the project has one, as a method's type reference does. GNUstep's own @interface NSString is no node on either arm.

Impact. impact pause_event on the fixture: 2 symbols on 1.6.2, 1 on main, 4 here.

Cost. No kernel change: Objective-C isn't routed to it. The check reads the holder's kind from its id, so a method's reference costs no node read. libs-base, median of 5 interleaved rounds: CPU 27.92 to 26.94 s, wall 7.88 to 7.73 s, level.

Suite. 857 files passed and 6 skipped, 10,651 tests passed, 2 expected fail, 87 skipped, 4 workers, with the kernel, on the stack one clean rebase back (719ea417 on main 3bd9949). After the rebase onto 087de4c, whose hunks are apart from these: 138 files and 2,224 tests of the C, C++, Objective-C, Python and extraction suites pass on the tip.

🤖 Generated with Claude Code

@colbymchenry
colbymchenry force-pushed the claude/fix-c-macro-renames branch from 6c87525 to c4683d1 Compare November 1, 2026 05:10
Base automatically changed from claude/fix-c-macro-renames to main November 1, 2026 05:10
PR 2394 removed the false `extends` that linked a struct to its members'
types, and PR 3144 put `references` in its place for C and C++ only. An
Objective-C struct stayed unlinked, so impact on a type missed what holds
one: on GNUstep's libs-base 1.6.2 had 153 such relations and main 0. No
benchmark repo has Objective-C.

Extraction writes the same member and alias references for `objc`, in the
wasm extractor, which is all Objective-C has. Resolution is name matching,
which already knows Objective-C's rules (a type an `.m` defines is its own),
with two limits in the spirit of the C++ lookup: only a type can be named
there, so a function or a variable of the name is no candidate and no other
strategy sees the ref; and a class's node in some other `.m`, an
`@implementation` or a category, yields to a header's, the class's own first.
GNUstep's `NSString` has 14 class nodes, in test files too. Explore treats
these edges as it does C's: no window per member, and out of the rank walk.

A header that reads as C and names an Objective-C type stays unlinked, as on
1.6.2: `id` in ObjFW's ObjFWRT.h, 18 refs over the five repos.

Validation against main 4499d00:
- Tests: all 6 fail on main, and the explore test on the tools.ts line alone;
  all pass. 4 mutations each fail a test.
- libs-base +421, nothing lost or moved. 140 of 1.6.2's 153 hold at the same
  site with the same type: 50 on the same node, 90 on a header's where 1.6.2
  had a category in an `.m`. The other 13 are members of unnamed structs in
  test functions, which main names (`main::vector`), and they link there too.
- ObjFW +114, FLEX +38, SDWebImage +29, hammerspoon +20, nothing lost or moved.
- 74 read against source over the five repos, every one a true relation. A
  framework class lands on a category of it where the project has one, as a
  method's type reference does; GNUstep's own `@interface NSString` is no node
  on either arm.
- `impact pause_event` on the fixture: 2 symbols on 1.6.2, 1 on main, 4 here.
- rocksdb, redis, leveldb, gin, flask: nothing from this commit.
- No kernel change: Objective-C isn't routed to it. The check reads the
  holder's kind from its id, so a method's reference costs no node read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@colbymchenry
colbymchenry force-pushed the claude/fix-objc-member-types branch from 841c605 to 6951c6c Compare November 1, 2026 05:10
@colbymchenry
colbymchenry merged commit 79c25b7 into main Nov 1, 2026
@colbymchenry
colbymchenry deleted the claude/fix-objc-member-types branch November 1, 2026 05:11
bompus added a commit to bompus/codegraph that referenced this pull request Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant