You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/09/01 17:04:44 UTC
[groovy] branch master updated: GROOVY-10741: STC: method pointer/reference to generated property method
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new a228fae2d1 GROOVY-10741: STC: method pointer/reference to generated property method
a228fae2d1 is described below
commit a228fae2d16c22a59fd29b8d4b205d9be059dadc
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Sep 1 11:31:09 2022 -0500
GROOVY-10741: STC: method pointer/reference to generated property method
---
.../transform/stc/StaticTypeCheckingVisitor.java | 31 +++++++++++++++++++---
src/test/groovy/transform/stc/BugsSTCTest.groovy | 26 ++++++++++++++++++
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index d791fddc1c..b438d7614f 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2450,6 +2450,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
receiverType = wrapTypeIfNecessary(currentReceiver.getType());
candidates = findMethodsWithGenerated(receiverType, nameText);
+ // GROOVY-10741: check for reference to a property node's method
+ MethodNode generated = findPropertyMethod(receiverType, nameText);
+ if (generated != null && candidates.stream().noneMatch(mn -> mn.getName().equals(generated.getName()))){
+ candidates.add(generated);
+ }
candidates.addAll(findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), receiverType, nameText));
candidates = filterMethodsByVisibility(candidates, typeCheckingContext.getEnclosingClassNode());
@@ -2487,6 +2492,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return makeClassSafe0(CLOSURE_TYPE, wrapTypeIfNecessary(returnType).asGenericsType());
}
+ private static MethodNode findPropertyMethod(final ClassNode type, final String name) {
+ 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());
+ return node;
+ } else if (name.equals(pn.getSetterNameOrDefault()) && !Modifier.isFinal(pn.getModifiers())) {
+ MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC | (pn.isStatic() ? Opcodes.ACC_STATIC : 0), VOID_TYPE, new Parameter[]{new Parameter(pn.getType(), pn.getName())}, ClassNode.EMPTY_ARRAY, null);
+ node.setDeclaringClass(pn.getDeclaringClass());
+ return node;
+ }
+ }
+ }
+ return null;
+ }
+
protected DelegationMetadata getDelegationMetadata(final ClosureExpression expression) {
return expression.getNodeMetaData(DELEGATION_METADATA);
}
@@ -3680,9 +3702,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterfaceType) {
- Parameter[] parameters = findSAM(functionalInterfaceType).getParameters().clone();
- for (int i = 0, n = parameters.length; i < n; i += 1) {
- parameters[i] = new Parameter(dynamicType(), "p" + System.nanoTime());
+ int nParameters = findSAM(functionalInterfaceType).getParameters().length;
+ Parameter[] parameters = new Parameter[nParameters];
+ for (int i = 0; i < nParameters; i += 1) {
+ parameters[i] = new Parameter(dynamicType(), "p" + i);
}
return new LambdaExpression(parameters, EmptyStatement.INSTANCE);
@@ -3726,8 +3749,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
* @param args the argument classes
*/
private static void addArrayMethods(final List<MethodNode> methods, final ClassNode receiver, final String name, final ClassNode[] args) {
- if (args.length != 1) return;
if (!receiver.isArray()) return;
+ if (args == null || args.length != 1) return;
if (!isIntCategory(getUnwrapper(args[0]))) return;
if ("getAt".equals(name)) {
MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, receiver.getComponentType(), new Parameter[]{new Parameter(args[0], "arg")}, null, null);
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 99d718cfb4..e3738a6d2c 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -945,6 +945,32 @@ Printer
'''
}
+ // GROOVY-10741
+ void testMethodPointerPropertyReference() {
+ assertScript '''
+ class C { def foo }
+ List<C> list = [new C(foo:'bar'), new C(foo:'baz')]
+ assert list.collect(C.&getFoo) == ['bar', 'baz'] // Cannot find matching method C#getFoo
+ '''
+ assertScript '''
+ record R(def foo) { }
+ List<R> list = [new R('bar'), new R('baz')]
+ assert list.collect(R.&foo) == ['bar', 'baz'] // Cannot find matching method R#foo
+ '''
+ assertScript '''
+ class C { def foo }
+ def proc = C.&setFoo
+ def pogo = new C(foo:'bar')
+ assert pogo.foo == 'bar'
+ proc.call(pogo, 'baz')
+ assert pogo.foo == 'baz'
+ '''
+ shouldFailWithMessages '''
+ class C { final foo }
+ def set = C.&setFoo
+ ''', 'Cannot find matching method C#setFoo'
+ }
+
// GROOVY-9463
void testMethodPointerUnknownReference() {
shouldFailWithMessages '''