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 2025/11/22 16:24:38 UTC

(groovy) branch GROOVY-11762 created (now 240e31518a)

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

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


      at 240e31518a GROOVY-11762: field hides getter of super class for callable property

This branch includes the following new commits:

     new 60b25db902 minor refactor
     new 240e31518a GROOVY-11762: field hides getter of super class for callable property

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(groovy) 02/02: GROOVY-11762: field hides getter of super class for callable property

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 240e31518a7589d49d000130b7cc11de72cf0749
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 22 10:03:07 2025 -0600

    GROOVY-11762: field hides getter of super class for callable property
---
 src/main/java/groovy/lang/MetaClassImpl.java |  8 ++--
 src/test/groovy/bugs/Groovy11762.groovy      | 57 ++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index d62bc8438a..c6d3bd94e0 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -1241,7 +1241,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             return transformedMetaMethod.doMethodInvoke(object, arguments);
         }
 
-        return invokePropertyOrMissing(object, methodName, originalArguments, fromInsideClass, isCallToSuper);
+        return invokePropertyOrMissing(sender, object, methodName, originalArguments, fromInsideClass, isCallToSuper);
     }
 
     private MetaMethod getMetaMethod(final Class<?> sender, final Object object, final String methodName, final boolean isCallToSuper, final Object[] arguments) {
@@ -1287,11 +1287,11 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     /**
      * Tries to find a callable property and make the call.
      */
-    private Object invokePropertyOrMissing(final Object object, final String methodName, final Object[] originalArguments, final boolean fromInsideClass, final boolean isCallToSuper) {
-        MetaProperty metaProperty = this.getMetaProperty(methodName, false);
+    private Object invokePropertyOrMissing(final Class<?> sender, final Object object, final String methodName, final Object[] originalArguments, final boolean fromInsideClass, final boolean isCallToSuper) {
+        MetaProperty metaProperty = getEffectiveGetMetaProperty(sender, object, methodName, isCallToSuper); // GROOVY-11762
 
         Object value = null;
-        if (metaProperty != null) {
+        if (!(metaProperty instanceof ReadOnlyMetaProperty)) {
             value = metaProperty.getProperty(object);
         } else if (object instanceof Map<?, ?> map) {
             value = map.get(methodName);
diff --git a/src/test/groovy/bugs/Groovy11762.groovy b/src/test/groovy/bugs/Groovy11762.groovy
new file mode 100644
index 0000000000..7fea64fcb6
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy11762.groovy
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package bugs
+
+import org.junit.jupiter.api.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy11762 {
+
+    @Test
+    void testReadFieldPropertyShadowing() {
+        def shell = new GroovyShell()
+        shell.parse '''package p
+            abstract class A {
+                Closure<String> getFoo() { return { -> 'A' } }
+            }
+            class B extends A {
+                protected Closure<String> foo = { -> 'B' }
+            }
+        '''
+        assertScript shell, '''import p.*
+            class C extends B {
+                void test() {
+                    assert foo() == 'B'
+                    assert this.foo() == 'B'
+                    assert this.@foo() == 'B'
+                    assert this.getFoo()() == 'A'
+
+                    def that = new C()
+                    assert that.foo() == 'B'
+                    assert that.@foo() == 'B'
+                    assert that.getFoo()() == 'A'
+                }
+            }
+
+            new C().test()
+            assert new C().foo() == 'A' // not the field from this perspective
+        '''
+    }
+}


(groovy) 01/02: minor refactor

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 60b25db902b58e9ea4a1f94afee767835c318cf7
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 22 09:51:37 2025 -0600

    minor refactor
---
 src/main/java/groovy/lang/MetaClassImpl.java | 58 +++++++++-------------------
 1 file changed, 19 insertions(+), 39 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 44c44b5373..d62bc8438a 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -1244,7 +1244,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         return invokePropertyOrMissing(object, methodName, originalArguments, fromInsideClass, isCallToSuper);
     }
 
-    private MetaMethod getMetaMethod(Class sender, Object object, String methodName, boolean isCallToSuper, Object... arguments) {
+    private MetaMethod getMetaMethod(final Class<?> sender, final Object object, final String methodName, final boolean isCallToSuper, final Object[] arguments) {
         MetaMethod method = null;
         if (CALL_METHOD.equals(methodName) && object instanceof GeneratedClosure) {
             method = getMethodWithCaching(sender, DO_CALL_METHOD, arguments, isCallToSuper);
@@ -1259,7 +1259,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         return method;
     }
 
-    private MetaMethod tryListParamMetaMethod(Class sender, String methodName, boolean isCallToSuper, Object[] arguments) {
+    private MetaMethod tryListParamMetaMethod(final Class<?> sender, final String methodName, final boolean isCallToSuper, final Object[] arguments) {
         MetaMethod method = null;
         if (arguments.length == 1 && arguments[0] instanceof List) {
             Object[] newArguments = ((List) arguments[0]).toArray();
@@ -1268,7 +1268,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         return method;
     }
 
-    protected MetaMethod createTransformMetaMethod(MetaMethod method) {
+    protected MetaMethod createTransformMetaMethod(final MetaMethod method) {
         if (method == null) {
             return null;
         }
@@ -1293,14 +1293,13 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         Object value = null;
         if (metaProperty != null) {
             value = metaProperty.getProperty(object);
-        } else if (object instanceof Map) {
-            value = ((Map<?, ?>) object).get(methodName);
-        } else if (object instanceof Script) {
-            value = ((Script) object).getBinding().getVariables().get(methodName);
+        } else if (object instanceof Map<?, ?> map) {
+            value = map.get(methodName);
+        } else if (object instanceof Script script) {
+            value = script.getBinding().getVariables().get(methodName);
         }
 
-        if (value instanceof Closure) {
-            Closure<?> closure = (Closure<?>) value;
+        if (value instanceof Closure closure) {
             MetaClass metaClass = closure.getMetaClass();
             try {
                 return metaClass.invokeMethod(closure.getClass(), closure, DO_CALL_METHOD, originalArguments, false, fromInsideClass);
@@ -2826,44 +2825,25 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private MetaProperty getMetaProperty(final Class clazz, final String name, final boolean useSuper, final boolean useStatic) {
-        if (clazz == theClass && !useSuper)
-            return getMetaProperty(name, useStatic);
+    private MetaProperty getMetaProperty(final Class<?> clazz, final String name, final boolean useSuper, final boolean useStatic) {
+        CachedClass cachedClass = (clazz == theClass ? theCachedClass : ReflectionCache.getCachedClass(clazz));
 
-        CachedClass cachedClass = ReflectionCache.getCachedClass(clazz);
-        while (true) {
-            Map<String, MetaProperty> propertyMap;
-            if (useStatic) {
-                propertyMap = staticPropertyIndex;
-            } else if (useSuper) {
-                propertyMap = classPropertyIndexForSuper.get(cachedClass);
-            } else {
-                propertyMap = classPropertyIndex.get(cachedClass);
-            }
-            if (propertyMap == null) {
-                if (cachedClass != theCachedClass) {
-                    cachedClass = theCachedClass;
-                    continue;
-                } else {
-                    return null;
-                }
-            }
-            return propertyMap.get(name);
-        }
-    }
-
-    private MetaProperty getMetaProperty(final String name, final boolean useStatic) {
-        CachedClass clazz = theCachedClass;
         Map<String, MetaProperty> propertyMap;
         if (useStatic) {
             propertyMap = staticPropertyIndex;
+        } else if (!useSuper) {
+            propertyMap = classPropertyIndex.get(cachedClass);
         } else {
-            propertyMap = classPropertyIndex.get(clazz);
+            propertyMap = classPropertyIndexForSuper.get(cachedClass);
         }
-        if (propertyMap == null) {
+
+        if (propertyMap != null) {
+            return propertyMap.get(name);
+        } else if (cachedClass != theCachedClass) {
+            return getMetaProperty(theClass, name, useSuper, useStatic);
+        } else {
             return null;
         }
-        return propertyMap.get(name);
     }
 
     /**