mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-21 08:47:04 +08:00
ed8957710f
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>
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
/**
|
|
* Inside an Objective-C `@implementation`, the parser wraps each method,
|
|
* function and declaration in an `implementation_definition` of its own, and
|
|
* the comment above it is that wrapper's sibling, not the method's. So no
|
|
* method, function or static written in an `@implementation` had its doc
|
|
* comment, while the same comment above an `@interface` property was read.
|
|
* The wrapper is now climbed like an `export` statement's.
|
|
*/
|
|
import { describe, it, expect, beforeAll } from 'vitest';
|
|
import { extractFromSource } from '../src/extraction';
|
|
import { initGrammars, loadGrammarsForLanguages } from '../src/extraction/grammars';
|
|
|
|
describe('a doc comment inside an Objective-C @implementation', () => {
|
|
beforeAll(async () => {
|
|
await initGrammars();
|
|
await loadGrammarsForLanguages(['objc']);
|
|
});
|
|
|
|
for (const crlf of [false, true]) {
|
|
const eol = (s: string) => (crlf ? s.replace(/\n/g, '\r\n') : s);
|
|
const label = crlf ? ' (CRLF)' : '';
|
|
|
|
it(`documents the method, function or static below it${label}`, () => {
|
|
const source = [
|
|
'@interface Tests : NSObject',
|
|
'/** The number of runs. */',
|
|
'@property (nonatomic) int runs;',
|
|
'@end',
|
|
'',
|
|
'@implementation Tests',
|
|
'',
|
|
'/** Flags the callbacks set. */',
|
|
'static struct {',
|
|
' int calls;',
|
|
'} g_callbackData;',
|
|
'',
|
|
'/** Runs it. */',
|
|
'- (void)testIt {',
|
|
'}',
|
|
'',
|
|
'// A helper.',
|
|
'static void helper(void) {',
|
|
'}',
|
|
'',
|
|
'/**',
|
|
' * The shared instance.',
|
|
' */',
|
|
'+ (instancetype)shared {',
|
|
' return nil;',
|
|
'}',
|
|
'',
|
|
'/** Synthesized. */',
|
|
'@synthesize runs = _runs;',
|
|
'',
|
|
'- (void)undocumented {',
|
|
'}',
|
|
'',
|
|
'@end',
|
|
'',
|
|
].join('\n');
|
|
const result = extractFromSource('src/Tests.m', eol(source), 'objc');
|
|
const docs = result.nodes
|
|
.filter((n) => n.kind !== 'file' && n.kind !== 'class')
|
|
.map((n) => `${n.kind} ${n.qualifiedName}: ${n.docstring ?? '-'}`);
|
|
expect(docs).toEqual([
|
|
'property Tests::runs: The number of runs.',
|
|
'struct Tests::g_callbackData: Flags the callbacks set.',
|
|
'variable Tests::g_callbackData: Flags the callbacks set.',
|
|
'method Tests::testIt: Runs it.',
|
|
'function Tests::helper: A helper.',
|
|
'method Tests::shared: The shared instance.',
|
|
'method Tests::undocumented: -',
|
|
]);
|
|
});
|
|
}
|
|
});
|