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 2023/02/02 17:23:59 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-10922: STC: forthcoming generated property method stub

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new d40b7b9ac6 GROOVY-10922: STC: forthcoming generated property method stub
d40b7b9ac6 is described below

commit d40b7b9ac62b4520b30b42ef89e43aca80cbefc5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Feb 2 10:11:46 2023 -0600

    GROOVY-10922: STC: forthcoming generated property method stub
    
    2_5_X backport
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 37 ++++++++++++++--------
 .../groovy/transform/stc/MethodCallsSTCTest.groovy | 26 +++++++++++++++
 2 files changed, 49 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 e560554a7a..f537530389 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4756,7 +4756,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return methods;
     }
 
-    private static List<MethodNode> addGeneratedMethods(final ClassNode receiver, final List<MethodNode> methods) {
+    private static List<MethodNode> addGeneratedMethods(final ClassNode receiver, final List<? extends MethodNode> methods) {
         // using a comparator of parameters
         List<MethodNode> result = new LinkedList<MethodNode>();
         for (MethodNode method : methods) {
@@ -4812,12 +4812,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return result;
     }
 
+    private static boolean allAbstract(final List<? extends MethodNode> methods) {
+        for (MethodNode method : methods) {
+            if (!method.isAbstract()) return false;
+        }
+        return true;
+    }
+
     protected List<MethodNode> findMethod(ClassNode receiver, final String name, final ClassNode... args) {
         if (isPrimitiveType(receiver)) receiver = getWrapper(receiver);
 
         List<MethodNode> methods;
         if ("<init>".equals(name) && !receiver.isInterface()) {
-            methods = addGeneratedMethods(receiver, new ArrayList<MethodNode>(receiver.getDeclaredConstructors()));
+            methods = addGeneratedMethods(receiver, receiver.getDeclaredConstructors());
             if (methods.isEmpty()) {
                 MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                 node.setDeclaringClass(receiver);
@@ -4841,33 +4848,35 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             if (methods.isEmpty()) {
                 addArrayMethods(methods, receiver, name, args);
             }
-            if (methods.isEmpty() && (args == null || args.length == 0)) {
-                // check if it's a property
+            if (args == null || args.length == 0) {
+                // check for property accessor
                 String pname = extractPropertyNameFromMethodName("get", name);
                 if (pname == null) {
                     pname = extractPropertyNameFromMethodName("is", name);
                 }
                 if (pname != null) {
                     PropertyNode property = findProperty(receiver, pname);
-                    if (property != null) {
-                        int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
-                        MethodNode node = new MethodNode(name, mods, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
+                    if (property != null && property.getDeclaringClass().getGetterMethod(name) == null) {
+                        MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0),
+                                property.getOriginType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                         node.setDeclaringClass(property.getDeclaringClass());
-                        return Collections.singletonList(node);
+                        node.setSynthetic(true);
+                        methods.add(node);
                     }
                 }
-            } else if (methods.isEmpty() && args != null && args.length == 1) {
-                // maybe we are looking for a setter ?
+            } else if (args.length == 1 && (methods.isEmpty() || allAbstract(methods))) { // GROOVY-10922
+                // check for property mutator
                 String pname = extractPropertyNameFromMethodName("set", name);
                 if (pname != null) {
                     PropertyNode property = findProperty(receiver, pname);
                     if (property != null && !Modifier.isFinal(property.getModifiers())) {
                         ClassNode type = property.getOriginType();
                         if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) {
-                            int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
-                            MethodNode node = new MethodNode(name, mods, VOID_TYPE, new Parameter[]{new Parameter(type, name)}, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
+                            MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0),
+                                    VOID_TYPE, new Parameter[]{new Parameter(type, name)}, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
                             node.setDeclaringClass(property.getDeclaringClass());
-                            return Collections.singletonList(node);
+                            node.setSynthetic(true);
+                            methods.add(node);
                         }
                     }
                 }
@@ -5518,7 +5527,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             params = ((ExtensionMethodNode) target).getExtensionMethodNode().getParameters();
         } else if (!target.isStatic() && source.getExpression() instanceof ClassExpression) {
             ClassNode thisType = ((ClassExpression) source.getExpression()).getType();
-            // there is an implicit parameter for "String::length"
+            // there is an implicit parameter for "String.&length"
             int n = target.getParameters().length;
             params = new Parameter[n + 1];
             params[0] = new Parameter(thisType, "");
diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
index 735fac4908..de4e7ef0ed 100644
--- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy
@@ -201,6 +201,32 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase {
         ''', 'Cannot call groovy.transform.stc.MethodCallsSTCTest$MyMethodCallTestClass2 <Integer>#identity(java.lang.Integer[]) with arguments [java.lang.String[]]'
     }
 
+    // GROOVY-10922
+    void testCallToSuperGenerated() {
+        assertScript '''
+            interface Foo {
+                String getString()
+                void setString(String s)
+            }
+            class Bar implements Foo {
+                String string
+            }
+            class Baz extends Bar {
+                String object
+                @Override
+                void setString(String string) {
+                    super.setString(string)
+                    object = string
+                }
+            }
+;
+            def obj = new Baz()
+            obj.setString('xx')
+            assert obj.object == 'xx'
+            assert obj.string == 'xx'
+        '''
+    }
+
     void testMethodCallFromSuperOwner() {
         assertScript '''
             class Child extends groovy.transform.stc.MethodCallsSTCTest.GroovyPage {