From c046fc5940b78b1444a8ada1ea9b04839580e9cf Mon Sep 17 00:00:00 2001 From: Tirth Kanani Date: Sun, 14 Jun 2026 18:02:53 +0100 Subject: [PATCH] fix(java-extractor): strip inner call args from chained method-call callee For a chained call like `builder().build()`, the method_invocation's `object` field is itself a method_invocation node, so building the callee as `${objectNode.text}.${nameNode.text}` produced the malformed callee "builder().build" (parentheses and inner args embedded in the name). Guard the qualified-call branch so it only prefixes the receiver when the object is not itself a method_invocation. Chained calls now yield a clean method name ("build") for the outer call plus the existing well-formed entry for the inner call ("builder"). Simple receivers such as `System.out.println` (object type field_access) are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../__tests__/java-extractor.test.ts | 19 +++++++++++++++++++ .../src/plugins/extractors/java-extractor.ts | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/understand-anything-plugin/packages/core/src/plugins/extractors/__tests__/java-extractor.test.ts b/understand-anything-plugin/packages/core/src/plugins/extractors/__tests__/java-extractor.test.ts index 17d14add..f047b4c4 100644 --- a/understand-anything-plugin/packages/core/src/plugins/extractors/__tests__/java-extractor.test.ts +++ b/understand-anything-plugin/packages/core/src/plugins/extractors/__tests__/java-extractor.test.ts @@ -408,6 +408,25 @@ public class Foo {} parser.delete(); }); + it("strips inner call args from chained method-call callee", () => { + const { tree, parser, root } = parse(`public class Foo { + public void run() { + builder().build(); + } +} +`); + const result = extractor.extractCallGraph(root); + + // The chained call should yield a clean method name "build" for the + // outer call (not the malformed "builder().build"), plus an entry for + // the inner "builder" call. + expect(result.some((e) => e.callee === "build")).toBe(true); + expect(result.some((e) => e.callee.includes("()"))).toBe(false); + + tree.delete(); + parser.delete(); + }); + it("tracks correct caller for constructors", () => { const { tree, parser, root } = parse(`public class Foo { public Foo() { diff --git a/understand-anything-plugin/packages/core/src/plugins/extractors/java-extractor.ts b/understand-anything-plugin/packages/core/src/plugins/extractors/java-extractor.ts index 4ac3a4f3..1a61cd4f 100644 --- a/understand-anything-plugin/packages/core/src/plugins/extractors/java-extractor.ts +++ b/understand-anything-plugin/packages/core/src/plugins/extractors/java-extractor.ts @@ -200,7 +200,7 @@ export class JavaExtractor implements LanguageExtractor { if (!nameNode) return null; const objectNode = node.childForFieldName("object"); - if (objectNode) { + if (objectNode && objectNode.type !== "method_invocation") { return `${objectNode.text}.${nameNode.text}`; }