diff --git a/gitnexus/src/core/ingestion/tree-sitter-queries.ts b/gitnexus/src/core/ingestion/tree-sitter-queries.ts index d1b0359aa..3261913ba 100644 --- a/gitnexus/src/core/ingestion/tree-sitter-queries.ts +++ b/gitnexus/src/core/ingestion/tree-sitter-queries.ts @@ -743,10 +743,11 @@ export const PYTHON_QUERIES = ` // Java queries - works with tree-sitter-java export const JAVA_QUERIES = ` -; Classes, Interfaces, Enums, Annotations +; Classes, Interfaces, Enums, Records, Annotations (class_declaration name: (identifier) @name) @definition.class (interface_declaration name: (identifier) @name) @definition.interface (enum_declaration name: (identifier) @name) @definition.enum +(record_declaration name: (identifier) @name) @definition.record (annotation_type_declaration name: (identifier) @name) @definition.annotation ; Anonymous class bodies: new Runnable() { ... } — no @name capture; the diff --git a/gitnexus/test/fixtures/lang-resolution/java-record-methods/Point.java b/gitnexus/test/fixtures/lang-resolution/java-record-methods/Point.java new file mode 100644 index 000000000..f4471a1e1 --- /dev/null +++ b/gitnexus/test/fixtures/lang-resolution/java-record-methods/Point.java @@ -0,0 +1,11 @@ +package probe; + +public record Point(int x, int y) { + public int sum() { + return x + y; + } + + public int scaled(int factor) { + return sum() * factor; + } +} diff --git a/gitnexus/test/integration/resolvers/java.test.ts b/gitnexus/test/integration/resolvers/java.test.ts index 66bc820dd..0d53ce0eb 100644 --- a/gitnexus/test/integration/resolvers/java.test.ts +++ b/gitnexus/test/integration/resolvers/java.test.ts @@ -1174,6 +1174,40 @@ describe('Java chained method call resolution', () => { }); }); +// --------------------------------------------------------------------------- +// Java record: container node + HAS_METHOD edges +// Regression test for #2564: JAVA_QUERIES previously had no @definition.record +// capture, so a record never got a Class/Record graph node — its methods +// existed as ownerless orphans with no HAS_METHOD edge. +// --------------------------------------------------------------------------- + +describe('Java record method resolution (#2564)', () => { + let result: PipelineResult; + + beforeAll(async () => { + result = await runPipelineFromRepo(path.join(FIXTURES, 'java-record-methods'), () => {}); + }, 60000); + + it('detects a Record node for Point', () => { + const records = getNodesByLabel(result, 'Record'); + expect(records).toContain('Point'); + }); + + it('emits HAS_METHOD edges linking sum and scaled to Point', () => { + const hasMethod = getRelationships(result, 'HAS_METHOD'); + const sumEdge = hasMethod.find((e) => e.source === 'Point' && e.target === 'sum'); + const scaledEdge = hasMethod.find((e) => e.source === 'Point' && e.target === 'scaled'); + expect(sumEdge).toBeDefined(); + expect(scaledEdge).toBeDefined(); + }); + + it('resolves scaled() calling sum() via a CALLS edge', () => { + const calls = getRelationships(result, 'CALLS'); + const sumCall = calls.find((c) => c.target === 'sum' && c.source === 'scaled'); + expect(sumCall).toBeDefined(); + }); +}); + // --------------------------------------------------------------------------- // Java 16+ instanceof pattern variable: `if (obj instanceof User user)` // Phase 5.2: extractPatternBinding on instanceof_expression binds user → User.