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')
         '''
     }