Objective-C read a file-scope declaration through the generic variable
fallback, which takes only a declarator that is a bare name (`int count;`).
Its most common globals were never indexed: `NSString *const
SDWebImageErrorDomain = @"…";`, `static const NSInteger kMaxRetries = 3;`,
`static dispatch_queue_t queues[4];`. A declaration written inside an
@implementation, file-scope C in the language, was not read at all,
because the class counts as an enclosing scope.
- tree-sitter.ts: Objective-C takes C's declarator branch in
extractVariable (initialized, pointer and array declarators, with the
initializer as the signature), keeping the bare names it always read.
A declaration whose parent is an implementation_definition takes the
variable branch; its globals are qualified under the class, as the
C functions written there already are. A block or function-pointer
variable reads as a prototype, as in C, and stays out.
- c-cpp.ts: isConstDeclaration, C's isConst, is shared, and objc.ts uses
it, so `static const NSInteger kMaxRetries` is a constant.
- name-matcher.ts: a global that a .m or .mm file defines joins the C
types that #2690 made file-local (OBJC_FILE_LOCAL_KINDS). A new
isObjcFileLocalElsewhere drops such a candidate in the exact-match and
fuzzy chains, before one is picked, and isVisibleAcrossFiles applies it
to the pick. Before the pick, so that a header's `extern NSString
*MJConfigFile;` stands for the definition in variables.m. Rejecting only
the pick left Hammerspoon's MJConfigFile references unresolved. Without
the rule, React Native's completionHandler(nil, image) block-parameter
calls reached a completionHandler in another .mm, and #include <vector>
a .mm's vector.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>