Skip to content

fix(groovy): dispatch juxt_function_call in both engines#1124

Merged
carlos-alm merged 1 commit into
mainfrom
fix/1108-groovy-juxt-call
May 15, 2026
Merged

fix(groovy): dispatch juxt_function_call in both engines#1124
carlos-alm merged 1 commit into
mainfrom
fix/1108-groovy-juxt-call

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

  • Both engines were silently dropping Groovy command-style calls (foo bar(x), Gradle DSL task someTask { ... }, apply plugin: 'java', println "hi", etc.). The grammar emits these as juxt_function_call, which neither walkGroovyNode (src/extractors/groovy.ts) nor match_groovy_node (crates/codegraph-core/src/extractors/groovy.rs) dispatched.
  • The juxt node carries a name field with the same shape as method_invocation, so wiring it into the existing call handler is enough — no new handler needed.
  • Added parity tests in both engines covering a Gradle-DSL fixture (apply, task, println).

Test plan

  • cargo test -p codegraph-core extractors::groovy — 8/8 pass (incl. new extracts_command_style_juxt_calls)
  • npx vitest run tests/parsers/groovy.test.ts — 6/6 pass (incl. new extracts command-style (juxt) function calls)

Closes #1108

Groovy command-style calls (`foo bar(x)`, Gradle DSL `task someTask { ... }`,
`apply plugin: 'java'`, etc.) parse as `juxt_function_call` nodes, which
neither the JS source-of-truth extractor nor the Rust port was dispatching —
so these call edges were silently dropped from the call graph in both
engines.

The juxt node has a `name` field with the same shape as `method_invocation`,
so adding it to the existing dispatch in `walkGroovyNode` /
`match_groovy_node` is sufficient — the existing call handler picks up the
callee without further special-casing.

Closes #1108
@claude
Copy link
Copy Markdown

claude Bot commented May 14, 2026

Claude finished @carlos-alm's task —— View job


✅ PR Review Complete

Reviewing PR #1124: fix(groovy): dispatch juxt_function_call in both engines

Review Checklist:

  • Phase 1: Root cause analysis - understand the problem being solved
  • Phase 2: Configuration change detection - check for high-risk changes
  • Phase 3: Test integrity - verify test quality and assertions
  • Phase 4: Code quality - review implementation details
  • Phase 5: Backlog compliance - grade against BACKLOG.md criteria
  • Final Assessment: Provide structured recommendation

Phase 1: Root Cause Analysis ✅

Problem Being Solved: Both TypeScript and Rust extraction engines were silently dropping Groovy command-style function calls (e.g., foo bar(x), Gradle DSL syntax like apply plugin: 'java', task someTask { ... }, println "hello"). The tree-sitter-groovy grammar emits these as juxt_function_call nodes, but neither walkGroovyNode() in the TS engine nor match_groovy_node() in the Rust engine had a dispatch case for this node type.

Why This Approach: The fix correctly identifies that juxt_function_call nodes have the same name field structure as method_invocation, so the existing call handler can process them without modification. This is a surgical fix that leverages existing infrastructure.

Risk Assessment: ✅ Low risk - minimal change, addresses clear gap in AST node coverage, both engines updated in parallel.

Phase 2: Configuration Change Detection ✅

No High-Risk Changes Detected:

  • ✅ No biome/linting rule changes
  • ✅ No test timeout or coverage modifications
  • ✅ No build configuration changes
  • ✅ No TypeScript strict mode relaxation
  • ✅ Pure feature addition with no config relaxation

Phase 3: Test Integrity ✅

Strong Test Coverage:

  • Rust engine test (tests/extractors/groovyextracts_command_style_juxt_calls): Tests real Gradle DSL syntax (apply plugin, task, println) with proper assertion structure
  • TypeScript engine test (groovy.test.tsextracts command-style (juxt) function calls): Mirrors the Rust test with identical fixture and assertions
  • No weakened assertions: Tests properly verify that the missing calls are now extracted (expect(callNames).toContain('apply') etc.)
  • Meaningful test fixture: Uses realistic Gradle build script syntax that would actually contain juxt calls
  • Both engines tested: Ensures parity between native and WASM implementations

Phase 4: Code Quality ✅

Implementation Analysis:

  • Minimal, surgical change: Only adds | "juxt_function_call" to existing match arms in both engines (groovy.rs:65, groovy.ts:71)
  • Correct approach: Leverages existing handle_call_expr/handleGroovyCallExpr since juxt nodes have same name field structure
  • Engine parity: Both TypeScript and Rust engines updated identically, maintaining dual-engine consistency
  • Good documentation: Rust code includes comprehensive comment explaining juxt behavior (lines 26-30)
  • No redundant code: No new handlers needed since existing call logic works for juxt nodes
  • Follows existing patterns: Matches the pattern of other multi-node-type dispatches in both engines

Phase 5: Backlog Compliance ✅

  • Zero-dep: ✅ No new runtime dependencies added
  • Foundation-aligned: ✅ Fully compliant - improves AST extraction accuracy without violating principles
  • Problem-fit: 4/5 - Directly improves AI agent accuracy by capturing previously missed function calls in Groovy/Gradle codebases
  • Breaking: No - purely additive, no existing behavior changed
  • Tier: 1 (zero-dep ✓ + foundation-aligned ✓)

Root Cause Analysis

Problem Being Solved: Missing extraction of Groovy command-style calls (juxt_function_call AST nodes), causing incomplete dependency graphs for Gradle builds
Why This Approach: Leverages existing call handlers since juxt nodes have identical structure to method_invocation
Risk Assessment: Minimal risk - surgical fix with comprehensive test coverage

Backlog Compliance

  • Zero-dep: ✅ — no new dependencies
  • Foundation-aligned: ✅ — improves extraction accuracy
  • Problem-fit: 4 — directly helps AI agents understand Gradle build dependencies
  • Breaking: No — purely additive functionality
  • Tier: 1

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Clean, well-tested fix that addresses a real gap in Groovy parsing. Minimal code change with strong test coverage and proper engine parity. The fix directly improves codegraph's ability to analyze Gradle builds, which is valuable for AI agents working with JVM projects.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Greptile Summary

This PR fixes a silent omission in both the TypeScript and Rust Groovy extractors where juxt_function_call nodes (Groovy command-style calls like foo bar(x), Gradle DSL apply, task, println, etc.) were never dispatched to the call handler, causing them to be silently dropped from the call graph. The fix routes juxt_function_call through the existing handle_call_expr / handleGroovyCallExpr handler in each engine, which already handled the name field shape that juxt_function_call provides.

  • groovy.rs: Adds | \"juxt_function_call\" to the match arm dispatching to handle_call_expr; updates the module doc comment from the tracked-TODO state to the resolved description.
  • groovy.ts: Adds case 'juxt_function_call': to the switch dispatching to handleGroovyCallExpr.
  • groovy.test.ts / test in groovy.rs: Adds parity tests in both engines covering apply, task, and println from a Gradle DSL fixture.

Confidence Score: 5/5

Safe to merge — the change is a minimal one-liner addition in each engine that routes a previously unhandled node kind to an already-correct handler.

Both engines' existing handle_call_expr / handleGroovyCallExpr already handled the name-field shape that juxt_function_call provides as its primary branch; dispatching the new node kind requires no handler changes. Parity tests are added in both engines using the same Gradle DSL fixture, confirming consistent extraction of apply, task, and println. No existing behavior is altered.

No files require special attention.

Important Files Changed

Filename Overview
crates/codegraph-core/src/extractors/groovy.rs Adds juxt_function_call to the dispatch match arm and a new regression test; the existing handle_call_expr already handles the name field shape that juxt nodes carry, so no handler changes needed.
src/extractors/groovy.ts Single-case addition routing juxt_function_call to the existing handleGroovyCallExpr; the fallback name-field path in that handler was already correct for this node shape.
tests/parsers/groovy.test.ts New test covering apply, task, and println juxt patterns with a Gradle DSL fixture; mirrors the Rust test for engine parity.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Tree-sitter Groovy AST node] --> B{node.kind}
    B -->|method_invocation\nmethod_call\ncall_expression\nfunction_call| C[handle_call_expr / handleGroovyCallExpr]
    B -->|juxt_function_call\n✅ NEW| C
    B -->|object_creation_expression| D[handle_object_creation]
    B -->|class / interface / enum\nmethod / function / import| E[other handlers]
    C --> F{has 'name' field?}
    F -->|yes - juxt_function_call\nmethod_invocation| G[Extract name + optional object receiver → push Call]
    F -->|no| H{has 'function' / 'method' field?}
    H -->|field_expression / member_access| I[Extract field + obj receiver → push Call]
    H -->|identifier| J[Use funcNode.text → push Call]
Loading

Reviews (1): Last reviewed commit: "fix(groovy): dispatch juxt_function_call..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

3 functions changed1 callers affected across 1 files

  • match_groovy_node in crates/codegraph-core/src/extractors/groovy.rs:55 (0 transitive callers)
  • extracts_command_style_juxt_calls in crates/codegraph-core/src/extractors/groovy.rs:504 (0 transitive callers)
  • walkGroovyNode in src/extractors/groovy.ts:37 (1 transitive callers)

@carlos-alm carlos-alm merged commit 02a581c into main May 15, 2026
29 checks passed
@carlos-alm carlos-alm deleted the fix/1108-groovy-juxt-call branch May 15, 2026 05:27
@github-actions github-actions Bot locked and limited conversation to collaborators May 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

follow-up: add juxt_function_call support to Groovy extractor (both engines)

1 participant