From 2bf054e209307f66e0ffa74004d59f92d90bcaca Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Fri, 3 Apr 2026 13:54:42 +0200 Subject: [PATCH 1/2] Fix RPC ser/deser for varargs --- rewrite-go/rewrite/pkg/rpc/java_receiver.go | 13 ++++++++++-- rewrite-go/rewrite/pkg/rpc/java_sender.go | 21 ++++++++++++++----- .../golang/rpc/GolangParserIntegTest.java | 14 +++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/rewrite-go/rewrite/pkg/rpc/java_receiver.go b/rewrite-go/rewrite/pkg/rpc/java_receiver.go index ebcafda8f4..0afb57de14 100644 --- a/rewrite-go/rewrite/pkg/rpc/java_receiver.go +++ b/rewrite-go/rewrite/pkg/rpc/java_receiver.go @@ -17,6 +17,7 @@ package rpc import ( + "github.com/google/uuid" "github.com/openrewrite/rewrite/rewrite-go/pkg/tree" ) @@ -355,8 +356,16 @@ func (r *JavaReceiver) receiveVariableDeclarations(vd *tree.VariableDeclarations if result != nil { vd.TypeExpr = result.(tree.Expression) } - // varargs - q.Receive(nil, nil) + // varargs — if non-nil, reconstruct Unary(Spread) wrapping the type expression + varargsResult := q.Receive(nil, func(v any) any { return receiveSpace(v.(tree.Space), q) }) + if varargsResult != nil && vd.TypeExpr != nil { + vd.TypeExpr = &tree.Unary{ + ID: uuid.New(), + Prefix: varargsResult.(tree.Space), + Operator: tree.LeftPadded[tree.UnaryOperator]{Element: tree.Spread}, + Operand: vd.TypeExpr, + } + } // variables beforeVars := make([]any, len(vd.Variables)) for i, v := range vd.Variables { diff --git a/rewrite-go/rewrite/pkg/rpc/java_sender.go b/rewrite-go/rewrite/pkg/rpc/java_sender.go index 80b3c08c60..a611b01977 100644 --- a/rewrite-go/rewrite/pkg/rpc/java_sender.go +++ b/rewrite-go/rewrite/pkg/rpc/java_sender.go @@ -470,11 +470,22 @@ func (s *JavaSender) sendVariableDeclarations(vd *tree.VariableDeclarations, q * q.GetAndSendList(vd, func(_ any) []any { return []any{} }, func(_ any) any { return nil }, nil) // modifiers (empty -- Go has no modifiers) q.GetAndSendList(vd, func(_ any) []any { return []any{} }, func(_ any) any { return nil }, nil) - // typeExpression - q.GetAndSend(vd, func(v any) any { return v.(*tree.VariableDeclarations).TypeExpr }, - func(v any) { s.parent.Visit(v, q) }) - // varargs (nil for Go) - q.GetAndSend(vd, func(_ any) any { return nil }, nil) + // typeExpression — unwrap Unary(Spread) for variadic params so Java sees a TypeTree + q.GetAndSend(vd, func(v any) any { + te := v.(*tree.VariableDeclarations).TypeExpr + if u, ok := te.(*tree.Unary); ok && u.Operator.Element == tree.Spread { + return u.Operand + } + return te + }, func(v any) { s.parent.Visit(v, q) }) + // varargs — send the ellipsis prefix space for variadic params + q.GetAndSend(vd, func(v any) any { + te := v.(*tree.VariableDeclarations).TypeExpr + if u, ok := te.(*tree.Unary); ok && u.Operator.Element == tree.Spread { + return u.Prefix + } + return nil + }, func(v any) { sendSpace(v.(tree.Space), q) }) // variables (list of right-padded NamedVariable) q.GetAndSendList(vd, func(v any) []any { diff --git a/rewrite-go/src/integTest/java/org/openrewrite/golang/rpc/GolangParserIntegTest.java b/rewrite-go/src/integTest/java/org/openrewrite/golang/rpc/GolangParserIntegTest.java index 2daf4ca29b..d448015338 100644 --- a/rewrite-go/src/integTest/java/org/openrewrite/golang/rpc/GolangParserIntegTest.java +++ b/rewrite-go/src/integTest/java/org/openrewrite/golang/rpc/GolangParserIntegTest.java @@ -451,4 +451,18 @@ void literalWithNonPrimitiveType() { ) ); } + + @Test + void variadicParameter() { + rewriteRun( + go( + """ + package main + + func foo(args ...string) { + } + """ + ) + ); + } } From dcdd730039b6576902fabc08c385dd5b8110a8e2 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Fri, 3 Apr 2026 14:22:26 +0200 Subject: [PATCH 2/2] Adding VariableDeclarations.Varargs field --- rewrite-go/rewrite/pkg/parser/go_parser.go | 12 ++++++++++++ rewrite-go/rewrite/pkg/printer/go_printer.go | 6 +++++- rewrite-go/rewrite/pkg/rpc/java_receiver.go | 19 +++++++++---------- rewrite-go/rewrite/pkg/rpc/java_sender.go | 19 +++++++------------ rewrite-go/rewrite/pkg/tree/j.go | 1 + 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/rewrite-go/rewrite/pkg/parser/go_parser.go b/rewrite-go/rewrite/pkg/parser/go_parser.go index 64941227fa..ab3c782c5a 100644 --- a/rewrite-go/rewrite/pkg/parser/go_parser.go +++ b/rewrite-go/rewrite/pkg/parser/go_parser.go @@ -669,9 +669,15 @@ func (ctx *parseContext) mapFieldListAsParams(fl *ast.FieldList) tree.Container[ if len(field.Names) == 0 { // Unnamed parameter: just a type expression (e.g., `int` in `func(int)`) typeExpr := ctx.mapTypeExpr(field.Type) + var varargs *tree.Space + if u, ok := typeExpr.(*tree.Unary); ok && u.Operator.Element == tree.Spread { + varargs = &u.Prefix + typeExpr = u.Operand + } vd := &tree.VariableDeclarations{ ID: uuid.New(), TypeExpr: typeExpr, + Varargs: varargs, Variables: []tree.RightPadded[*tree.VariableDeclarator]{ {Element: &tree.VariableDeclarator{ID: uuid.New(), Name: &tree.Identifier{ID: uuid.New()}}}, }, @@ -706,9 +712,15 @@ func (ctx *parseContext) mapFieldListAsParams(fl *ast.FieldList) tree.Container[ } typeExpr := ctx.mapTypeExpr(field.Type) + var varargs *tree.Space + if u, ok := typeExpr.(*tree.Unary); ok && u.Operator.Element == tree.Spread { + varargs = &u.Prefix + typeExpr = u.Operand + } vd := &tree.VariableDeclarations{ ID: uuid.New(), TypeExpr: typeExpr, + Varargs: varargs, Variables: vars, } diff --git a/rewrite-go/rewrite/pkg/printer/go_printer.go b/rewrite-go/rewrite/pkg/printer/go_printer.go index d5ef8f328a..7b6081c345 100644 --- a/rewrite-go/rewrite/pkg/printer/go_printer.go +++ b/rewrite-go/rewrite/pkg/printer/go_printer.go @@ -323,7 +323,11 @@ func (p *GoPrinter) VisitVariableDeclarations(vd *tree.VariableDeclarations, par out.Append(",") } } - // Then type expression + // Then varargs + type expression + if vd.Varargs != nil { + p.visitSpace(*vd.Varargs, out) + out.Append("...") + } if vd.TypeExpr != nil { p.Visit(vd.TypeExpr, out) } diff --git a/rewrite-go/rewrite/pkg/rpc/java_receiver.go b/rewrite-go/rewrite/pkg/rpc/java_receiver.go index 0afb57de14..668cd44192 100644 --- a/rewrite-go/rewrite/pkg/rpc/java_receiver.go +++ b/rewrite-go/rewrite/pkg/rpc/java_receiver.go @@ -17,7 +17,6 @@ package rpc import ( - "github.com/google/uuid" "github.com/openrewrite/rewrite/rewrite-go/pkg/tree" ) @@ -356,15 +355,15 @@ func (r *JavaReceiver) receiveVariableDeclarations(vd *tree.VariableDeclarations if result != nil { vd.TypeExpr = result.(tree.Expression) } - // varargs — if non-nil, reconstruct Unary(Spread) wrapping the type expression - varargsResult := q.Receive(nil, func(v any) any { return receiveSpace(v.(tree.Space), q) }) - if varargsResult != nil && vd.TypeExpr != nil { - vd.TypeExpr = &tree.Unary{ - ID: uuid.New(), - Prefix: varargsResult.(tree.Space), - Operator: tree.LeftPadded[tree.UnaryOperator]{Element: tree.Spread}, - Operand: vd.TypeExpr, - } + // varargs + var currentVarargs any + if vd.Varargs != nil { + currentVarargs = *vd.Varargs + } + varargsResult := q.Receive(currentVarargs, func(v any) any { return receiveSpace(v.(tree.Space), q) }) + if varargsResult != nil { + sp := varargsResult.(tree.Space) + vd.Varargs = &sp } // variables beforeVars := make([]any, len(vd.Variables)) diff --git a/rewrite-go/rewrite/pkg/rpc/java_sender.go b/rewrite-go/rewrite/pkg/rpc/java_sender.go index a611b01977..391de64331 100644 --- a/rewrite-go/rewrite/pkg/rpc/java_sender.go +++ b/rewrite-go/rewrite/pkg/rpc/java_sender.go @@ -470,19 +470,14 @@ func (s *JavaSender) sendVariableDeclarations(vd *tree.VariableDeclarations, q * q.GetAndSendList(vd, func(_ any) []any { return []any{} }, func(_ any) any { return nil }, nil) // modifiers (empty -- Go has no modifiers) q.GetAndSendList(vd, func(_ any) []any { return []any{} }, func(_ any) any { return nil }, nil) - // typeExpression — unwrap Unary(Spread) for variadic params so Java sees a TypeTree - q.GetAndSend(vd, func(v any) any { - te := v.(*tree.VariableDeclarations).TypeExpr - if u, ok := te.(*tree.Unary); ok && u.Operator.Element == tree.Spread { - return u.Operand - } - return te - }, func(v any) { s.parent.Visit(v, q) }) - // varargs — send the ellipsis prefix space for variadic params + // typeExpression + q.GetAndSend(vd, func(v any) any { return v.(*tree.VariableDeclarations).TypeExpr }, + func(v any) { s.parent.Visit(v, q) }) + // varargs q.GetAndSend(vd, func(v any) any { - te := v.(*tree.VariableDeclarations).TypeExpr - if u, ok := te.(*tree.Unary); ok && u.Operator.Element == tree.Spread { - return u.Prefix + va := v.(*tree.VariableDeclarations).Varargs + if va != nil { + return *va } return nil }, func(v any) { sendSpace(v.(tree.Space), q) }) diff --git a/rewrite-go/rewrite/pkg/tree/j.go b/rewrite-go/rewrite/pkg/tree/j.go index 5b5757a1d7..1356e2ac68 100644 --- a/rewrite-go/rewrite/pkg/tree/j.go +++ b/rewrite-go/rewrite/pkg/tree/j.go @@ -1076,6 +1076,7 @@ type VariableDeclarations struct { Prefix Space Markers Markers TypeExpr Expression // the declared type (nil if inferred) + Varargs *Space // non-nil for variadic params (`...T`); holds prefix of `...` Variables []RightPadded[*VariableDeclarator] // the declared variables Specs *Container[Statement] // non-nil for grouped `var ( ... )`; Before = space before `(` }