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 18:14:18 UTC
[groovy] branch GROOVY_3_0_X 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 GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new 9f8518a6dc GROOVY-10741: STC: method pointer/reference to generated property method
9f8518a6dc is described below
commit 9f8518a6dcf2077f931bf7b0da34de1685ac1076
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
3_0_X backport
---
.../transform/stc/StaticTypeCheckingVisitor.java | 63 +++++++++++++---------
src/test/groovy/transform/stc/BugsSTCTest.groovy | 21 ++++++++
2 files changed, 59 insertions(+), 25 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 0e4162f0d3..a93bd0db9e 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -189,11 +189,11 @@ import static org.codehaus.groovy.ast.tools.ClosureUtils.getResolveStrategyName;
import static org.codehaus.groovy.ast.tools.ClosureUtils.hasImplicitParameter;
import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.elvisX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getGetterName;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
@@ -1727,7 +1727,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- private MethodNode findGetter(final ClassNode current, String name, final boolean searchOuterClasses) {
+ private static MethodNode findGetter(final ClassNode current, String name, final boolean searchOuterClasses) {
MethodNode getterMethod = current.getGetterMethod(name);
if (getterMethod == null && searchOuterClasses && current.getOuterClass() != null) {
return findGetter(current.getOuterClass(), name, true);
@@ -2490,7 +2490,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
ClassNode receiverType = wrapTypeIfNecessary(currentReceiver.getType());
candidates = findMethodsWithGenerated(receiverType, nameText);
- if (isBeingCompiled(receiverType)) candidates.addAll(GROOVY_OBJECT_TYPE.getMethods(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);
+ }
+ if (!receiverType.isInterface() && isBeingCompiled(receiverType))
+ candidates.addAll(GROOVY_OBJECT_TYPE.getMethods(nameText));
candidates.addAll(findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), receiverType, nameText));
candidates = filterMethodsByVisibility(candidates, typeCheckingContext.getEnclosingClassNode());
@@ -2526,6 +2532,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return inferredType;
}
+ private static MethodNode findPropertyMethod(final ClassNode type, final String name) {
+ for (ClassNode cn = type; cn != null; cn = cn.getSuperClass()) {
+ for (PropertyNode pn : cn.getProperties()) {
+ String getterName = getGetterName(pn); // Groovy 4+ moves getter name to PropertyNode#getGetterNameOrDefault
+ if (boolean_TYPE.equals(pn.getType()) && findGetter(cn, getterName, false) == null) getterName = "is" + capitalize(pn.getName());
+ if (name.equals(getterName)) {
+ 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(getSetterName(pn.getName())) && !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);
}
@@ -3663,24 +3688,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode paramType) {
- Parameter[] newParameters = createParametersForConstructedLambdaExpression(paramType);
- return new LambdaExpression(newParameters, block());
- }
-
- private Parameter[] createParametersForConstructedLambdaExpression(final ClassNode functionalInterfaceType) {
- MethodNode abstractMethodNode = findSAM(functionalInterfaceType);
-
- Parameter[] abstractMethodNodeParameters = abstractMethodNode.getParameters();
- if (abstractMethodNodeParameters == null) {
- abstractMethodNodeParameters = Parameter.EMPTY_ARRAY;
+ private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterfaceType) {
+ int nParameters = findSAM(functionalInterfaceType).getParameters().length;
+ Parameter[] parameters = new Parameter[nParameters];
+ for (int i = 0; i < nParameters; i += 1) {
+ parameters[i] = new Parameter(DYNAMIC_TYPE, "p" + i);
}
-
- Parameter[] newParameters = new Parameter[abstractMethodNodeParameters.length];
- for (int i = 0; i < newParameters.length; i += 1) {
- newParameters[i] = new Parameter(DYNAMIC_TYPE, "p" + System.nanoTime());
- }
- return newParameters;
+ return new LambdaExpression(parameters, GENERATED_EMPTY_STATEMENT);
}
/**
@@ -3721,8 +3735,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);
@@ -4729,11 +4743,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
if (receiver.isInterface()) {
methods.addAll(OBJECT_TYPE.getMethods(name));
}
-
- if (methods.isEmpty() || receiver.isResolved()) {
- return methods;
+ if (!receiver.isResolved() && !methods.isEmpty()) {
+ methods = addGeneratedMethods(receiver, methods);
}
- return addGeneratedMethods(receiver, methods);
+ return methods;
}
private static List<MethodNode> addGeneratedMethods(final ClassNode receiver, final List<MethodNode> methods) {
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 2671495372..46788b6d0c 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -934,6 +934,27 @@ 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 '''
+ 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 '''