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 2020/10/21 14:48:09 UTC

[groovy] 01/01: GROOVY-9779: don't chain call properties together

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-9779
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit b8b947a61b74e2bacd27b7aa0ed15297fcfe890d
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Oct 21 09:47:53 2020 -0500

    GROOVY-9779: don't chain call properties together
---
 src/main/java/groovy/lang/MetaClassImpl.java |  2 +-
 src/test/groovy/bugs/Groovy9779.groovy       | 91 +++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 9 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 1d678a0..254858b 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -1334,7 +1334,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             return metaClass.invokeMethod(closure.getClass(), closure, DO_CALL_METHOD, originalArguments, false, fromInsideClass);
         }
 
-        if (value != null && !(value instanceof Map)) {
+        if (value != null && !(value instanceof Map) && !methodName.equals(CALL_METHOD)) {
             try {
                 MetaClass metaClass = ((MetaClassRegistryImpl) registry).getMetaClass(value);
                 return metaClass.invokeMethod(value, CALL_METHOD, originalArguments); // delegate to call method of property value
diff --git a/src/test/groovy/bugs/Groovy9779.groovy b/src/test/groovy/bugs/Groovy9779.groovy
index c2b0623..eb383d3 100644
--- a/src/test/groovy/bugs/Groovy9779.groovy
+++ b/src/test/groovy/bugs/Groovy9779.groovy
@@ -22,22 +22,97 @@ import groovy.transform.CompileStatic
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 
 @CompileStatic
 final class Groovy9779 {
     @Test
-    void testCallOperatorOnDynamicProperties() {
+    void testCallOperatorOnDynamicProperties1() {
         assertScript '''
-            class C {
+            class A {
                 def call() { return 42 }
             }
-            class D {
-                static final x = new C()
-                       final y = new C()
+            class C {
+                static final x = new A()
+                       final y = new A()
+            }
+            assert C.x() == 42
+            assert new C().x() == 42
+            assert new C().y() == 42
+        '''
+    }
+
+    @Test
+    void testCallOperatorOnDynamicProperties2() {
+        assertScript '''
+            class A {
+                def call = { -> return 42 }
+            }
+            class C {
+                static final x = new A()
+                       final y = new A()
+            }
+            assert C.x() == 42
+            assert new C().x() == 42
+            assert new C().y() == 42
+        '''
+    }
+
+    @Test // don't chain call properties together
+    void testCallOperatorOnDynamicProperties3() {
+        def err = shouldFail '''
+            class A {
+                def call = { -> return 42 }
+            }
+            class B {
+                def call = new A()
+            }
+            class C {
+                static final x = new B()
+                       final y = new B()
+            }
+            C.x()
+        '''
+        assert err.message.contains('No signature of method: B.call() is applicable')
+    }
+
+    @Test // don't chain call properties together
+    void testCallOperatorOnDynamicProperties4() {
+        def err = shouldFail '''
+            class A {
+                def call(x) { assert x == 1; return 42 }
+            }
+            class B {
+                def call = new A()
+            }
+            class C {
+                def plus = new B()
+            }
+            assert new C() + 1 == 42
+        '''
+        assert err.message.contains('No signature of method: C.plus() is applicable')
+    }
+
+    @Test
+    void testOperatorOverloadViaCallable() {
+        assertScript '''
+            class A {
+                def call(x) { return x + 1 }
+            }
+            class C {
+                def plus = new A()
+            }
+            assert new C() + 1 == 2
+        '''
+    }
+
+    @Test
+    void testOperatorOverloadViaClosure() {
+        assertScript '''
+            class C {
+                def plus = { x -> x + 1 }
             }
-            assert D.x() == 42
-            assert new D().x() == 42
-            assert new D().y() == 42
+            assert new C() + 1 == 2
         '''
     }
 }