feat: add Objective-C language support#165
Merged
colbymchenry merged 1 commit intoMay 26, 2026
Merged
Conversation
74ca84e to
ed563b2
Compare
a80d5b0 to
f26998e
Compare
Wire tree-sitter-objc for .m/.mm/ObjC headers: classes, protocols, methods, @Property, #import edges, inheritance, and message-send calls.
f26998e to
af197eb
Compare
colbymchenry
added a commit
that referenced
this pull request
May 26, 2026
) Covers #165: tree-sitter-objc extractor for .m / .mm / content-sniffed .h, with full multi-part selectors, @protocol nodes, @Property, message expression call edges, extends/implements edges. Validated on AFNetworking / RestKit / Texture. Disclosed limitations match the README's 'Partial support' note (categories produce duplicate class nodes per category file; .mm ObjC++ parses incompletely under the ObjC grammar; mixed Swift/ObjC bridging out of scope, tracked separately). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
colbymchenry
added a commit
that referenced
this pull request
May 26, 2026
…thod definition #165 extracted multi-part ObjC selectors correctly on the *definition* side (`GET:parameters:headers:progress:success:failure:` as a method node name) but the call-site handler in tree-sitter.ts only built the first selector keyword, so calls never resolved to those definitions. Verified on AFNetworking: 0 → 84 call edges targeting multi-keyword methods after the fix. The grammar emits one `method` field child per keyword on message_expression nodes; collecting them all and joining with `:` reconstructs the full selector (matching what extractObjcMethodName does on the definition side). Regression test in extraction.test.ts covers `[d setObject:@"v" forKey:@"k"]` → `d.setObject:forKey:`, the 3-keyword form, and the self/super-skip case (`touchesBegan:withEvent:`). This is a prerequisite for Swift↔ObjC bridging (the bridge rides the same call-edge path), but stands on its own as a #165 followup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
colbymchenry
added a commit
that referenced
this pull request
May 26, 2026
…ging (#430) Implements the design from `docs/design/mixed-ios-and-react-native-bridging.md`. Closes the cross-language flow gap so `trace` / `callers` / `callees` / `impact` connect end-to-end across language boundaries in real iOS, React Native, and Expo codebases. ## Bridges shipped | Boundary | Mechanism | Real-codebase validation | |---|---|---| | **Swift ↔ Objective-C** | Resolver applying Apple's @objc auto-bridging name math + Cocoa preposition prefixes | Charts (S, 269) · realm-swift (M, 369) · wikipedia-ios (L, 1734) | | **React Native legacy bridge** | Resolver parsing `RCT_EXPORT_MODULE` / `RCT_EXPORT_METHOD` / `RCT_REMAP_METHOD` (ObjC) + `@ReactMethod` (Java/Kotlin) | AsyncStorage (S, ~60) · react-native-svg (M, ~700) · react-native-firebase (L, ~1100) | | **React Native TurboModules** | Resolver treating `Native<X>.ts` spec interface as ground truth | via RNSvg + RNFirebase subsets | | **Native → JS events** | Synthesizer matching native `sendEventWithName:`/`emit(...)` to JS `addListener('e', handler)` keyed by literal event name; falls back to enclosing constant/variable for wrapper-API parameter handlers | RNGeolocation (S) · RNFirebase (L) | | **Expo Modules** | Framework extract synthesizes `method` nodes from Swift/Kotlin `Module { Name("X"); Function("y") { ... } }` DSL | expo-haptics (S, 14) · expo-camera (M, 72) · ExpoSweep (L, 332, 7 packages) | | **Fabric + legacy Paper view components** | Extract `component` + `property` nodes from Codegen `codegenNativeComponent<Props>('Name', ...)` specs AND legacy `RCT_EXPORT_VIEW_PROPERTY` / `@ReactProp` macros, then synthesize component → native class by name+suffix convention | react-native-segmented-control (S, legacy) · react-native-screens (M, Codegen) · react-native-skia (L, hybrid monorepo) | ## Bug fixes surfaced along the way - `tree-sitter.ts` message_expression — multi-keyword ObjC call sites now reconstruct `a:b:` selectors so they resolve to multi-part method definitions (gap discovered post-#165; 0 → 84 call edges to `GET:parameters:...` style methods on AFNetworking). - `src/index.ts` resolver lifecycle — `indexAll()` now re-initializes the resolver after extraction so framework `detect()` sees the populated index. Pre-existing latent bug that affected UIKit and SwiftUI resolvers too. - `src/extraction/index.ts` `buildDetectionContext` — added `listDirectories` so framework detect() can probe monorepo subpackages uniformly (fix needed for react-native-skia detection). ## Regression check on 5 control repos | Repo | Result | |---|---| | Express (small JS) | ✅ unchanged — 266 routes, express framework detected | | Excalidraw (medium TS/React) | ✅ 9284 nodes (CLAUDE.md baseline ~9290); canonical `trace(mutateElement, renderStaticScene)` returns the flow | | Django realworld (Python) | ✅ django framework detected, 16 routes | | Spring petclinic (Java) | ✅ spring framework detected, 17 routes | | Texture (pure ObjC, large) | ✅ exactly matches #165 baseline: 4702 methods, 894 classes, 808/808 file coverage, 913 multi-keyword selectors, 55 protocols, 1036 properties | ## Tests 928 passing (+87 net new bridge tests across the 5 channels); 2 pre-existing skips. The mcp-staleness-banner / watcher parallel flakiness is unchanged by this work (different test fails each run, all pass in isolation; pre-existing on main). ## Documentation - README: new 'Mixed iOS / React Native / Expo bridging' section with the per-boundary table and validation-corpus links. - CHANGELOG `[Unreleased]`: full entry per bridge with measurements. - `docs/design/mixed-ios-and-react-native-bridging.md`: the design doc (§8 measurements filled in across §8a-§8g). - `docs/design/dynamic-dispatch-coverage-playbook.md` §6 coverage matrix: six new rows. - `.claude/skills/agent-eval/corpus.json`: four new sections covering 15 real GitHub repos for the eval harness. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
colbymchenry
added a commit
that referenced
this pull request
May 26, 2026
…435) The 0.9.5 release tag included all of: - Shared MCP daemon (#411) - Per-file staleness banner (#403) - Worktree-borrow detection (#312) - Watcher inotify-budget fix (#276) - Objective-C indexing (#165) - Mixed iOS / React Native / Expo cross-language bridging (#430) But the [0.9.5] block in CHANGELOG.md only had two Fixed entries (the fs-based change detection and default-ignore set), because the major feature entries were still sitting under [Unreleased] when 0.9.5 was tagged. release.yml extracts release notes from the matching version block, so the published v0.9.5 release notes are missing the bulk of what shipped. Move all the [Unreleased] entries that pre-date 0.9.5's tag (commit 318cda1) into [0.9.5], and reset [Unreleased] to empty. The GitHub Release notes for v0.9.5 get updated separately via gh release edit. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
KannaKuron
added a commit
to KannaKuron/codegraph4bevy
that referenced
this pull request
May 26, 2026
…, watcher fixes Key upstream changes merged: - feat(extraction): Objective-C language support (colbymchenry#165) - feat(mcp): share one serve --mcp per project across MCP clients (colbymchenry#411) - feat(mcp): per-file staleness banner + tunable watcher debounce (colbymchenry#403) - feat(mcp): detect borrowed git worktree index (colbymchenry#312) - feat(index): default-ignore dependency/build/cache dirs (colbymchenry#407) - feat(resolution): mixed iOS / React Native / Expo bridging (colbymchenry#430) - fix(watcher): exclude ignored dirs before watching (colbymchenry#276) - fix(sync): filesystem-based change detection (colbymchenry#414) Conflicts resolved: CLAUDE.md, .cursor/rules, extraction tests (kept split), MCP files (tools/server-instructions/transport/engine), package.json (kept jieba) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds partial Objective-C support to the tree-sitter extraction pipeline so iOS/macOS codebases can be indexed with the same graph queries as other languages.
Wiring
objcinLANGUAGES,WASM_GRAMMAR_FILES(tree-sitter-objc.wasmfromtree-sitter-wasms, ABI 14), andEXTRACTORS.m/.mm→objc; classify.has Objective-C when content matches@interface/@implementation/@protocol/@synthesize(after the existing C++.hheuristic)isSourceFile+.gitignore— no separateincludeglobs neededExtraction (
objc.ts)@interfaceemits one class node;@implementationreuses it viavisitNode(avoids duplicate class/method nodes)@protocol→protocolnodesmethod_definitiononly; full multi-part selectors (doThing:with:) viaresolveName@propertyviaextractPropertyName(walksstruct_declarator/pointer_declarator)function_definitionand#import(preproc_include)extendsfor superclass;implementsfor angle-bracket protocols on@interfacecall_expressionand[receiver message](message_expression) call edgesCore hooks
resolveName/extractPropertyNameonLanguageExtractor(used by ObjC; generic fallbacks unchanged)extractInheritanceearly-return branch forclass_interface.h,.m,.mmDocs & eval corpus
.mmObjC++ limits)[Unreleased]entry with known limitationsBenchmark (local dev build)
Known limitations
[[Class alloc] init]) only record the innermost method nameinstantiatesedge for[Class alloc]patterns@protocol Foo <Bar>refinement lists not yet wired toimplementsedges.mmfiles may parse incompletely under the ObjC grammarTest plan
npm run buildnpx vitest run __tests__/extraction.test.ts -t "Objective-C"(7 tests)node scripts/add-lang/verify-extraction.mjson sample + Masonry / FMDB / SDWebImage