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
The following commit(s) were added to refs/heads/master by this push:
new ef4c711ef7 GROOVY-11367, GROOVY-11387: STC: entry or field for
property of map type
ef4c711ef7 is described below
commit ef4c711ef75858b5965bd3a8f65126e97fd1a967
Author: Eric Milles <[email protected]>
AuthorDate: Wed May 29 08:29:26 2024 -0500
GROOVY-11367, GROOVY-11387: STC: entry or field for property of map type
---
.../groovy/classgen/AsmClassGenerator.java | 15 +++++----------
.../classgen/asm/sc/StaticTypesCallSiteWriter.java | 19 +++++++++++++++----
.../transform/stc/StaticTypeCheckingVisitor.java | 20 ++++++++++++--------
.../stc/FieldsAndPropertiesSTCTest.groovy | 22 ++++++++++++++++++++++
4 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 7f09adaa6a..60dfc25210 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -1144,17 +1144,12 @@ public class AsmClassGenerator extends ClassGenerator {
return;
}
- if (propertyName != null) {
- // TODO: spread safe should be handled inside
- if (adapter == getProperty && !pexp.isSpreadSafe()) {
-
controller.getCallSiteWriter().makeGetPropertySite(objectExpression,
propertyName, pexp.isSafe(), pexp.isImplicitThis());
- } else if (adapter == getGroovyObjectProperty &&
!pexp.isSpreadSafe()) {
-
controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression,
propertyName, pexp.isSafe(), pexp.isImplicitThis());
- } else {
-
controller.getCallSiteWriter().fallbackAttributeOrPropertySite(pexp,
objectExpression, propertyName, adapter);
- }
+ if (adapter == getGroovyObjectProperty && propertyName != null &&
!pexp.isSpreadSafe()) { // TODO: spread safe should be handled by each
+
controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression,
propertyName, pexp.isSafe(), pexp.isImplicitThis());
+ } else if (adapter == getProperty && propertyName != null &&
!pexp.isSpreadSafe()) {
+
controller.getCallSiteWriter().makeGetPropertySite(objectExpression,
propertyName, pexp.isSafe(), pexp.isImplicitThis());
} else {
-
controller.getCallSiteWriter().fallbackAttributeOrPropertySite(pexp,
objectExpression, null, adapter);
+
controller.getCallSiteWriter().fallbackAttributeOrPropertySite(pexp,
objectExpression, propertyName, adapter);
}
}
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index d7c9d55716..3b674b03a9 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -408,13 +408,24 @@ public class StaticTypesCallSiteWriter extends
CallSiteWriter {
}
if (makeGetPropertyWithGetter(receiver, receiverType, propertyName,
safe, implicitThis)) return;
- if (makeGetField(receiver, receiverType, propertyName, safe,
implicitThis)) return;
- if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType,
propertyName, safe, implicitThis)) return;
boolean isStaticProperty = (receiver instanceof ClassExpression
&& (receiverType.isDerivedFrom(receiver.getType()) ||
receiverType.implementsInterface(receiver.getType())));
- // GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-6144, GROOVY-8788:
for maps, replace "map.foo" with "map.get('foo')"
- if (!isStaticProperty && isOrImplements(receiverType, MAP_TYPE)) {
+ boolean isMapDotProperty = !isStaticProperty &&
isOrImplements(receiverType, MAP_TYPE);
+
+ // GROOVY-5001, GROOVY-5491, GROOVY-5517, GROOVY-6144, GROOVY-8788:
for map types,
+ // replace "map.foo" with "map.get('foo')" -- if no public field "foo"
is declared
+ if (isMapDotProperty
+ && (!isThisExpression(receiver) || (implicitThis &&
controller.isInGeneratedFunction())) // GROOVY-8978
+ && Optional.ofNullable( getField(receiverType, propertyName)
).filter(FieldNode::isPublic).isEmpty()) {
+ writeMapDotProperty(receiver, propertyName, safe);
+ return;
+ }
+
+ if (makeGetField(receiver, receiverType, propertyName, safe,
implicitThis)) return;
+ if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType,
propertyName, safe, implicitThis)) return;
+
+ if (isMapDotProperty) {
writeMapDotProperty(receiver, propertyName, safe);
return;
}
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 2f07ba450d..3bdec7150f 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1656,11 +1656,14 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
continue;
}
- // skip property/accessor checks for "field", "this.field",
"this.with { field }", etc. in declaring class of field
- if (field != null && enclosingTypes.contains(current)) {
- if (storeField(field, pexp, receiverType, visitor,
receiver.getData(), !readMode)) {
- return true;
- }
+ if (field != null && !(field.isPublic() ||
(field.isProtected() && !readMode)) // GROOVY-11387: map entry before
non-public field
+ && !(isThisExpression(objectExpression) &&
(!pexp.isImplicitThis() || typeCheckingContext.getEnclosingClosure() == null))
+ && isOrImplements(receiverType, MAP_TYPE)) {
+ field = null;
+ }
+ // skip property/accessor checks for "field", "this.field",
"this.with { field }", etc. within the declaring class of the field
+ else if (field != null && enclosingTypes.contains(current) &&
storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
+ return true;
}
MethodNode getter = current.getGetterMethod(isserName);
@@ -1882,6 +1885,8 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
};
if (!pexp.isSpreadSafe()) {
+ if (pexp.isImplicitThis() &&
isThisExpression(pexp.getObjectExpression()))
+ pexp.putNodeMetaData(DYNAMIC_RESOLUTION,Boolean.TRUE); //
GROOVY-11387
return getCombinedBoundType(gts[1]);
} else {
// map*.property syntax acts on Entry
@@ -1946,12 +1951,9 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
}
private boolean storeField(final FieldNode field, final PropertyExpression
expressionToStoreOn, final ClassNode receiver, final ClassCodeVisitorSupport
visitor, final String delegationData, final boolean lhsOfAssignment) {
- if (visitor != null) visitor.visitField(field);
- checkOrMarkPrivateAccess(expressionToStoreOn, field, lhsOfAssignment);
boolean superField =
isSuperExpression(expressionToStoreOn.getObjectExpression());
boolean accessible = (!superField &&
receiver.equals(field.getDeclaringClass()) &&
!field.getDeclaringClass().isAbstract()) // GROOVY-7300, GROOVY-11358
||
hasAccessToMember(typeCheckingContext.getEnclosingClassNode(),
field.getDeclaringClass(), field.getModifiers());
-
if (!accessible) {
if (expressionToStoreOn instanceof AttributeExpression) {
addStaticTypeError("Cannot access field: " + field.getName() +
" of class: " + prettyPrintTypeName(field.getDeclaringClass()),
expressionToStoreOn.getProperty());
@@ -1960,6 +1962,8 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
}
}
+ if (visitor != null) visitor.visitField(field);
+ checkOrMarkPrivateAccess(expressionToStoreOn, field, lhsOfAssignment);
storeWithResolve(field.getOriginType(), receiver,
field.getDeclaringClass(), field.isStatic(), expressionToStoreOn);
if (delegationData != null) {
expressionToStoreOn.putNodeMetaData(IMPLICIT_RECEIVER,
delegationData);
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index c4071cea98..0c0481db34 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -822,6 +822,28 @@ class FieldsAndPropertiesSTCTest extends
StaticTypeCheckingTestCase {
"""
}
+ // GROOVY-11387
+ void testMapPropertyAccess11() {
+ assertScript '''
+ def map = new HashMap<String,String>()
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+ })
+ def xxx = map.table
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+ })
+ def yyy = map.with{
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+ })
+ def zzz = table
+ }
+ assert xxx == null
+ assert yyy == null
+ '''
+ }
+
void testTypeCheckerDoesNotThinkPropertyIsReadOnly() {
assertScript '''
// a base class defining a read-only property