Three residual ObjC extractor bugs from the #1475 thread, each reproduced
against the real tree-sitter-objc grammar:
1. NS_ASSUME_NONNULL_BEGIN before @interface made the parser fail to emit
a class_interface node at all (the whole interface was swallowed into
ERROR nodes), so headers using the macro produced no class node. Blank
the two argument-less annotation macros to equal-length spaces before
parsing (offset-preserving; macro-free files are byte-identical). The
reporter's "@class breaks it" hypothesis was wrong — only the macro does.
2. Quoted `#import "X.h"` edges dangled once a `.h`/`.m` pair existed: the
target used the bare stem, which the post-pass canonicalizes and then
_disambiguate_colliding_node_ids salts apart by path, so the import
target no longer matched. Resolve the include to a real file (mirroring
_import_c), and repoint imports/imports_from edges to the header variant
in _disambiguate_colliding_node_ids — taking precedence over the
same-source-file salt so a `.m` importing its own `.h` resolves to the
header instead of self-looping. Also repairs the equivalent latent
C-include dangling bug.
3. `[[Foo alloc] init]` produced no edge — walk_calls only reconstructed
selectors and skipped the receiver. Emit a `references` edge from the
allocating method to the class, resolved via the unique-class stub guard
(ensure_named_node + _rewire_unique_stub_nodes) so unknown/ambiguous
names produce no false edge. The calls-to-init edge is deliberately
deferred (init selectors are ambiguous across classes).
Reported by JabberYQ with a precise repro and test repo. Adds regression
tests incl. a self-loop guard on the import edges. Still open on #1475:
dot-syntax property accesses (Bug 5) and @selector target-action (Bug 6b).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>