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 2024/04/27 20:38:54 UTC
(groovy) 01/02: GROOVY-8283: field hides getter of super class (not interface)
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-8283
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 953acc1596e0688817f566a855d4693bd8eb0c09
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Aug 19 11:54:51 2022 -0500
GROOVY-8283: field hides getter of super class (not interface)
---
src/main/java/groovy/lang/MetaClassImpl.java | 45 ++++++++++++++-------
src/test/groovy/bugs/Groovy8283.groovy | 60 ++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 15 deletions(-)
diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 71e89ac635..0ff27734a1 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -1822,18 +1822,18 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
//----------------------------------------------------------------------
Tuple2<MetaMethod, MetaProperty> methodAndProperty = createMetaMethodAndMetaProperty(sender, sender, name, useSuper, isStatic);
MetaMethod method = methodAndProperty.getV1();
+ MetaProperty prop = methodAndProperty.getV2();
- if (method == null || isSpecialProperty(name)) {
+ if (method == null || isSpecialProperty(name) || isVisibleProperty(prop, method, sender)) {
//------------------------------------------------------------------
// public field
//------------------------------------------------------------------
- MetaProperty mp = methodAndProperty.getV2();
- if (mp != null && mp.isPublic()) {
+ if (prop != null && prop.isPublic()) {
try {
- return mp.getProperty(object);
+ return prop.getProperty(object);
} catch (GroovyRuntimeException e) {
// can't access the field directly but there may be a getter
- mp = null;
+ prop = null;
}
}
@@ -1847,9 +1847,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
//------------------------------------------------------------------
// non-public field
//------------------------------------------------------------------
- if (mp != null) {
+ if (prop != null) {
try {
- return mp.getProperty(object);
+ return prop.getProperty(object);
} catch (GroovyRuntimeException e) {
}
}
@@ -1937,19 +1937,19 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
//----------------------------------------------------------------------
Tuple2<MetaMethod, MetaProperty> methodAndProperty = createMetaMethodAndMetaProperty(sender, theClass, name, useSuper, isStatic);
MetaMethod method = methodAndProperty.getV1();
+ MetaProperty prop = methodAndProperty.getV2();
- if (method == null || isSpecialProperty(name)) {
+ if (method == null || isSpecialProperty(name) || isVisibleProperty(prop, method, sender)) {
//------------------------------------------------------------------
// public field
//------------------------------------------------------------------
- MetaProperty mp = methodAndProperty.getV2();
- if (mp != null && mp.isPublic()) {
- return mp;
+ if (prop != null && prop.isPublic()) {
+ return prop;
}
- //----------------------------------------------------------------------
+ //------------------------------------------------------------------
// java.util.Map get method
- //----------------------------------------------------------------------
+ //------------------------------------------------------------------
if (isMap && !isStatic) {
return new MetaProperty(name, Object.class) {
@Override
@@ -1967,8 +1967,8 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
//------------------------------------------------------------------
// non-public field
//------------------------------------------------------------------
- if (mp != null) {
- return mp;
+ if (prop != null) {
+ return prop;
}
}
@@ -2086,6 +2086,21 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
return "class".equals(name) || (isMap && ("empty".equals(name) || "metaClass".equals(name)));
}
+ private boolean isVisibleProperty(final MetaProperty field, final MetaMethod method, final Class<?> sender) {
+ if (!(field instanceof CachedField)) return false;
+
+ if (field.isPrivate()) return false;
+
+ Class<?> owner = ((CachedField) field).getDeclaringClass();
+ // ensure access originates within the type hierarchy of the field owner
+ if (owner.equals(sender) || !owner.isAssignableFrom(sender)) return false;
+
+ if (!field.isPublic() && !field.isProtected() && !inSamePackage(owner, sender)) return false;
+
+ // GROOVY-8283: non-private field that hides class access method
+ return !owner.isAssignableFrom(method.getDeclaringClass().getTheClass()) && !method.getDeclaringClass().isInterface();
+ }
+
private Tuple2<MetaMethod, MetaProperty> createMetaMethodAndMetaProperty(final Class senderForMP, final Class senderForCMG, final String name, final boolean useSuper, final boolean isStatic) {
MetaMethod method = null;
MetaProperty mp = getMetaProperty(senderForMP, name, useSuper, isStatic);
diff --git a/src/test/groovy/bugs/Groovy8283.groovy b/src/test/groovy/bugs/Groovy8283.groovy
new file mode 100644
index 0000000000..96956770ad
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy8283.groovy
@@ -0,0 +1,60 @@
+/*
+ * 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 groovy.bugs
+
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy8283 {
+
+ @Test
+ void testReadFieldPropertyShadowing() {
+ def shell = new GroovyShell()
+ shell.parse '''package p
+ class A {}
+ class B {}
+ class C {
+ protected A foo = new A()
+ A getFoo() { return foo }
+ }
+ class D extends C {
+ protected B foo = new B() // hides A#foo; should hide A#getFoo in subclasses
+ }
+ '''
+ assertScript shell, '''import p.*
+ class E extends D {
+ void test() {
+ assert foo.class == B
+ assert this.foo.class == B
+ assert this.@foo.class == B
+ assert this.getFoo().getClass() == A
+
+ def that = new E()
+ assert that.foo.class == B
+ assert that.@foo.class == B
+ assert that.getFoo().getClass() == A
+ }
+ }
+
+ new E().test()
+ assert new E().foo.class == A // not the field from this perspective
+ '''
+ }
+}