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
The following commit(s) were added to refs/heads/GROOVY-8283 by this push:
new a69e055fce GROOVY-8283: STC: field hides getter of super class
a69e055fce is described below
commit a69e055fce2551923f4f300a627a5dcafcfe4065
Author: Eric Milles <[email protected]>
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 f0cdc32950..131a4c6cfa 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1664,11 +1664,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)))
@@ -1681,8 +1683,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);
@@ -1828,6 +1830,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)
@@ -2714,7 +2722,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