Skip to content

Commit d8adf51

Browse files
authored
Go: add StatementExpression, fix variadic params, remove receiver overrides (#7261)
* Revert "Go: override Java receiver visitors for Go-specific type mismatches (#7258)" This reverts commit 8174845. * Go: add StatementExpression for func literals, fix variadic params and parse input order Add Go.StatementExpression (both Java and Go sides) to wrap MethodDeclaration in expression contexts, following the same pattern as Cs.StatementExpression in rewrite-csharp. Func literals like `func(x int) int { return x }` are parsed as MethodDeclaration (a Statement) but need to appear in returns, assignments, and call args. Fix variadic parameter handling: detect `...T` in mapFieldListAsParams, store the `...` prefix in VariableDeclarations.Varargs, and pass only the element type through mapTypeExpr. Previously `...T` was mapped as Unary{Spread, T} in the TypeExpr field, which violated the TypeTree constraint. Fix RPC parse input order: check Text before Path/SourcePath so text- based inputs (from integration tests) aren't mistakenly treated as file paths. Add 8 integration tests. 51 of 52 pass (goroutineAndDefer fails due to directly-invoked func literal `go func(){}()` padding mismatch).
1 parent 9258932 commit d8adf51

12 files changed

Lines changed: 179 additions & 154 deletions

File tree

rewrite-go/rewrite/cmd/rpc/main.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,22 @@ func (s *server) handleParse(params json.RawMessage) (any, *rpcError) {
308308
var sourcePath string
309309
var source string
310310

311-
filePath := input.Path
312-
if filePath == "" {
313-
filePath = input.SourcePath
314-
}
315-
if filePath != "" {
311+
if input.Text != "" {
312+
// Text-based input (inline source from tests or recipe framework)
313+
source = input.Text
314+
sourcePath = input.SourcePath
315+
if sourcePath == "" {
316+
sourcePath = "<unknown>"
317+
}
318+
} else {
319+
// File-path-based input (mod build sends file paths)
320+
filePath := input.Path
321+
if filePath == "" {
322+
filePath = input.SourcePath
323+
}
324+
if filePath == "" {
325+
continue
326+
}
316327
absPath := filePath
317328
data, err := os.ReadFile(absPath)
318329
if err != nil {
@@ -329,14 +340,6 @@ func (s *server) handleParse(params json.RawMessage) (any, *rpcError) {
329340
} else {
330341
sourcePath = absPath
331342
}
332-
} else if input.Text != "" {
333-
source = input.Text
334-
sourcePath = input.SourcePath
335-
if sourcePath == "" {
336-
sourcePath = "<unknown>"
337-
}
338-
} else {
339-
continue
340343
}
341344

342345
cu, parseErr := func() (cu *tree.CompilationUnit, err error) {

rewrite-go/rewrite/pkg/parser/go_parser.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,14 +1970,21 @@ func (ctx *parseContext) mapFuncLit(expr *ast.FuncLit) tree.Expression {
19701970
returnType := ctx.mapReturnType(expr.Type.Results)
19711971
body := ctx.mapBlockStmt(expr.Body)
19721972

1973-
return &tree.MethodDeclaration{
1973+
md := &tree.MethodDeclaration{
19741974
ID: uuid.New(),
1975-
Prefix: prefix,
19761975
Name: &tree.Identifier{ID: uuid.New(), Name: ""},
19771976
Parameters: params,
19781977
ReturnType: returnType,
19791978
Body: body,
19801979
}
1980+
// Wrap in StatementExpression so the MethodDeclaration (a Statement) can
1981+
// appear in expression contexts like return statements, assignments, and
1982+
// call arguments.
1983+
return &tree.StatementExpression{
1984+
ID: uuid.New(),
1985+
Prefix: prefix,
1986+
Statement: md,
1987+
}
19811988
}
19821989

19831990
// mapKeyValueExpr maps a key:value expression in composite literals.

rewrite-go/rewrite/pkg/printer/go_printer.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,14 @@ func (p *GoPrinter) VisitMapType(mt *tree.MapType, param any) tree.J {
751751
return mt
752752
}
753753

754+
func (p *GoPrinter) VisitStatementExpression(se *tree.StatementExpression, param any) tree.J {
755+
out := param.(*PrintOutputCapture)
756+
p.beforeSyntax(se.Prefix, se.Markers, out)
757+
p.Visit(se.Statement, out)
758+
p.afterSyntax(se.Markers, out)
759+
return se
760+
}
761+
754762
func (p *GoPrinter) VisitPointerType(pt *tree.PointerType, param any) tree.J {
755763
out := param.(*PrintOutputCapture)
756764
p.beforeSyntax(pt.Prefix, pt.Markers, out)

rewrite-go/rewrite/pkg/rpc/go_receiver.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ func (r *GoReceiver) Visit(node any, q *ReceiveQueue) any {
7474
return r.receiveSlice(v, q)
7575
case *tree.MapType:
7676
return r.receiveMapType(v, q)
77+
case *tree.StatementExpression:
78+
return r.receiveStatementExpression(v, q)
7779
case *tree.PointerType:
7880
return r.receivePointerType(v, q)
7981
case *tree.Channel:
@@ -125,6 +127,8 @@ func (r *GoReceiver) preVisit(node any, q *ReceiveQueue) any {
125127
c := *n; node = &c
126128
case *tree.MapType:
127129
c := *n; node = &c
130+
case *tree.StatementExpression:
131+
c := *n; node = &c
128132
case *tree.PointerType:
129133
c := *n; node = &c
130134
case *tree.Channel:
@@ -404,6 +408,16 @@ func (r *GoReceiver) receiveMapType(mt *tree.MapType, q *ReceiveQueue) *tree.Map
404408
return mt
405409
}
406410

411+
func (r *GoReceiver) receiveStatementExpression(se *tree.StatementExpression, q *ReceiveQueue) *tree.StatementExpression {
412+
c := *se
413+
se = &c
414+
result := q.Receive(se.Statement, func(v any) any { return r.Visit(v, q) })
415+
if result != nil {
416+
se.Statement = result.(tree.Statement)
417+
}
418+
return se
419+
}
420+
407421
func (r *GoReceiver) receivePointerType(pt *tree.PointerType, q *ReceiveQueue) *tree.PointerType {
408422
c := *pt
409423
pt = &c

rewrite-go/rewrite/pkg/rpc/go_sender.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ func (s *GoSender) Visit(node any, q *SendQueue) {
7373
s.sendSlice(v, q)
7474
case *tree.MapType:
7575
s.sendMapType(v, q)
76+
case *tree.StatementExpression:
77+
s.sendStatementExpression(v, q)
7678
case *tree.PointerType:
7779
s.sendPointerType(v, q)
7880
case *tree.Channel:
@@ -211,6 +213,11 @@ func (s *GoSender) sendMapType(mt *tree.MapType, q *SendQueue) {
211213
func(v any) { s.Visit(v, q) })
212214
}
213215

216+
func (s *GoSender) sendStatementExpression(se *tree.StatementExpression, q *SendQueue) {
217+
q.GetAndSend(se, func(v any) any { return v.(*tree.StatementExpression).Statement },
218+
func(v any) { s.Visit(v, q) })
219+
}
220+
214221
func (s *GoSender) sendPointerType(pt *tree.PointerType, q *SendQueue) {
215222
q.GetAndSend(pt, func(v any) any { return v.(*tree.PointerType).Elem },
216223
func(v any) { s.Visit(v, q) })

rewrite-go/rewrite/pkg/rpc/node_helpers.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ func nodePrefix(v any) any {
6060
return n.Prefix
6161
case *tree.PointerType:
6262
return n.Prefix
63+
case *tree.StatementExpression:
64+
return n.Prefix
6365
case *tree.Channel:
6466
return n.Prefix
6567
case *tree.FuncType:
@@ -174,6 +176,8 @@ func nodeMarkers(v any) any {
174176
return n.Markers
175177
case *tree.PointerType:
176178
return n.Markers
179+
case *tree.StatementExpression:
180+
return n.Markers
177181
case *tree.Channel:
178182
return n.Markers
179183
case *tree.FuncType:
@@ -288,6 +292,8 @@ func setPrefix(v any, prefix tree.Space) {
288292
n.Prefix = prefix
289293
case *tree.PointerType:
290294
n.Prefix = prefix
295+
case *tree.StatementExpression:
296+
n.Prefix = prefix
291297
case *tree.Channel:
292298
n.Prefix = prefix
293299
case *tree.FuncType:
@@ -400,6 +406,8 @@ func setMarkers(v any, markers tree.Markers) {
400406
n.Markers = markers
401407
case *tree.PointerType:
402408
n.Markers = markers
409+
case *tree.StatementExpression:
410+
n.Markers = markers
403411
case *tree.Channel:
404412
n.Markers = markers
405413
case *tree.FuncType:

rewrite-go/rewrite/pkg/tree/go.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,32 @@ func (n *CommClause) WithMarkers(markers Markers) *CommClause {
564564
return &c
565565
}
566566

567+
// StatementExpression wraps a Statement so it can appear in expression contexts.
568+
// Used for Go function literals which are parsed as MethodDeclaration (a Statement)
569+
// but can appear in return statements, assignments, and call arguments.
570+
type StatementExpression struct {
571+
ID uuid.UUID
572+
Prefix Space
573+
Markers Markers
574+
Statement Statement
575+
}
576+
577+
func (*StatementExpression) isTree() {}
578+
func (*StatementExpression) isJ() {}
579+
func (*StatementExpression) isExpression() {}
580+
581+
func (n *StatementExpression) WithPrefix(prefix Space) *StatementExpression {
582+
c := *n
583+
c.Prefix = prefix
584+
return &c
585+
}
586+
587+
func (n *StatementExpression) WithMarkers(markers Markers) *StatementExpression {
588+
c := *n
589+
c.Markers = markers
590+
return &c
591+
}
592+
567593
// IndexList represents a multi-index expression like `Map[int, string]` (generic instantiation
568594
// with multiple type parameters). Single-index uses ArrayAccess; this is for 2+ indices.
569595
type IndexList struct {

rewrite-go/rewrite/pkg/visitor/go_visitor.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ func (v *GoVisitor) Visit(t tree.Tree, p any) tree.Tree {
123123
return v.self().VisitSlice(n, p)
124124
case *tree.MapType:
125125
return v.self().VisitMapType(n, p)
126+
case *tree.StatementExpression:
127+
return v.self().VisitStatementExpression(n, p)
126128
case *tree.PointerType:
127129
return v.self().VisitPointerType(n, p)
128130
case *tree.Channel:
@@ -200,6 +202,7 @@ type VisitorI interface {
200202
VisitKeyValue(kv *tree.KeyValue, p any) tree.J
201203
VisitSlice(s *tree.Slice, p any) tree.J
202204
VisitMapType(mt *tree.MapType, p any) tree.J
205+
VisitStatementExpression(se *tree.StatementExpression, p any) tree.J
203206
VisitPointerType(pt *tree.PointerType, p any) tree.J
204207
VisitChannel(ch *tree.Channel, p any) tree.J
205208
VisitFuncType(ft *tree.FuncType, p any) tree.J
@@ -538,6 +541,16 @@ func (v *GoVisitor) VisitMapType(mt *tree.MapType, p any) tree.J {
538541
return mt
539542
}
540543

544+
func (v *GoVisitor) VisitStatementExpression(se *tree.StatementExpression, p any) tree.J {
545+
se = se.WithPrefix(v.self().VisitSpace(se.Prefix, p))
546+
se = se.WithMarkers(v.visitMarkers(se.Markers, p))
547+
result := v.self().Visit(se.Statement, p)
548+
if stmt, ok := result.(tree.Statement); ok {
549+
se.Statement = stmt
550+
}
551+
return se
552+
}
553+
541554
func (v *GoVisitor) VisitPointerType(pt *tree.PointerType, p any) tree.J {
542555
pt = pt.WithPrefix(v.self().VisitSpace(pt.Prefix, p))
543556
pt = pt.WithMarkers(v.visitMarkers(pt.Markers, p))

rewrite-go/src/main/java/org/openrewrite/golang/GolangVisitor.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,19 @@ public J visitMapType(Go.MapType mapType, P p) {
155155
return m;
156156
}
157157

158+
public J visitStatementExpression(Go.StatementExpression statementExpression, P p) {
159+
Go.StatementExpression se = statementExpression;
160+
se = se.withPrefix(visitSpace(se.getPrefix(), Space.Location.LANGUAGE_EXTENSION, p));
161+
Expression tempExpression = (Expression) visitExpression(se, p);
162+
if (!(tempExpression instanceof Go.StatementExpression)) {
163+
return tempExpression;
164+
}
165+
se = (Go.StatementExpression) tempExpression;
166+
se = se.withMarkers(visitMarkers(se.getMarkers(), p));
167+
se = se.withStatement((Statement) visitAndCast(se.getStatement(), p));
168+
return se;
169+
}
170+
158171
public J visitPointerType(Go.PointerType pointerType, P p) {
159172
Go.PointerType pt = pointerType;
160173
pt = pt.withPrefix(visitSpace(pt.getPrefix(), Space.Location.LANGUAGE_EXTENSION, p));

0 commit comments

Comments
 (0)