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 ba984b19e5 GROOVY-11387: STC: class field or property of map-based type
ba984b19e5 is described below
commit ba984b19e5dc5d7ddf6aae6e15f1be8e259b1781
Author: Eric Milles <[email protected]>
AuthorDate: Thu May 30 15:39:40 2024 -0500
GROOVY-11387: STC: class field or property of map-based type
---
.../transform/stc/StaticTypeCheckingVisitor.java | 42 +++++++++++-----------
.../stc/FieldsAndPropertiesSTCTest.groovy | 10 ++++++
2 files changed, 32 insertions(+), 20 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 3bdec7150f..2e637cf1d5 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1656,7 +1656,7 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
continue;
}
- if (field != null && !(field.isPublic() ||
(field.isProtected() && !readMode)) // GROOVY-11387: map entry before
non-public field
+ if (field != null && !staticOnly && !(field.isPublic() ||
(field.isProtected() && !readMode)) // GROOVY-11387: entry before field
&& !(isThisExpression(objectExpression) &&
(!pexp.isImplicitThis() || typeCheckingContext.getEnclosingClosure() == null))
&& isOrImplements(receiverType, MAP_TYPE)) {
field = null;
@@ -1677,6 +1677,7 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
&&
(!hasAccessToMember(typeCheckingContext.getEnclosingClassNode(),
getter.getDeclaringClass(), getter.getModifiers())
// GROOVY-11369:
|| (isOrImplements(receiverType, MAP_TYPE)
+ && !staticOnly // GROOVY-10387: Map.foo
&& !isSuperExpression(objectExpression)
&& !(isThisExpression(objectExpression) &&
(!pexp.isImplicitThis() || typeCheckingContext.getEnclosingClosure() == null))
// GROOVY-11384
&& (!getter.isPublic() ||
(propertyName.matches("empty|class|metaClass") &&
!List.of(getTypeCheckingAnnotations()).contains(COMPILESTATIC_CLASSNODE)))))) {
@@ -1791,25 +1792,26 @@ out: if ((samParameterTypes.length == 1 &&
isOrImplements(samParameterTypes[0
}
}
- for (Receiver<String> receiver : receivers) {
- ClassNode receiverType = receiver.getType();
- ClassNode propertyType =
getTypeForMapPropertyExpression(receiverType, pexp);
- if (propertyType == null)
- propertyType = getTypeForListPropertyExpression(receiverType,
pexp);
- if (propertyType == null)
- propertyType = getTypeForSpreadExpression(receiverType, pexp);
- if (propertyType == null)
- continue;
- if (visitor != null) {
- // TODO: type inference on maps and lists, if possible
- PropertyNode node = new PropertyNode(propertyName,
Opcodes.ACC_PUBLIC, propertyType, receiver.getType(), null, null, null);
- node.setDeclaringClass(receiver.getType());
- visitor.visitProperty(node);
- }
- storeType(pexp, propertyType);
- String delegationData = receiver.getData();
- if (delegationData != null)
pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
- return true;
+ if (pexp.isImplicitThis() || !staticOnlyAccess) {
+ for (Receiver<String> receiver : receivers) {
+ ClassNode receiverType = receiver.getType();
+ ClassNode propertyType =
getTypeForMapPropertyExpression(receiverType, pexp);
+ if (propertyType == null)
+ propertyType =
getTypeForListPropertyExpression(receiverType, pexp);
+ if (propertyType == null)
+ propertyType = getTypeForSpreadExpression(receiverType,
pexp);
+ if (propertyType == null)
+ continue;
+ if (visitor != null) {
+ PropertyNode node = new PropertyNode(propertyName,
Opcodes.ACC_PUBLIC, propertyType, receiverType, null, null, null);
+ node.setDeclaringClass(receiverType);
+ visitor.visitProperty(node);
+ }
+ storeType(pexp, propertyType);
+ String delegationData = receiver.getData();
+ if (delegationData != null)
pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
+ return true;
+ }
}
if (pexp.isImplicitThis() && isThisExpression(objectExpression)) {
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 0c0481db34..71f244e7b1 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -842,6 +842,16 @@ class FieldsAndPropertiesSTCTest extends
StaticTypeCheckingTestCase {
assert xxx == null
assert yyy == null
'''
+ assertScript '''
+ class HttpHeaders extends HashMap<String,List<String>> {
+ protected static final String ACCEPT = 'Accept'
+ }
+ @ASTTest(phase=INSTRUCTION_SELECTION, value={
+ assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
+ })
+ def accept = HttpHeaders.ACCEPT
+ assert accept == 'Accept'
+ '''
}
void testTypeCheckerDoesNotThinkPropertyIsReadOnly() {