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

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

commit 4445a1e618a081d6899191da50cb11244eb07fb7
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Thu Nov 21 13:44:14 2024 -0600

    GROOVY-8283: STC: field hides getter of super class
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 18 ++++++---
 src/test/groovy/bugs/Groovy8283.groovy             | 44 ++++++++++++++++++++++
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index e9036cb409..b087852c08 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1685,11 +1685,13 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                 else if (field != null && enclosingTypes.contains(current) && 
storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
                     return true;
                 }
+                // GROOVY-8283: accessible field shadows getter of super 
class; GROOVY-11381: inaccessible field stops the loop, so search supers for 
getter
+                boolean checkUp = field != null && 
!hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), 
field.getDeclaringClass(), field.getModifiers());
 
-                MethodNode getter = current.getGetterMethod(isserName);
+                MethodNode getter = getGetterMethod(current, isserName, 
checkUp);
                 getter = allowStaticAccessToMember(getter, staticOnly);
                 if (getter == null) {
-                    getter = current.getGetterMethod(getterName);
+                    getter = getGetterMethod(current, getterName, checkUp);
                     getter = allowStaticAccessToMember(getter, staticOnly);
                 }
                 if (getter != null && ((publicOnly && (!getter.isPublic() || 
"class".equals(propertyName) || "empty".equals(propertyName)))
@@ -1702,8 +1704,8 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
 
                 PropertyNode property = current.getProperty(propertyName);
                 property = allowStaticAccessToMember(property, staticOnly);
-                // prefer explicit getter or setter over property if receiver 
is not 'this'
-                if (property == null || 
!enclosingTypes.contains(receiverType)) {
+                // prefer explicit getter/setter for out-of-scope references
+                if (property == null || !enclosingTypes.contains(current)) {
                     if (readMode) {
                         if (getter != null) {
                             ClassNode returnType = 
inferReturnTypeGenerics(receiverType, getter, 
ArgumentListExpression.EMPTY_ARGUMENTS);
@@ -1849,6 +1851,12 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
         return foundGetterOrSetter;
     }
 
+    private static MethodNode getGetterMethod(final ClassNode classNode, final 
String getterName, final boolean searchSupers) {
+        MethodNode getter = classNode.getGetterMethod(getterName, 
searchSupers);
+        if (getter != null && (getter.getModifiers() & Opcodes.ACC_BRIDGE) != 
0) getter = null; // GROOVY-11341
+        return getter;
+    }
+
     private static boolean hasAccessToMember(final ClassNode accessor, final 
ClassNode receiver, final int modifiers) {
         if (Modifier.isPublic(modifiers)
                 || accessor.equals(receiver)
@@ -2742,7 +2750,7 @@ out:    if ((samParameterTypes.length == 1 && 
isOrImplements(samParameterTypes[0
                     node.setDeclaringClass(pn.getDeclaringClass());
                     node.setSynthetic(true);
                     return node;
-                } else if (name.equals(pn.getSetterNameOrDefault()) && 
!Modifier.isFinal(pn.getModifiers())) {
+                } else if (name.equals(pn.getSetterNameOrDefault()) && 
!pn.isFinal()) {
                     MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC 
| (pn.isStatic() ? Opcodes.ACC_STATIC : 0), VOID_TYPE, new Parameter[]{new 
Parameter(pn.getType(), pn.getName())}, ClassNode.EMPTY_ARRAY, null);
                     node.setDeclaringClass(pn.getDeclaringClass());
                     node.setSynthetic(true);
diff --git a/src/test/groovy/bugs/Groovy8283.groovy 
b/src/test/groovy/bugs/Groovy8283.groovy
index ec99829e2d..9e75a720b2 100644
--- a/src/test/groovy/bugs/Groovy8283.groovy
+++ b/src/test/groovy/bugs/Groovy8283.groovy
@@ -56,6 +56,50 @@ final class Groovy8283 {
             new E().test()
             assert new E().foo.class == A // not the field from this 
perspective
         '''
+        assertScript shell, '''import p.*
+            class E extends D {
+                
@groovy.transform.ASTTest(phase=org.codehaus.groovy.control.CompilePhase.INSTRUCTION_SELECTION,
 value={
+                    def typeof = { label -> 
lookup(label)[0].getExpression().getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_TYPE).toString(false)
 }
+
+                    assert typeof('implicit'   ) == 'p.B'
+                    assert typeof('explicit'   ) == 'p.B'
+                    assert typeof('attribute'  ) == 'p.B'
+                    assert typeof('methodCall' ) == 'p.A'
+
+                    assert typeof('property'   ) == 'p.B'
+                    assert typeof('attribute2' ) == 'p.B'
+                    assert typeof('methodCall2') == 'p.A'
+                })
+                @groovy.transform.TypeChecked
+                void test() {
+                  implicit:
+                    def a = foo
+                  explicit:
+                    def b = this.foo
+                  attribute:
+                    def c = this.@foo
+                  methodCall:
+                    def d = this.getFoo()
+
+                    def that = new E()
+                  property:
+                    def x = that.foo
+                  attribute2:
+                    def y = that.@foo
+                  methodCall2:
+                    def z = that.getFoo()
+                }
+            }
+
+            @groovy.transform.TypeChecked
+            void test() {
+                
@groovy.transform.ASTTest(phase=org.codehaus.groovy.control.CompilePhase.INSTRUCTION_SELECTION,
 value={
+                    def type = 
node.getNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_TYPE)
+                    assert type.toString(false) == 'p.A'
+                })
+                def a = new E().foo
+            }
+        '''
     }
 
     @Test

Reply via email to