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:48:15 UTC
[groovy] branch GROOVY_2_5_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_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new e25af85727 GROOVY-10741: STC: method pointer/reference to generated property method
e25af85727 is described below
commit e25af85727b1bde560a7c97980460569ed6d99db
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
2_5_X backport
---
.../transform/stc/StaticTypeCheckingVisitor.java | 46 ++++++++++++++++++----
src/test/groovy/transform/stc/BugsSTCTest.groovy | 19 +++++++++
2 files changed, 58 insertions(+), 7 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 ec271d106b..c9a2929376 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1709,7 +1709,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
}
- private MethodNode findGetter(ClassNode current, String name, boolean searchOuterClasses) {
+ private static MethodNode findGetter(ClassNode current, String name, boolean searchOuterClasses) {
MethodNode getterMethod = current.getGetterMethod(name);
if (getterMethod == null && searchOuterClasses && current instanceof InnerClassNode) {
return findGetter(current.getOuterClass(), name, true);
@@ -2541,7 +2541,20 @@ 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) {
+ boolean contains = false;
+ for (MethodNode candidate : candidates) {
+ if (candidate.getName().equals(generated.getName())) {
+ contains = true;
+ break;
+ }
+ }
+ if (!contains) 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);
if (!candidates.isEmpty()) {
@@ -2585,6 +2598,26 @@ 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 properName = MetaClassHelper.capitalize(pn.getName());
+ String getterName = "get" + properName; // Groovy 4+ moves getter name to PropertyNode#getGetterNameOrDefault
+ if (boolean_TYPE.equals(pn.getType()) && findGetter(cn, getterName, false) == null) getterName = "is" + properName;
+ 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("set" + properName) && !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 (DelegationMetadata) expression.getNodeMetaData(StaticTypesMarker.DELEGATION_METADATA);
}
@@ -3703,8 +3736,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);
@@ -4597,11 +4630,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 d4357d24bb..395894d97d 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -918,6 +918,25 @@ Printer
'''
}
+ // GROOVY-10741
+ void testMethodPointerPropertyReference() {
+ assertScript '''
+ class C { def foo }
+ def pogo = new C(foo:'bar')
+ assert pogo.foo == 'bar'
+
+ def proc = pogo.&setFoo
+ proc.call('baz')
+ assert pogo.foo == 'baz'
+ '''
+ shouldFailWithMessages '''
+ class C { final foo }
+ def pogo = new C(foo:'bar')
+
+ def proc = pogo.&setFoo
+ ''', 'Cannot find matching method C#setFoo'
+ }
+
// GROOVY-9463
void testMethodPointerUnknownReference() {
shouldFailWithMessages '''