This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new 3aa0530920 GROOVY-10904, GROOVY-11618: reference to inner class
property method
3aa0530920 is described below
commit 3aa0530920dc8724cf20c55884f4496a8786f017
Author: Eric Milles <[email protected]>
AuthorDate: Sun Apr 13 12:22:52 2025 -0500
GROOVY-10904, GROOVY-11618: reference to inner class property method
---
...StaticTypesMethodReferenceExpressionWriter.java | 25 +++
.../transform/stc/MethodReferenceTest.groovy | 173 ++++++++++++++-------
2 files changed, 145 insertions(+), 53 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
index 4eeda01ded..c6a48edcc0 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
@@ -24,6 +24,7 @@ import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.ArrayExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
@@ -399,6 +400,11 @@ public class StaticTypesMethodReferenceExpressionWriter
extends MethodReferenceE
private List<MethodNode> findVisibleMethods(final String name, final
ClassNode type) {
List<MethodNode> methods = type.getMethods(name);
+ // GROOVY-11618: reference to a property node's method
+ MethodNode generated = findPropertyMethod(name, type);
+ if (generated != null && methods.stream().noneMatch(m ->
m.getName().equals(generated.getName()))) {
+ methods.add(generated);
+ }
// GROOVY-10791, GROOVY-11467: include non-static interface methods
Set<ClassNode> implemented = getInterfacesAndSuperInterfaces(type);
implemented.remove(type);
@@ -413,6 +419,25 @@ public class StaticTypesMethodReferenceExpressionWriter
extends MethodReferenceE
return filterMethodsByVisibility(methods, controller.getClassNode());
}
+ private MethodNode findPropertyMethod(final String name, final ClassNode
type) {
+ for (ClassNode cn = type; cn != null; cn = cn.getSuperClass()) {
+ for (PropertyNode pn : cn.getProperties()) {
+ if (name.equals(pn.getGetterNameOrDefault())) {
+ MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC
| (pn.isStatic() ? Opcodes.ACC_STATIC : 0), pn.getType(),
Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
+ node.setDeclaringClass(pn.getDeclaringClass());
+ node.setSynthetic(true);
+ return node;
+ } else if (name.equals(pn.getSetterNameOrDefault()) &&
(pn.getModifiers() & Opcodes.ACC_FINAL) == 0) {
+ MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC
| (pn.isStatic() ? Opcodes.ACC_STATIC : 0), ClassHelper.VOID_TYPE, new
Parameter[]{new Parameter(pn.getType(), pn.getName())}, ClassNode.EMPTY_ARRAY,
null);
+ node.setDeclaringClass(pn.getDeclaringClass());
+ node.setSynthetic(true);
+ return node;
+ }
+ }
+ }
+ return null;
+ }
+
private void addFatalError(final String msg, final ASTNode node) {
controller.getSourceUnit().addFatalError(msg, node);
// GRECLIPSE: addFatalError won't throw for quick parse
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 91f61ed26d..6c198f55d9 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -61,7 +61,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-10047
+ // GROOVY-10047
+ @Test // class::instanceMethod
void testFunctionCI3() {
assertScript shell, '''
@CompileStatic
@@ -99,7 +100,8 @@ final class MethodReferenceTest {
assert err =~ /Invalid receiver type: java.lang.Integer is not
compatible with java.lang.String/
}
- @Test // class::instanceMethod -- GROOVY-9814
+ // GROOVY-9814
+ @Test // class::instanceMethod
void testFunctionCI5() {
assertScript shell, '''
class One { String id }
@@ -123,7 +125,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-9813
+ // GROOVY-9813
+ @Test // class::instanceMethod
void testFunctionCI6() {
String head = '''
@CompileStatic
@@ -156,7 +159,8 @@ final class MethodReferenceTest {
''' + tail
}
- @Test // class::instanceMethod -- GROOVY-9853
+ // GROOVY-9853
+ @Test // class::instanceMethod
void testFunctionCI7() {
assertScript shell, '''
@CompileStatic
@@ -218,7 +222,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-10734
+ // GROOVY-10054, GROOVY-10734
+ @Test // class::instanceMethod
void testFunctionCI8() {
assertScript shell, '''
class C {
@@ -238,7 +243,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-9803
+ // GROOVY-9803
+ @Test // class::instanceMethod
void testFunctionCI9() {
assertScript shell, '''
class Try<X> { X x
@@ -265,7 +271,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-11241
+ // GROOVY-11241
+ @Test // class::instanceMethod
void testFunctionCI10() {
assertScript shell, '''
@Grab('io.vavr:vavr:0.10.4')
@@ -327,7 +334,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-11259
+ // GROOVY-11259
+ @Test // class::instanceMethod
void testFunctionCI11() {
assertScript shell, '''
def consume(Set<String> keys){keys}
@@ -345,7 +353,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::instanceMethod -- GROOVY-9974
+ // GROOVY-9974
+ @Test // class::instanceMethod
void testPredicateCI1() {
assertScript shell, '''
@CompileStatic
@@ -358,8 +367,9 @@ final class MethodReferenceTest {
'''
}
+ // GROOVY-11051
@NotYetImplemented
- @Test // class::instanceMethod -- GROOVY-11051
+ @Test // class::instanceMethod
void testPredicateCI2() {
[['null','Empty'],['new Object()','Present']].each { value, which ->
assertScript """import java.util.concurrent.atomic.AtomicReference
@@ -370,7 +380,8 @@ final class MethodReferenceTest {
}
}
- @Test // class::instanceMethod -- GROOVY-10791
+ // GROOVY-10791
+ @Test // class::instanceMethod
void testBiConsumerCI() {
assertScript shell, '''
@CompileStatic
@@ -383,7 +394,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10974
+ // GROOVY-10974
+ @Test // instance::instanceMethod
void testBiConsumerII() {
assertScript shell, '''import java.util.stream.*
@CompileStatic
@@ -411,7 +423,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10933
+ // GROOVY-10933
+ @Test // instance::instanceMethod
void testConsumerII() {
assertScript shell, '''
@CompileStatic
@@ -426,7 +439,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-11020
+ // GROOVY-11020
+ @Test // instance::instanceMethod
void testConsumerII2() {
assertScript shell, '''
def <C extends Consumer<String>> void m(C c) {
@@ -462,7 +476,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-11068
+ // GROOVY-11068
+ @Test // instance::instanceMethod
void testConsumerII3() {
assertScript shell, '''
@Grab('org.apache.pdfbox:pdfbox:2.0.28')
@@ -485,7 +500,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-11068
+ // GROOVY-11068
+ @Test // instance::instanceMethod
void testConsumerII4() {
assertScript shell, '''
@Grab('org.apache.pdfbox:pdfbox:2.0.28')
@@ -510,7 +526,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-9813
+ // GROOVY-9813
+ @Test // instance::instanceMethod
void testFunctionII() {
String asList = '''
def <T> List<T> asList(T... a) {
@@ -568,7 +585,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10653
+ // GROOVY-10653
+ @Test // instance::instanceMethod
void testFunctionII2() {
assertScript shell, '''
class C {
@@ -591,7 +609,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceGroovyMethod -- GROOVY-10653
+ // GROOVY-10653
+ @Test // instance::instanceGroovyMethod
void testFunctionII3() {
assertScript shell, '''
@CompileStatic
@@ -605,7 +624,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10972
+ // GROOVY-10972
+ @Test // instance::instanceMethod
void testFunctionII4() {
assertScript shell, '''
@CompileStatic
@@ -620,7 +640,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-11364
+ // GROOVY-11364
+ @Test // instance::instanceMethod
void testFunctionII5() {
assertScript shell, '''
abstract class A<N extends Number> {
@@ -643,7 +664,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10057
+ // GROOVY-10057
+ @Test // instance::instanceMethod
void testPredicateII() {
assertScript shell, '''
Class c = Integer
@@ -671,7 +693,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10994
+ // GROOVY-10994
+ @Test // instance::instanceMethod
void testPredicateII2() {
assertScript shell, '''
@CompileStatic
@@ -683,7 +706,8 @@ final class MethodReferenceTest {
'''
}
- @Test // instance::instanceMethod -- GROOVY-10975
+ // GROOVY-10975
+ @Test // instance::instanceMethod
void testComparatorII() {
assertScript shell, '''
@CompileStatic
@@ -697,8 +721,9 @@ final class MethodReferenceTest {
'''
}
+ // GROOVY-11026
@NotYetImplemented
- @Test // instance::instanceMethod -- GROOVY-11026
+ @Test // instance::instanceMethod
void testBiFunctionII() {
assertScript shell, '''
@CompileDynamic
@@ -902,7 +927,7 @@ final class MethodReferenceTest {
}
@Test // class::new
- void testFunctionCN() {
+ void testFunctionCN1() {
assertScript shell, '''
@CompileStatic
void test() {
@@ -928,7 +953,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::new -- GROOVY-10033
+ // GROOVY-10033
+ @Test // class::new
void testFunctionCN3() {
assertScript shell, '''
@CompileStatic
@@ -946,7 +972,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::new -- GROOVY-10033
+ // GROOVY-10033
+ @Test // class::new
void testFunctionCN4() {
assertScript shell, '''
class A {
@@ -976,8 +1003,9 @@ final class MethodReferenceTest {
'''
}
+ // GROOVY-10930
@NotYetImplemented
- @Test // class::new -- GROOVY-10930
+ @Test // class::new
void testFunctionCN5() {
def err = shouldFail shell, '''
class Foo { Foo() { } }
@@ -993,7 +1021,8 @@ final class MethodReferenceTest {
assert err =~ /Cannot find matching constructor
Foo\(java.lang.String\)/
}
- @Test // class::new -- GROOVY-10971
+ // GROOVY-10971
+ @Test // class::new
void testFunctionCN6() {
assertScript shell, '''
class Foo {
@@ -1009,7 +1038,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::new -- GROOVY-11001
+ // GROOVY-11001
+ @Test // class::new
void testFunctionCN7() {
assertScript shell, '''
@Grab('io.vavr:vavr:0.10.4')
@@ -1031,7 +1061,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::new -- GROOVY-11385
+ // GROOVY-11385
+ @Test // class::new
void testFunctionCN8() {
def err = shouldFail shell, '''
abstract class A {
@@ -1067,7 +1098,7 @@ final class MethodReferenceTest {
void test() {
IntFunction<Integer[]> f = Integer[]::new;
def result = [1, 2, 3].stream().toArray(f)
- assert result == new Integer[] {1, 2, 3}
+ assert result == new Integer[] { 1, 2, 3 }
}
test()
@@ -1090,7 +1121,7 @@ final class MethodReferenceTest {
@Test // class::staticMethod
void testFunctionCS2() {
def methods = ['Collections::singletonList']
- if (isAtLeastJdk('9.0')) methods<<'List::of' // GROOVY-11024
+ if (isAtLeastJdk('9.0')) methods.add('List::of') // GROOVY-11024
for (makeList in methods) {
assertScript shell, """
@CompileStatic
@@ -1103,7 +1134,8 @@ final class MethodReferenceTest {
}
}
- @Test // class::staticMethod -- GROOVY-9799
+ // GROOVY-9799
+ @Test // class::staticMethod
void testFunctionCS3() {
assertScript shell, '''
class C {
@@ -1155,7 +1187,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::staticMethod -- GROOVY-9813
+ // GROOVY-9813
+ @Test // class::staticMethod
void testFunctionCS6() {
assertScript shell, '''
@CompileStatic
@@ -1194,7 +1227,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::staticMethod -- GROOVY-10807
+ // GROOVY-10807
+ @Test // class::staticMethod
void testFunctionCS7() {
assertScript shell, '''
@CompileStatic
@@ -1212,8 +1246,9 @@ final class MethodReferenceTest {
'''
}
+ // GROOVY-10807
@NotYetImplemented
- @Test // class::staticMethod -- GROOVY-10807
+ @Test // class::staticMethod
void testFunctionCS8() {
assertScript shell, '''
@CompileStatic
@@ -1231,7 +1266,8 @@ final class MethodReferenceTest {
'''
}
- @Test // class::staticMethod -- GROOVY-11009
+ // GROOVY-11009
+ @Test // class::staticMethod
void testFunctionCS9() {
assertScript shell, '''
class C {
@@ -1316,7 +1352,8 @@ final class MethodReferenceTest {
assert err.message.contains("Failed to find class method
'addx(java.math.BigDecimal,java.math.BigDecimal)' or instance method
'addx(java.math.BigDecimal)' for the type: java.math.BigDecimal")
}
- @Test // GROOVY-9463
+ // GROOVY-9463
+ @Test
void testMethodNotFound2() {
def err = shouldFail shell, '''
@CompileStatic
@@ -1327,7 +1364,8 @@ final class MethodReferenceTest {
assert err.message.contains("Failed to find class method
'toLowerCaseX(java.lang.String)' or instance method 'toLowerCaseX()' for the
type: java.lang.String")
}
- @Test // GROOVY-10714
+ // GROOVY-10714
+ @Test
void testMethodSelection() {
assertScript shell, '''
class C {
@@ -1359,7 +1397,8 @@ final class MethodReferenceTest {
'''
}
- @Test // GROOVY-10813, GROOVY-11363
+ // GROOVY-10813, GROOVY-11363
+ @Test
void testMethodSelection2() {
for (spec in ['', '<?>', '<Object>', '<? extends Object>', '<? super
String>']) {
assertScript shell, """
@@ -1414,7 +1453,8 @@ final class MethodReferenceTest {
'''
}
- @Test // GROOVY-10813, GROOVY-10858
+ // GROOVY-10813, GROOVY-10858
+ @Test
void testMethodSelection3() {
def err = shouldFail shell, '''
@CompileStatic
@@ -1425,7 +1465,8 @@ final class MethodReferenceTest {
assert err.message.contains("Failed to find class method 'toString()'
for the type: java.lang.Object")
}
- @Test // GROOVY-10859
+ // GROOVY-10859
+ @Test
void testDynamicMethodSelection() {
for (tag in ['@TypeChecked', '@CompileStatic', '@CompileDynamic']) {
assertScript shell, """
@@ -1440,8 +1481,8 @@ final class MethodReferenceTest {
}
}
- @NotYetImplemented
- @Test // GROOVY-10904
+ // GROOVY-10904
+ @Test
void testPropertyMethodLocation() {
for (tag in ['@TypeChecked', '@CompileStatic', '@CompileDynamic']) {
assertScript shell, """
@@ -1462,7 +1503,8 @@ final class MethodReferenceTest {
}
}
- @Test // GROOVY-10742
+ // GROOVY-10742
+ @Test
void testIncompatibleReturnType() {
def err = shouldFail shell, '''
void foo(bar) {
@@ -1475,7 +1517,8 @@ final class MethodReferenceTest {
assert err =~ /Invalid return type: void is not convertible to
java.lang.String/
}
- @Test // GROOVY-10269
+ // GROOVY-10269
+ @Test
void testNotFunctionalInterface() {
def err = shouldFail shell, '''
void foo(Integer y) {
@@ -1492,7 +1535,8 @@ final class MethodReferenceTest {
assert err =~ /Argument is a method reference, but parameter type
'java.lang.Object' is not a functional interface/
}
- @Test // GROOVY-10336
+ // GROOVY-10336
+ @Test
void testNotFunctionalInterface2() {
def err = shouldFail shell, '''
class C {
@@ -1509,7 +1553,8 @@ final class MethodReferenceTest {
assert err =~ /Argument is a method reference, but parameter type
'java.lang.Object' is not a functional interface/
}
- @Test // GROOVY-10979
+ // GROOVY-10979
+ @Test
void testNotFunctionalInterface3() {
def err = shouldFail shell, '''
Integer m(String x) {
@@ -1529,7 +1574,8 @@ final class MethodReferenceTest {
assert err =~ /Argument is a method reference, but parameter type 'U'
is not a functional interface/
}
- @Test // GROOVY-11254
+ // GROOVY-11254
+ @Test
void testLocalFunctionalInterface() {
assertScript shell, '''
class C { String s }
@@ -1547,7 +1593,8 @@ final class MethodReferenceTest {
'''
}
- @Test // GROOVY-11467
+ // GROOVY-11467
+ @Test
void testSuperInterfaceMethodReference() {
assertScript shell, '''
interface A { int m() }
@@ -1567,7 +1614,8 @@ final class MethodReferenceTest {
'''
}
- @Test // GROOVY-10635
+ // GROOVY-10635
+ @Test
void testRecordComponentMethodReference() {
assertScript shell, '''
record Bar(String name) {
@@ -1576,4 +1624,23 @@ final class MethodReferenceTest {
assert
bars.stream().map(Bar::name).map(String::toLowerCase).toList() == ['a', 'b']
'''
}
+
+ // GROOVY-11618
+ @Test
+ void testRecordComponentMethodReference2() {
+ assertScript shell, '''
+ class C {
+ record R(String x) {
+ }
+ @CompileStatic m() {
+ def list = [new R('x')]
+ def stream = list.stream().map(R::x)
+ def string = stream.collect(Collectors.joining())
+
+ assert string == 'x'
+ }
+ }
+ new C().m()
+ '''
+ }
}