mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-02 02:11:29 +00:00
* fix(rust): respect Cargo target boundaries in name fallback * fix(rust): read Cargo sources through validated file descriptors * fix(rust): require matching imports for crate-root guesses * fix(rust): require Cargo root identity for cross-target imports * fix(rust): enforce Cargo identity across fallback imports * fix(rust): keep Cargo membership on typical derive/macros (#3294) Abort only genuine unknown expansion, ignore Cargo artifact layouts instead of every `target` path segment, and require a covering import for unanswered crate-root name fallback so #3253 still holds on ordinary Rust sources. Co-authored-by: Cursor <cursoragent@cursor.com> * test(rust): gate Cargo target membership in CI (#3253) Add a parse-dispatch-rounds-style bench so derive/macro abort, target-path globs, and superlinear membership walks fail in CI instead of staying graph-invisible. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(rust): verify Cargo macro and re-export evidence * style(bench): format Cargo membership benchmark * fix(rust): require imports for cross-file root guesses --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
103 lines
4.7 KiB
TypeScript
103 lines
4.7 KiB
TypeScript
/**
|
||
* Regression tests for Rust scope-resolution coverage gaps (issue #1934).
|
||
*/
|
||
import { describe, it, expect } from 'vitest';
|
||
import { emitRustScopeCaptures } from '../../../src/core/ingestion/languages/rust/index.js';
|
||
import type { CaptureMatch } from 'gitnexus-shared';
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// F66/F68 — let binding patterns (identifier-only, works with let mut x)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
describe('F66/F68 — let binding pattern shapes', () => {
|
||
it('bare identifier let binding emits @declaration.variable', () => {
|
||
const src = `fn f() { let x = 1; }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const vars = matches.filter((m) => m['@declaration.variable']);
|
||
expect(vars.length).toBe(1);
|
||
expect(vars[0]['@declaration.name'].text).toBe('x');
|
||
});
|
||
|
||
it('let mut x emits @declaration.variable', () => {
|
||
const src = `fn f() { let mut x = 1; }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const vars = matches.filter((m) => m['@declaration.variable']);
|
||
expect(vars.length).toBe(1);
|
||
expect(vars[0]['@declaration.name'].text).toBe('x');
|
||
});
|
||
});
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// F71 — union declarations
|
||
// ---------------------------------------------------------------------------
|
||
|
||
describe('F71 — union declaration', () => {
|
||
it('union item emits @scope.class and @declaration.struct', () => {
|
||
const src = `union MyUnion { x: i32, y: f64 }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const scopes = matches.filter((m) => m['@scope.class']);
|
||
expect(scopes.length).toBe(1);
|
||
const decls = matches.filter((m) => m['@declaration.struct']);
|
||
expect(decls.length).toBe(1);
|
||
expect(decls[0]['@declaration.name'].text).toBe('MyUnion');
|
||
});
|
||
});
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// F72 — macro invocations (capture layer)
|
||
//
|
||
// These pin the tree-sitter CAPTURE shape only. End-to-end macro RESOLUTION
|
||
// (the @reference.macro → MacroRegistry → USES-edge-to-a-Macro-node path, and
|
||
// the guarantee that a macro never binds to a same-named function) is asserted
|
||
// at the pipeline level in `rust.test.ts` › "Rust macro resolution (issue #1934 F72)".
|
||
// ---------------------------------------------------------------------------
|
||
|
||
describe('F72 — macro invocations (capture layer)', () => {
|
||
it('macro_invocation with bare identifier emits @reference.macro', () => {
|
||
const src = `fn f() { println!("hi"); }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const macroRefs = matches.filter((m) => m['@reference.macro']);
|
||
const macroNames = macroRefs.map((m) => m['@reference.name']?.text);
|
||
expect(macroNames).toContain('println');
|
||
});
|
||
|
||
it('vec! macro emits @reference.macro', () => {
|
||
const src = `fn f() { let v = vec![1, 2, 3]; }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const macroRefs = matches.filter((m) => m['@reference.macro']);
|
||
const macroNames = macroRefs.map((m) => m['@reference.name']?.text);
|
||
expect(macroNames).toContain('vec');
|
||
});
|
||
|
||
it('scoped macro invocation captures the TAIL identifier, not the full path', () => {
|
||
const src = `fn f() { log::info!("hi"); }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const macroRefs = matches.filter((m) => m['@reference.macro']);
|
||
const macroNames = macroRefs.map((m) => m['@reference.name']?.text);
|
||
// Must be the tail `info`, not the whole path `log::info` — mirrors the
|
||
// scoped free-call pattern. Guards the P3 fix.
|
||
expect(macroNames).toContain('info');
|
||
expect(macroNames).not.toContain('log::info');
|
||
});
|
||
|
||
it('macro_rules! definition emits a @declaration.macro capture', () => {
|
||
const src = `macro_rules! greet { () => {}; }\n`;
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const macroDecls = matches.filter((m) => m['@declaration.macro']);
|
||
expect(macroDecls.length).toBe(1);
|
||
expect(macroDecls[0]['@declaration.name'].text).toBe('greet');
|
||
});
|
||
});
|
||
|
||
describe('restricted visibility use is not a re-export', () => {
|
||
it.each([
|
||
['pub use foo::helper;', 'reexport'],
|
||
['pub(crate) use foo::helper;', 'named'],
|
||
['pub(super) use foo::helper;', 'named'],
|
||
['use foo::helper;', 'named'],
|
||
])('%s', (src, kind) => {
|
||
const matches = emitRustScopeCaptures(src, 'test.rs') as CaptureMatch[];
|
||
const imps = matches.filter((m) => m['@import.kind']);
|
||
expect(imps.map((m) => m['@import.kind']?.text)).toEqual([kind]);
|
||
});
|
||
});
|