Skip to content

Commit 9819280

Browse files
committed
GROOVY-8283: SC: field hides getter of super class
1 parent a69e055 commit 9819280

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555

5656
import static org.apache.groovy.ast.tools.ClassNodeUtils.getField;
5757
import static org.apache.groovy.ast.tools.ClassNodeUtils.getMethod;
58+
import static org.apache.groovy.ast.tools.ClassNodeUtils.isSubtype;
5859
import static org.apache.groovy.ast.tools.ExpressionUtils.isThisExpression;
5960
import static org.apache.groovy.util.BeanUtils.capitalize;
6061
import static org.codehaus.groovy.ast.ClassHelper.CLASS_Type;
@@ -454,6 +455,12 @@ private boolean makeGetPropertyWithGetter(final Expression receiver, final Class
454455
if (!AsmClassGenerator.isMemberDirectlyAccessible(getterNode.getModifiers(), getterNode.getDeclaringClass(), controller.getClassNode())) {
455456
return false; // GROOVY-6277
456457
}
458+
FieldNode fieldNode = getField(receiverType, propertyName);
459+
if (fieldNode != null && !getterNode.getDeclaringClass().equals(fieldNode.getDeclaringClass())
460+
&& isSubtype(getterNode.getDeclaringClass(), fieldNode.getDeclaringClass()) // field found before getter (starting from receiver type)
461+
&& AsmClassGenerator.isMemberDirectlyAccessible(fieldNode.getModifiers(), fieldNode.getDeclaringClass(), controller.getClassNode())) {
462+
return false; // GROOVY-8283
463+
}
457464
MethodCallExpression call = callX(receiver, getterName);
458465
call.setImplicitThis(implicitThis);
459466
call.setMethodTarget(getterNode);

src/test/groovy/bugs/Groovy8283.groovy

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ final class Groovy8283 {
3535
A getFoo() { return foo }
3636
}
3737
class D extends C {
38-
protected B foo = new B() // hides A#foo; should hide A#getFoo in subclasses
38+
protected B foo = new B()
3939
}
4040
'''
4141
assertScript shell, '''import p.*
@@ -56,6 +56,22 @@ final class Groovy8283 {
5656
new E().test()
5757
assert new E().foo.class == A // not the field from this perspective
5858
'''
59+
}
60+
61+
@Test
62+
void testReadFieldPropertyShadowing2() {
63+
def shell = new GroovyShell()
64+
shell.parse '''package p
65+
class A {}
66+
class B {}
67+
class C {
68+
protected A foo = new A()
69+
A getFoo() { return foo }
70+
}
71+
class D extends C {
72+
protected B foo = new B()
73+
}
74+
'''
5975
assertScript shell, '''import p.*
6076
class E extends D {
6177
@groovy.transform.ASTTest(phase=org.codehaus.groovy.control.CompilePhase.INSTRUCTION_SELECTION, value={
@@ -102,6 +118,42 @@ final class Groovy8283 {
102118
'''
103119
}
104120

121+
@Test
122+
void testReadFieldPropertyShadowing3() {
123+
def shell = GroovyShell.withConfig {
124+
ast(groovy.transform.CompileStatic)
125+
}
126+
shell.parse '''package p
127+
class A {}
128+
class B {}
129+
class C {
130+
protected A foo = new A()
131+
A getFoo() { return foo }
132+
}
133+
class D extends C {
134+
protected B foo = new B()
135+
}
136+
'''
137+
assertScript shell, '''import p.*
138+
class E extends D {
139+
void test() {
140+
assert foo.class == B
141+
assert this.foo.class == B
142+
assert [email protected] == B
143+
assert this.getFoo().getClass() == A
144+
145+
def that = new E()
146+
assert that.foo.class == B
147+
assert [email protected] == B
148+
assert that.getFoo().getClass() == A
149+
}
150+
}
151+
152+
new E().test()
153+
assert new E().foo.class == A // not the field from this perspective
154+
'''
155+
}
156+
105157
@Test
106158
void testWriteFieldPropertyShadowing() {
107159
def shell = new GroovyShell()

0 commit comments

Comments
 (0)