Skip to content

Commit 732c82d

Browse files
committed
fix(groovy): use current node's start line in WASM interface helper (#1158)
Align the TypeScript collectGroovyParentInterfaces helper with the Rust collect_interfaces helper, which re-evaluates start_line(interfaces) at each recursive invocation. Previously the WASM extractor forwarded the interface declaration's start line through every recursion level, so a multi-line interface (e.g. interface X\n extends Y, Z {}) produced line=1 in WASM but line=2 in native — the two engines must produce identical results. Add a multi-line line-parity test in both engines to guard against future regressions.
1 parent 809b1c7 commit 732c82d

3 files changed

Lines changed: 34 additions & 3 deletions

File tree

crates/codegraph-core/src/extractors/groovy.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,4 +555,18 @@ mod tests {
555555
rels
556556
);
557557
}
558+
559+
#[test]
560+
fn interface_inheritance_line_tracks_extends_clause() {
561+
// Engine-parity guard: the relation line should match the
562+
// `extends_interfaces` node's start line, not the `interface_declaration`'s
563+
// — `collect_interfaces` re-evaluates `start_line(interfaces)` on every
564+
// recursive call, and the WASM extractor must match.
565+
let s = parse_groovy("interface Serializable\n extends Comparable, Cloneable {}");
566+
let rels: Vec<_> = s.classes.iter().filter(|c| c.name == "Serializable").collect();
567+
assert!(!rels.is_empty(), "expected at least one ClassRelation");
568+
for rel in &rels {
569+
assert_eq!(rel.line, 2, "line should track the extends clause, got: {:?}", rel);
570+
}
571+
}
558572
}

src/extractors/groovy.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ function handleGroovyInterfaceDecl(node: TreeSitterNode, ctx: ExtractorOutput):
157157
for (let i = 0; i < node.childCount; i++) {
158158
const child = node.child(i);
159159
if (child && child.type === 'extends_interfaces') {
160-
collectGroovyParentInterfaces(child, ifaceName, node.startPosition.row + 1, ctx);
160+
collectGroovyParentInterfaces(child, ifaceName, ctx);
161161
break;
162162
}
163163
}
@@ -166,9 +166,12 @@ function handleGroovyInterfaceDecl(node: TreeSitterNode, ctx: ExtractorOutput):
166166
function collectGroovyParentInterfaces(
167167
parent: TreeSitterNode,
168168
name: string,
169-
line: number,
170169
ctx: ExtractorOutput,
171170
): void {
171+
// Use the current node's start line at each recursion level — matches the
172+
// Rust `collect_interfaces` helper, which re-evaluates `start_line(interfaces)`
173+
// for whatever node (`extends_interfaces` → `type_list`) is being processed.
174+
const line = parent.startPosition.row + 1;
172175
for (let i = 0; i < parent.childCount; i++) {
173176
const child = parent.child(i);
174177
if (!child) continue;
@@ -185,7 +188,7 @@ function collectGroovyParentInterfaces(
185188
break;
186189
}
187190
case 'type_list':
188-
collectGroovyParentInterfaces(child, name, line, ctx);
191+
collectGroovyParentInterfaces(child, name, ctx);
189192
break;
190193
}
191194
}

tests/parsers/groovy.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,20 @@ describe('Groovy parser', () => {
6464
);
6565
});
6666

67+
it('reports line of extends_interfaces clause for multi-line declarations', () => {
68+
// Engine-parity guard: the line should match the `extends_interfaces`
69+
// node's start line, not the `interface_declaration`'s start line, so the
70+
// WASM extractor stays consistent with the Rust `collect_interfaces`
71+
// helper which re-evaluates the current node's `start_line` at each
72+
// recursion level.
73+
const symbols = parseGroovy(`interface Serializable\n extends Comparable, Cloneable {}`);
74+
const rels = symbols.classes.filter((c) => c.name === 'Serializable');
75+
expect(rels.length).toBeGreaterThan(0);
76+
for (const rel of rels) {
77+
expect(rel.line).toBe(2);
78+
}
79+
});
80+
6781
it('extracts enum declarations', () => {
6882
const symbols = parseGroovy(`enum Color {
6983
RED, GREEN, BLUE

0 commit comments

Comments
 (0)