Skip to content

Commit

Permalink
GROOVY-11369: map entry comes before access method (pt.2)
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed May 14, 2024
1 parent ff4857e commit e999d51
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
import static org.codehaus.groovy.syntax.Types.MOD;
import static org.codehaus.groovy.syntax.Types.MOD_EQUAL;
import static org.codehaus.groovy.syntax.Types.PLUS_PLUS;
import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.COMPILESTATIC_CLASSNODE;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.ArrayList_TYPE;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.Collection_TYPE;
import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.LinkedHashMap_TYPE;
Expand Down Expand Up @@ -1567,16 +1568,17 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
}
}

MethodNode getter = findGetter(current, getterName, pexp.isImplicitThis());
getter = allowStaticAccessToMember(getter, staticOnly);
if (getter == null) getter = findGetter(current, isserName, pexp.isImplicitThis());
getter = allowStaticAccessToMember(getter, staticOnly);
if (getter != null && !isThisExpression(objectExpression) && !isSuperExpression(objectExpression) && isOrImplements(objectExpressionType, MAP_TYPE)) {
getter = null; // GROOVY-11369: map entry comes before access method
MethodNode getter = null;
if (!isMapProperty(pexp)) { // GROOVY-11369: map entry before getter
getter = findGetter(current, getterName, pexp.isImplicitThis());
getter = allowStaticAccessToMember(getter, staticOnly);
if (getter == null) {
getter = findGetter(current, isserName, pexp.isImplicitThis());
getter = allowStaticAccessToMember(getter, staticOnly);
}
if (readMode && getter != null && visitor != null) visitor.visitMethod(getter);
}

if (readMode && getter != null && visitor != null) visitor.visitMethod(getter);

PropertyNode property = current.getProperty(propertyName);
property = allowStaticAccessToMember(property, staticOnly);
// prefer explicit getter or setter over property if receiver is not 'this'
Expand Down Expand Up @@ -1787,6 +1789,15 @@ private ClassNode getTypeForMapPropertyExpression(final ClassNode testClass, fin
return null;
}

private boolean isMapProperty(final PropertyExpression pexp) {
final Expression objectExpression = pexp.getObjectExpression();
if ((isThisExpression(objectExpression) || isSuperExpression(objectExpression))
&& Arrays.asList(getTypeCheckingAnnotations()).contains(COMPILESTATIC_CLASSNODE)) {
return false;
}
return isOrImplements(getType(objectExpression), MAP_TYPE);
}

/**
* Filters search result to prevent access to instance members from a static
* context.
Expand Down
20 changes: 20 additions & 0 deletions src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,26 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'''
}

// GROOVY-11369
void testMapPropertyAccess5a() {
for (mod in ['def', 'public', 'protected', '@groovy.transform.PackageScope', 'private']) {
assertScript """
class C implements Map<String,String> {
@Delegate Map<String,String> impl = [:].withDefault{'entry'}
$mod getFoo() { 'getter' }
void test() {
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
})
def which = this.foo
assert which == 'entry'
}
}
new C().test()
"""
}
}

// GROOVY-8074
void testMapPropertyAccess6() {
assertScript '''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -827,4 +827,25 @@ final class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCT
void testPublicFieldVersusPrivateGetter() {
super.testPublicFieldVersusPrivateGetter()
}

// GROOVY-11369
@Override
void testMapPropertyAccess5a() {
for (mod in ['def', 'public', 'protected', '@groovy.transform.PackageScope', 'private']) {
assertScript """
class C implements Map<String,String> {
@Delegate Map<String,String> impl = [:].withDefault{'entry'}
$mod getFoo() { 'getter' }
void test() {
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == OBJECT_TYPE
})
def which = this.foo
assert which == 'getter'
}
}
new C().test()
"""
}
}
}

0 comments on commit e999d51

Please sign in to comment.