mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-02 02:11:29 +00:00
* docs: add Objective-C fork provider notes * feat(objective-c): add deterministic provider and grammar * feat(objective-c): finalize provider MVP * fix(objective-c): harden provider integration * fix(objective-c): normalize bare macro markers * docs(objective-c): integrate provider documentation * fix(objective-c): harden resolution and header classification * fix(objective-c): complete provider follow-ups * fix: address Objective-C review follow-ups * chore: format Objective-C grammar sources * fix(objective-c): harden review follow-ups * Address PR review feedback (#3179) Keep Objective-C chunking and macro recovery aligned with the grammar, and stop Community MEMBER_OF edges from leaking into symbol context. Co-authored-by: Cursor <cursoragent@cursor.com> * Address follow-up review on ObjC chunking and language fallback. Keep preprocessor directive text from changing file-scope brace depth, group real ivar nodes, skip header modifiers, and restore Rakefile/Gemfile detection through getLanguageFromFilename. Co-authored-by: Cursor <cursoragent@cursor.com> * Parse Objective-C headers with the objc grammar in embeddings. ensureAndParse and structural extraction now use the same content classifier as ingest, including method snippets from .h files, so Protocol/Category/Class chunks are not re-parsed as C++. Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) Keep file-scope macro elision off C line splices and @interface/@protocol/@implementation bodies, and attach ivar attributes to the following instance variable when chunking. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(bench): rebaseline Objective-C CSV emit * feat(objective-c): add workspace resolution and linear emit benches Plain .h files are classified as C++, so the ObjC pass could not resolve #import of those headers. Load a C/C#-style workspace once per pass, and keep protocol-candidate USES linear. Refs #3179 Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) - Compare LadybugDB labels() as a scalar when excluding Community MEMBER_OF edges. - Walk superclass members, skip file-static C sibling defs, and ignore comments in ObjC header/macro scans. Note: pre-existing failure in objective-c-provider integration (worker-pool ready timeout) not addressed by this PR. Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) Emit Objective-C declaration captures so compilation-unit siblings can share header/implementation bindings, and keep class vs protocol visibility groups distinct. Note: pre-existing failure in worker-pool startup (GITNEXUS_WORKER_READY_TIMEOUT_MS) not addressed by this PR. Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) Emit every comma-separated property/ivar declarator, and count @interface after a multiline block comment closes so in-declaration macros stay intact. Note: pre-existing failure in worker-pool startup (GITNEXUS_WORKER_READY_TIMEOUT_MS) not addressed by this PR. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: ximengkai <ximengkai@soyoung.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
195 lines
7.6 KiB
TypeScript
195 lines
7.6 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { preprocessObjectiveCMacroMarkers } from '../../src/core/ingestion/languages/objective-c/macro-marker-preprocess.js';
|
|
|
|
describe('preprocessObjectiveCMacroMarkers', () => {
|
|
it('elides bare file-scope markers and preserves positions', () => {
|
|
const source = [
|
|
'#define RCT_EXTERN_C_BEGIN',
|
|
'#define RCT_EXTERN_C_END',
|
|
'RCT_EXTERN_C_BEGIN',
|
|
'typedef struct RCTMethodInfo {',
|
|
' const char *const jsName;',
|
|
'} RCTMethodInfo;',
|
|
'RCT_EXTERN_C_END',
|
|
'@protocol RCTBridgeModule <NSObject>',
|
|
'- (void)run;',
|
|
'@end',
|
|
'',
|
|
].join('\r\n');
|
|
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'RCTBridgeModule.h');
|
|
|
|
expect(normalized).toHaveLength(source.length);
|
|
expect(normalized.split('\r\n')).toHaveLength(source.split('\r\n').length);
|
|
expect(normalized).toContain('#define RCT_EXTERN_C_BEGIN');
|
|
expect(normalized).toContain('@protocol RCTBridgeModule <NSObject>');
|
|
expect(normalized).toContain(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
expect(normalized).toContain(' '.repeat('RCT_EXTERN_C_END'.length));
|
|
expect(preprocessObjectiveCMacroMarkers(normalized, 'RCTBridgeModule.h')).toBe(normalized);
|
|
});
|
|
|
|
it('leaves non-marker syntax, strings, and comments untouched', () => {
|
|
const source = [
|
|
'void marker(void) {',
|
|
' RCT_EXTERN_C_BEGIN',
|
|
'}',
|
|
'RCT_EXTERN_C_END()',
|
|
'RCT_EXTERN_C_END;',
|
|
'#define RCT_EXTERN_C_END',
|
|
'#define RCT_MARKER_SEQUENCE \\',
|
|
'RCT_EXTERN_C_END',
|
|
'const char *value = "RCT_EXTERN_C_END";',
|
|
'// RCT_EXTERN_C_END',
|
|
'/*',
|
|
'RCT_EXTERN_C_END',
|
|
'*/',
|
|
'',
|
|
].join('\n');
|
|
|
|
expect(preprocessObjectiveCMacroMarkers(source, 'Example.m')).toBe(source);
|
|
});
|
|
|
|
it('does not rewrite markers inside a continued line comment', () => {
|
|
const source = [
|
|
'// The following token remains part of this comment \\',
|
|
'RCT_EXTERN_C_END',
|
|
'RCT_EXTERN_C_BEGIN',
|
|
'',
|
|
].join('\n');
|
|
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'CommentedMarker.h');
|
|
|
|
expect(normalized).toHaveLength(source.length);
|
|
expect(normalized).toContain('RCT_EXTERN_C_END');
|
|
expect(normalized.split('\n')[2]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
});
|
|
|
|
it('recognizes form feed and vertical tab as preprocessing whitespace', () => {
|
|
const source = [
|
|
'\f#define RCT_EXTERN_C_BEGIN',
|
|
'\v#define RCT_EXTERN_C_END',
|
|
'\fRCT_EXTERN_C_BEGIN',
|
|
'\vRCT_EXTERN_C_END',
|
|
'@protocol RCTBridgeModule <NSObject>',
|
|
'@end',
|
|
'',
|
|
].join('\n');
|
|
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'WhitespaceMarkers.h');
|
|
|
|
expect(normalized).toHaveLength(source.length);
|
|
expect(normalized).toContain('\f#define RCT_EXTERN_C_BEGIN');
|
|
expect(normalized).toContain('\v#define RCT_EXTERN_C_END');
|
|
expect(normalized.split('\n')[2]).toBe(' '.repeat('\fRCT_EXTERN_C_BEGIN'.length));
|
|
expect(normalized.split('\n')[3]).toBe(' '.repeat('\vRCT_EXTERN_C_END'.length));
|
|
expect(normalized).toContain('@protocol RCTBridgeModule <NSObject>');
|
|
});
|
|
|
|
it('preserves directives preceded by comments', () => {
|
|
const source = [
|
|
'/**/ #define RCT_MARKER_SEQUENCE \\',
|
|
'RCT_EXTERN_C_END',
|
|
'/* leading comment',
|
|
' */ #define RCT_SECOND_SEQUENCE \\',
|
|
'RCT_EXTERN_C_BEGIN',
|
|
'',
|
|
].join('\n');
|
|
|
|
expect(preprocessObjectiveCMacroMarkers(source, 'CommentDirective.h')).toBe(source);
|
|
});
|
|
|
|
it('does not rewrite markers inside a multiline function-like macro invocation', () => {
|
|
const source = ['SOME_MACRO(', 'RCT_EXTERN_C_END', ')', 'RCT_EXTERN_C_BEGIN', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'MultilineMacro.m');
|
|
|
|
expect(normalized.split('\n')[1]).toBe('RCT_EXTERN_C_END');
|
|
expect(normalized.split('\n')[3]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
});
|
|
|
|
it('does not treat directive replacement braces as file-scope nesting', () => {
|
|
const source = ['#define WRAP {', 'RCT_EXTERN_C_BEGIN', 'RCT_EXTERN_C_END', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'DirectiveBrace.h');
|
|
|
|
expect(normalized.split('\n')[0]).toBe('#define WRAP {');
|
|
expect(normalized.split('\n')[1]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
expect(normalized.split('\n')[2]).toBe(' '.repeat('RCT_EXTERN_C_END'.length));
|
|
});
|
|
|
|
it('does not rewrite markers inside a block comment opened on a directive line', () => {
|
|
const source = ['#define X /*', 'RCT_EXTERN_C_BEGIN', '*/', 'RCT_EXTERN_C_END', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'DirectiveComment.h');
|
|
|
|
expect(normalized.split('\n')[1]).toBe('RCT_EXTERN_C_BEGIN');
|
|
expect(normalized.split('\n')[3]).toBe(' '.repeat('RCT_EXTERN_C_END'.length));
|
|
});
|
|
|
|
it('requires a valid identifier start for a bare marker', () => {
|
|
const source = ['123_RCT_EXTERN_C_END', 'RCT_EXTERN_C_END', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'NumericMarker.h');
|
|
|
|
expect(normalized.split('\n')[0]).toBe('123_RCT_EXTERN_C_END');
|
|
expect(normalized.split('\n')[1]).toBe(' '.repeat('RCT_EXTERN_C_END'.length));
|
|
});
|
|
|
|
it('does not rewrite an object-like macro continued from a spliced statement', () => {
|
|
const source = ['int value = \\', 'FEATURE_VALUE', ';', 'RCT_EXTERN_C_BEGIN', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'SplicedStatement.m');
|
|
|
|
expect(normalized.split('\n')[1]).toBe('FEATURE_VALUE');
|
|
expect(normalized.split('\n')[3]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
});
|
|
|
|
it('tracks declarations that follow a leading block comment', () => {
|
|
const source = [
|
|
'/* documentation */ @interface Widget',
|
|
'DECLARE_WIDGET_MEMBERS',
|
|
'@end',
|
|
'RCT_EXTERN_C_BEGIN',
|
|
'',
|
|
].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'DocumentedWidget.h');
|
|
const lines = normalized.split('\n');
|
|
|
|
expect(lines[1]).toBe('DECLARE_WIDGET_MEMBERS');
|
|
expect(lines[3]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
});
|
|
|
|
it('tracks a declaration that follows a multiline block comment close', () => {
|
|
const source = ['/*', '*/ @interface Widget', 'DECLARE_WIDGET_MEMBERS', '@end', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'MultilineCommentWidget.h');
|
|
const lines = normalized.split('\n');
|
|
|
|
expect(lines[2]).toBe('DECLARE_WIDGET_MEMBERS');
|
|
});
|
|
|
|
it('elides a marker after a directive that ends in a continued line comment', () => {
|
|
const source = ['#define X // \\', 'text', 'RCT_EXTERN_C_BEGIN', ''].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'DirectiveLineComment.h');
|
|
|
|
expect(normalized.split('\n')[1]).toBe('text');
|
|
expect(normalized.split('\n')[2]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
});
|
|
|
|
it('does not rewrite bare macros inside @interface / @protocol / @implementation', () => {
|
|
const source = [
|
|
'@interface Widget',
|
|
'DECLARE_WIDGET_MEMBERS',
|
|
'@end',
|
|
'@protocol WidgetDelegate',
|
|
'DECLARE_WIDGET_DELEGATE',
|
|
'@end',
|
|
'@implementation Widget',
|
|
'DECLARE_WIDGET_IVARS',
|
|
'@end',
|
|
'RCT_EXTERN_C_BEGIN',
|
|
'',
|
|
].join('\n');
|
|
const normalized = preprocessObjectiveCMacroMarkers(source, 'Widget.h');
|
|
const lines = normalized.split('\n');
|
|
|
|
expect(lines[1]).toBe('DECLARE_WIDGET_MEMBERS');
|
|
expect(lines[4]).toBe('DECLARE_WIDGET_DELEGATE');
|
|
expect(lines[7]).toBe('DECLARE_WIDGET_IVARS');
|
|
expect(lines[9]).toBe(' '.repeat('RCT_EXTERN_C_BEGIN'.length));
|
|
});
|
|
});
|