You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2024/05/10 14:49:10 UTC
(groovy) branch GROOVY_4_0_X updated: GROOVY-11372: STC: write property via extension method
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new 753c34a10d GROOVY-11372: STC: write property via extension method
753c34a10d is described below
commit 753c34a10d2daa41c5a6c0c9425e82da8ada7054
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri May 10 09:07:53 2024 -0500
GROOVY-11372: STC: write property via extension method
4_0_X backport
---
.../transform/stc/StaticTypeCheckingVisitor.java | 32 ++++++++++++++--------
.../stc/FieldsAndPropertiesSTCTest.groovy | 16 +++++++++--
2 files changed, 34 insertions(+), 14 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 492034f774..9a6eb6b26f 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1530,6 +1530,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
return true;
}
+ // in case of a lookup on java.lang.Class, look for instance methods on Class
+ // as well; in case of static property access Class<Type> and Type are listed
+ boolean staticOnly = isClassClassNodeWrappingConcreteType(receiverType) ? false
+ : (receiver.getData() == null ? staticOnlyAccess : false);
+
+ List<MethodNode> setters = findSetters(wrapTypeIfNecessary(receiverType), setterName, /*voidOnly:*/false);
+ setters = allowStaticAccessToMember(setters, staticOnly);
+ // GROOVY-11319:
+ setters.removeIf(setter -> !hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), setter.getDeclaringClass(), setter.getModifiers()));
+ // GROOVY-11372:
+ ClassLoader loader = getSourceUnit().getClassLoader();
+ Set<MethodNode> dgmSet = findDGMMethodsForClassNode(loader, receiverType, setterName);
+ if (isPrimitiveType(receiverType)) findDGMMethodsForClassNode(loader, getWrapper(receiverType), setterName, (java.util.TreeSet<MethodNode>) dgmSet);
+ for (MethodNode method : dgmSet) {
+ if ((!staticOnly || method.isStatic()) && method.getParameters().length == 1) {
+ setters.add(method);
+ }
+ }
+
LinkedList<ClassNode> queue = new LinkedList<>();
queue.add(receiverType);
if (isPrimitiveType(receiverType)) {
@@ -1546,11 +1565,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
Collections.addAll(queue, current.getInterfaces());
}
- boolean staticOnly = (receiver.getData() == null ? staticOnlyAccess : false);
- // in case of a lookup on java.lang.Class, look for instance methods on Class
- // as well; in case of static property access Class<Type> and Type are listed
- if (isClassClassNodeWrappingConcreteType(current)) staticOnly = false;
-
field = allowStaticAccessToMember(field, staticOnly);
// skip property/accessor checks for "x.@field"
@@ -1579,10 +1593,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
|| (!isThisExpression(objectExpression) && !isSuperExpression(objectExpression) && isOrImplements(objectExpressionType, MAP_TYPE)))) {
getter = null;
}
- List<MethodNode> setters = findSetters(current, setterName, /*enforce void:*/false);
- setters = allowStaticAccessToMember(setters, staticOnly);
- // GROOVY-11319:
- setters.removeIf(setter -> !hasAccessToMember(typeCheckingContext.getEnclosingClassNode(), setter.getDeclaringClass(), setter.getModifiers()));
if (readMode && getter != null && visitor != null) visitor.visitMethod(getter);
@@ -1635,7 +1645,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
foundGetterOrSetter = (foundGetterOrSetter || getter != null || !setters.isEmpty());
}
- if (!readMode || isThisExpression(objectExpression) || isSuperExpression(objectExpression) || !isOrImplements(objectExpressionType, MAP_TYPE)) { // GROOVY-11370
+ if (readMode && (isThisExpression(objectExpression) || isSuperExpression(objectExpression) || !isOrImplements(objectExpressionType, MAP_TYPE))) { // GROOVY-11370, GROOVY-11372
// GROOVY-5568, GROOVY-9115, GROOVY-9123: the property may be defined by an extension
for (ClassNode dgmReceiver : isPrimitiveType(receiverType) ? new ClassNode[]{receiverType, getWrapper(receiverType)} : new ClassNode[]{receiverType}) {
Set<MethodNode> methods = findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), dgmReceiver, getterName);
@@ -1660,7 +1670,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
ClassNode returnType = inferReturnTypeGenerics(dgmReceiver, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, returnType);
- if (readMode) storeTargetMethod(pexp, getter);
+ storeTargetMethod(pexp, getter);
return true;
}
}
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 75eab43812..a9ee27e763 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -460,7 +460,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
}
// GROOVY-5232
- void testSetterForProperty() {
+ void testSetterForProperty1() {
assertScript '''
class Person {
String name
@@ -475,6 +475,16 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-11372
+ void testSetterForProperty2() {
+ assertScript '''
+ def baos = new ByteArrayOutputStream()
+ assert baos.size() == 0
+ baos.bytes= new byte[1]
+ assert baos.size() == 1
+ '''
+ }
+
// GROOVY-5443
void testFieldInitShouldPass() {
assertScript '''
@@ -690,13 +700,13 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
map.entry = null
map.empty = null // not read-only property
map.class = null // not read-only property
- map.metaClass = null // TODO: 6549 SC is "put"
+ map.metaClass = null
map.properties = null
assert map.containsKey('entry')
assert map.containsKey('empty')
assert map.containsKey('class')
- //assert !map.containsKey('metaClass')
+ assert !map.containsKey('metaClass')
assert map.containsKey('properties')
'''
}