mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-07 08:26:11 +00:00
* fix(java): close parsing-layer coverage gaps F35/F38/F41 (#1928) Registry-primary scope-resolution path (the live one post-#942/#943): - F35 [HIGH]: qualified / qualified-generic constructor calls. `new pkg.Foo()` parses as a `scoped_type_identifier` that the query bound only as `@reference.call.constructor.qualified` with no `@reference.name`, so the scope extractor fell back to the whole-expression anchor and the reference name became the raw `new pkg.Foo()` text (never resolved). Bind the simple -name tail (end-anchored last child) and add an arm for the previously uncaptured `new pkg.Box<String>()` (qualified + generic) shape. - F38 [MEDIUM]: `super(...)` / `this(...)` explicit constructor invocations, modeled as `explicit_constructor_invocation` and never matched by the scope query, dropped the chained-constructor CALLS edges. Synthesize them with the target resolved structurally (this -> enclosing type name; super -> superclass tail via the shared javaBaseLookupNameNode, skipping implicit Object) plus arity for overload disambiguation. - F41 [LOW]: interpretJavaTypeBinding stripped the qualifier before generics, so a qualified generic type arg (`Map<String, com.example.User>`) was cut inside the generic into `User>`. Strip generics first, then the qualifier; make the erasure fallback qualifier-tolerant. F36/F37 already landed upstream (#1940/#1956); F39/F40 are legacy-bank remnants that are no longer consumed (legacy @import skipped in parse-worker; legacy @call never read in parse-impl) so they are intentionally left untouched. Tests: low-level capture unit tests (constructor shapes incl. double-match guard; super/this/enum/implicit-Object), interpretJavaTypeBinding unit tests (qualified generic args + the corruption case), and end-to-end resolver tests with new fixtures asserting the CALLS edges resolve to the correct constructors. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(scope-resolution): register Constructor overload keys so this()/super() chains don't self-loop (#1928 F38 review) Review of #2045 caught two gaps; both confirmed by reproduction. P2 — F38 this() emitted a self-loop. On the java-explicit-constructor fixture, Child(int){ this(); } produced CALLS Child()#0 -> Child()#0 instead of Child(int)#1 -> Child()#0. Root cause is the language-agnostic graph-bridge: the parse phase mints distinct Constructor nodes (Child#0, Child#1) carrying parameterTypes, but node-lookup.ts registered the parameter-types / shape overload keys only for Function/Method, never Constructor, so both ctors collapsed onto the first-wins qualified/simple key and the caller Child(int) resolved to Child#0 (the this() target). Extend the overload keys to Constructor in both node-lookup.ts (registration) and ids.ts (lookup) via a shared isOverloadableCallable predicate. Verified the edge now connects distinct nodes (Child#1 -> Child#0); super(1)->Base#1 still correct. No cross-language regressions (the 9 worker-path failures reproduce identically on clean HEAD). Also harden the integration test: it matched the this() edge on name only, which a self-loop satisfies; now assert the endpoints are DISTINCT constructors. P3 — F41 order-regression guard was inert (List<Map<String,User>> normalizes to List under both strip orders). Add List<com.x.Foo<String>> -> List, which is corrupted to Foo<String>> under the old order and only correct generics-first. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(java): update fingerprint and add notes for constructor query captures in baselines.json Updated the fingerprint for the Java section and added detailed notes regarding the enhancements in constructor query captures, including qualified and qualified-generic constructor queries. This change reflects ongoing improvements in the parsing layer coverage and fixture updates. --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
76 lines
3.5 KiB
TypeScript
76 lines
3.5 KiB
TypeScript
/**
|
|
* Java parsing-layer coverage gaps (#1928) — end-to-end resolution.
|
|
*
|
|
* - F35: qualified / qualified-generic constructor calls (`new pkg.Foo()`,
|
|
* `new pkg.Box<String>()`) resolve to the target constructor instead of
|
|
* dropping the edge on a corrupted `pkg.Foo` reference name.
|
|
* - F38: `super(...)` / `this(...)` explicit constructor invocations emit CALLS
|
|
* edges to the superclass / sibling constructor.
|
|
*/
|
|
import { describe, it, expect, beforeAll } from 'vitest';
|
|
import path from 'path';
|
|
import { FIXTURES, getRelationships, runPipelineFromRepo, type PipelineResult } from './helpers.js';
|
|
|
|
describe('Java qualified constructor resolution (F35 #1928)', () => {
|
|
let result: PipelineResult;
|
|
|
|
beforeAll(async () => {
|
|
result = await runPipelineFromRepo(path.join(FIXTURES, 'java-qualified-constructor'), () => {});
|
|
}, 60000);
|
|
|
|
it('resolves `new pkg.Foo()` to the Foo constructor', () => {
|
|
const calls = getRelationships(result, 'CALLS');
|
|
const fooCtor = calls.find((c) => c.target === 'Foo' && c.source === 'make');
|
|
expect(fooCtor).toBeDefined();
|
|
expect(fooCtor!.targetLabel).toBe('Constructor');
|
|
expect(fooCtor!.targetFilePath).toBe('pkg/Foo.java');
|
|
});
|
|
|
|
it('resolves `new pkg.Box<String>()` to the Box constructor', () => {
|
|
const calls = getRelationships(result, 'CALLS');
|
|
const boxCtor = calls.find((c) => c.target === 'Box' && c.source === 'make');
|
|
expect(boxCtor).toBeDefined();
|
|
expect(boxCtor!.targetLabel).toBe('Constructor');
|
|
expect(boxCtor!.targetFilePath).toBe('pkg/Box.java');
|
|
});
|
|
|
|
it('does not emit a CALLS edge to a corrupted `pkg.Foo` / `pkg.Box` name', () => {
|
|
const calls = getRelationships(result, 'CALLS');
|
|
expect(calls.some((c) => c.target === 'pkg.Foo' || c.target === 'pkg.Box')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('Java explicit constructor invocation resolution (F38 #1928)', () => {
|
|
let result: PipelineResult;
|
|
|
|
beforeAll(async () => {
|
|
result = await runPipelineFromRepo(path.join(FIXTURES, 'java-explicit-constructor'), () => {});
|
|
}, 60000);
|
|
|
|
it('resolves `super(1)` in Child() to the Base constructor', () => {
|
|
const calls = getRelationships(result, 'CALLS');
|
|
const superCall = calls.find((c) => c.target === 'Base' && c.targetLabel === 'Constructor');
|
|
expect(superCall).toBeDefined();
|
|
expect(superCall!.source).toBe('Child');
|
|
expect(superCall!.targetFilePath).toBe('models/Base.java');
|
|
// Source is the arity-0 `Child()`, where `super(1)` lives.
|
|
expect(superCall!.rel.sourceId).toContain('Child.Child#0');
|
|
expect(superCall!.rel.targetId).toContain('Base.Base#1');
|
|
});
|
|
|
|
it('resolves `this()` in Child(int) to a DISTINCT Child constructor (no self-loop)', () => {
|
|
const calls = getRelationships(result, 'CALLS');
|
|
const thisCall = calls.find(
|
|
(c) => c.target === 'Child' && c.targetLabel === 'Constructor' && c.source === 'Child',
|
|
);
|
|
expect(thisCall).toBeDefined();
|
|
expect(thisCall!.targetFilePath).toBe('models/Child.java');
|
|
// The edge must connect DISTINCT constructors: the caller `Child(int)` (#1)
|
|
// chains to `Child()` (#0). A self-loop (`#0 → #0`) — the bug this PR's
|
|
// review caught (#1928 F38: ctor overload keys missing in node-lookup) —
|
|
// satisfies the name-only match above but must NOT pass here.
|
|
expect(thisCall!.rel.sourceId).not.toBe(thisCall!.rel.targetId);
|
|
expect(thisCall!.rel.sourceId).toContain('Child.Child#1');
|
|
expect(thisCall!.rel.targetId).toContain('Child.Child#0');
|
|
});
|
|
});
|