Skip to content

Commit 4a92ecf

Browse files
authored
Support Groovy method pointers and array constructor method references (#5782)
1 parent 713fd62 commit 4a92ecf

4 files changed

Lines changed: 98 additions & 10 deletions

File tree

rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -955,8 +955,12 @@ public boolean endsWithClosures(List<org.codehaus.groovy.ast.expr.Expression> li
955955

956956
@Override
957957
public void visitClassExpression(ClassExpression clazz) {
958-
Space prefix = whitespace();
959958
ClassNode type = clazz.getType();
959+
if (type.isArray()) {
960+
queue.add(arrayType(type));
961+
return;
962+
}
963+
Space prefix = whitespace();
960964
String name = type.getNameWithoutPackage().replace('$', '.');
961965
if (!source.startsWith(name, cursor)) {
962966
name = type.getUnresolvedName().replace('$', '.');
@@ -2004,21 +2008,18 @@ public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
20042008

20052009
@Override
20062010
public void visitMethodPointerExpression(MethodPointerExpression ref) {
2007-
String referenceName = null;
2008-
if (ref.getMethodName() instanceof ConstantExpression) {
2009-
referenceName = ((ConstantExpression) ref.getMethodName()).getValue().toString();
2010-
}
2011-
2011+
boolean isMethodRef = ref instanceof MethodReferenceExpression;
2012+
String name = ref.getMethodName().getText();
20122013
queue.add(new J.MemberReference(randomId(),
20132014
whitespace(),
2014-
Markers.EMPTY,
2015-
padRight(visit(ref.getExpression()), sourceBefore("::")),
2015+
isMethodRef ? Markers.EMPTY : Markers.build(singleton(new MethodPointer(randomId()))),
2016+
padRight(visit(ref.getExpression()), sourceBefore(isMethodRef ? "::" : ".&")),
20162017
null, // not supported by Groovy
20172018
padLeft(whitespace(), new J.Identifier(randomId(),
2018-
sourceBefore(referenceName),
2019+
sourceBefore(name),
20192020
Markers.EMPTY,
20202021
emptyList(),
2021-
referenceName,
2022+
name,
20222023
null, null)),
20232024
typeMapping.type(ref.getType()),
20242025
null, // not enough information in the AST

rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,21 @@ public J visitLambda(J.Lambda lambda, PrintOutputCapture<P> p) {
358358
return lambda;
359359
}
360360

361+
@Override
362+
public J visitMemberReference(J.MemberReference memberRef, PrintOutputCapture<P> p) {
363+
beforeSyntax(memberRef, Space.Location.MEMBER_REFERENCE_PREFIX, p);
364+
visitRightPadded(memberRef.getPadding().getContaining(), JRightPadded.Location.MEMBER_REFERENCE_CONTAINING, p);
365+
if (memberRef.getMarkers().findFirst(MethodPointer.class).isPresent()) {
366+
p.append(".&");
367+
} else {
368+
p.append("::");
369+
}
370+
visitContainer("<", memberRef.getPadding().getTypeParameters(), JContainer.Location.TYPE_PARAMETERS, ",", ">", p);
371+
visitLeftPadded("", memberRef.getPadding().getReference(), JLeftPadded.Location.MEMBER_REFERENCE_NAME, p);
372+
afterSyntax(memberRef, p);
373+
return memberRef;
374+
}
375+
361376
@Override
362377
public J visitFieldAccess(J.FieldAccess fieldAccess, PrintOutputCapture<P> p) {
363378
beforeSyntax(fieldAccess, Space.Location.FIELD_ACCESS_PREFIX, p);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.groovy.marker;
17+
18+
import lombok.Value;
19+
import lombok.With;
20+
import org.openrewrite.marker.Marker;
21+
22+
import java.util.UUID;
23+
24+
@Value
25+
@With
26+
public class MethodPointer implements Marker {
27+
UUID id;
28+
}

rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,17 @@ def xMethod() {}
211211
);
212212
}
213213

214+
@Test
215+
void staticMethodPointer() {
216+
rewriteRun(
217+
groovy(
218+
"""
219+
Integer.&parseInt
220+
"""
221+
)
222+
);
223+
}
224+
214225
@Test
215226
void staticMethodReference() {
216227
rewriteRun(
@@ -222,6 +233,17 @@ void staticMethodReference() {
222233
);
223234
}
224235

236+
@Test
237+
void instanceMethodPointer() {
238+
rewriteRun(
239+
groovy(
240+
"""
241+
["a", "b", "c"].forEach(System.out.&println)
242+
"""
243+
)
244+
);
245+
}
246+
225247
@Test
226248
void instanceMethodReference() {
227249
rewriteRun(
@@ -233,6 +255,17 @@ void instanceMethodReference() {
233255
);
234256
}
235257

258+
@Test
259+
void constructorMethodPointer() {
260+
rewriteRun(
261+
groovy(
262+
"""
263+
ArrayList.&new
264+
"""
265+
)
266+
);
267+
}
268+
236269
@Test
237270
void constructorMethodReference() {
238271
rewriteRun(
@@ -244,6 +277,17 @@ void constructorMethodReference() {
244277
);
245278
}
246279

280+
@Test
281+
void arrayConstructorMethodReference() {
282+
rewriteRun(
283+
groovy(
284+
"""
285+
[1, 2, 3].stream().toArray(Integer[]::new)
286+
"""
287+
)
288+
);
289+
}
290+
247291
@SuppressWarnings("GroovyAssignabilityCheck")
248292
@Test
249293
void closureWithImplicitParameter() {

0 commit comments

Comments
 (0)