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() }