You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by sh...@apache.org on 2016/10/06 02:59:25 UTC
groovy git commit: GROOVY-7952: Property expressions for extension
methods starting with 'is' fail STC (closes #436) * Add support for 'is'
getter method variants of GROOVY-5580
Repository: groovy
Updated Branches:
refs/heads/master f29962c54 -> c504e6455
GROOVY-7952: Property expressions for extension methods starting with 'is' fail STC (closes #436)
* Add support for 'is' getter method variants of GROOVY-5580
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/c504e645
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/c504e645
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/c504e645
Branch: refs/heads/master
Commit: c504e645521315a3eee9bf07e6254e19ef3d2a0a
Parents: f29962c
Author: Shil Sinha <sh...@gmail.com>
Authored: Tue Oct 4 17:08:20 2016 -0400
Committer: Shil Sinha <sh...@gmail.com>
Committed: Wed Oct 5 20:10:00 2016 -0400
----------------------------------------------------------------------
src/main/org/codehaus/groovy/ast/ClassNode.java | 4 ++-
.../asm/sc/StaticTypesCallSiteWriter.java | 18 ++++++++---
.../stc/StaticTypeCheckingVisitor.java | 3 ++
.../stc/DefaultGroovyMethodsSTCTest.groovy | 7 +++++
.../transform/stc/MethodCallsSTCTest.groovy | 33 ++++++++++++++++++++
5 files changed, 59 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/c504e645/src/main/org/codehaus/groovy/ast/ClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/ClassNode.java b/src/main/org/codehaus/groovy/ast/ClassNode.java
index fee628f..9b885fd 100644
--- a/src/main/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/org/codehaus/groovy/ast/ClassNode.java
@@ -1092,10 +1092,12 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
public MethodNode getGetterMethod(String getterName, boolean searchSuperClasses) {
MethodNode getterMethod = null;
+ boolean booleanReturnOnly = getterName.startsWith("is");
for (MethodNode method : getDeclaredMethods(getterName)) {
if (getterName.equals(method.getName())
&& ClassHelper.VOID_TYPE!=method.getReturnType()
- && method.getParameters().length == 0) {
+ && method.getParameters().length == 0
+ && (!booleanReturnOnly || ClassHelper.Boolean_TYPE.equals(ClassHelper.getWrapper(method.getReturnType())))) {
// GROOVY-7363: There can be multiple matches for a getter returning a generic parameter type, due to
// the generation of a bridge method. The real getter is really the non-bridge, non-synthetic one as it
// has the most specific and exact return type of the two. Picking the bridge method results in loss of
http://git-wip-us.apache.org/repos/asf/groovy/blob/c504e645/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index e955efc..9a62622 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -158,19 +158,24 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
// GROOVY-5580, it is still possible that we're calling a superinterface property
String getterName = "get" + MetaClassHelper.capitalize(methodName);
+ String altGetterName = "is" + MetaClassHelper.capitalize(methodName);
if (receiverType.isInterface()) {
Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
MethodNode getterMethod = null;
for (ClassNode anInterface : allInterfaces) {
getterMethod = anInterface.getGetterMethod(getterName);
- if (getterMethod!=null) break;
+ if (getterMethod == null) getterMethod = anInterface.getGetterMethod(altGetterName);
+ if (getterMethod != null) break;
}
// GROOVY-5585
- if (getterMethod==null) {
+ if (getterMethod == null) {
getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
}
+ if (getterMethod == null) {
+ getterMethod = OBJECT_TYPE.getGetterMethod(altGetterName);
+ }
- if (getterMethod!=null) {
+ if (getterMethod != null) {
MethodCallExpression call = new MethodCallExpression(
receiver,
getterName,
@@ -188,13 +193,16 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
// GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
List<MethodNode> methods = findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, getterName, ClassNode.EMPTY_ARRAY);
+ for (MethodNode m: findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, altGetterName, ClassNode.EMPTY_ARRAY)) {
+ if (Boolean_TYPE.equals(getWrapper(m.getReturnType()))) methods.add(m);
+ }
if (!methods.isEmpty()) {
List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
- if (methodNodes.size()==1) {
+ if (methodNodes.size() == 1) {
MethodNode getter = methodNodes.get(0);
MethodCallExpression call = new MethodCallExpression(
receiver,
- getterName,
+ getter.getName(),
ArgumentListExpression.EMPTY_ARGUMENTS
);
call.setMethodTarget(getter);
http://git-wip-us.apache.org/repos/asf/groovy/blob/c504e645/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 1ca5429..df128eb 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1315,6 +1315,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
// GROOVY-5568, the property may be defined by DGM
List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), testClass, "get" + capName, ClassNode.EMPTY_ARRAY);
+ for (MethodNode m: findDGMMethodsByNameAndArguments(getTransformLoader(), testClass, "is" + capName, ClassNode.EMPTY_ARRAY)) {
+ if (Boolean_TYPE.equals(getWrapper(m.getReturnType()))) methods.add(m);
+ }
if (!methods.isEmpty()) {
List<MethodNode> methodNodes = chooseBestMethod(testClass, methods, ClassNode.EMPTY_ARRAY);
if (methodNodes.size() == 1) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/c504e645/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index 3ea6a4d..a8a7531 100644
--- a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
@@ -144,5 +144,12 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
assert list[0] == 3 && list[0].class == Long
'''
}
+
+ // GROOVY-7952
+ void testIsGetterMethodAsProperty() {
+ assertScript '''
+ assert !'abc'.allWhitespace
+ '''
+ }
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/c504e645/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index aa37ecf..d7c6573 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -690,6 +690,39 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ void testIsGetterAsPropertyFromSuperInterface() {
+ assertScript '''interface Upper { boolean isBar() }
+ interface Lower extends Upper {}
+ boolean foo(Lower impl) {
+ impl.bar // isBar() called with the property notation
+ }
+ assert foo({ true } as Lower)
+ '''
+ }
+
+ void testIsGetterAsPropertyFromSuperInterfaceUsingConcreteImpl() {
+ assertScript '''interface Upper { boolean isBar() }
+ interface Lower extends Upper {}
+ class Foo implements Lower { boolean isBar() { true } }
+ boolean foo(Foo impl) {
+ impl.bar // isBar() called with the property notation
+ }
+ assert foo(new Foo())
+ '''
+ }
+
+ void testIsGetterAsPropertyFromSuperInterfaceUsingConcreteImplSubclass() {
+ assertScript '''interface Upper { boolean isBar() }
+ interface Lower extends Upper {}
+ class Foo implements Lower { boolean isBar() { true } }
+ class Bar extends Foo {}
+ boolean foo(Bar impl) {
+ impl.bar // isBar() called with the property notation
+ }
+ assert foo(new Bar())
+ '''
+ }
+
// GROOVY-5580: getName variant
void testGetNameFromSuperInterface() {
assertScript '''interface Upper { String getName() }