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 2021/06/02 21:33:39 UTC

[groovy] branch master updated: GROOVY-10122: stubgen: find type of helper method in special ctor call

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 9a4df4d  GROOVY-10122: stubgen: find type of helper method in special ctor call
9a4df4d is described below

commit 9a4df4dd29723e4073e59832c23d0308710039b0
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jun 2 16:03:59 2021 -0500

    GROOVY-10122: stubgen: find type of helper method in special ctor call
---
 .../groovy/tools/javac/JavaStubGenerator.java      | 78 +++++++++-------------
 .../groovy/tools/stubgenerator/Groovy10122.groovy  | 53 +++++++++++++++
 2 files changed, 83 insertions(+), 48 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
index 1a41e7b..543c011 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.tools.javac;
 
+import org.apache.groovy.ast.tools.ExpressionUtils;
 import org.apache.groovy.io.StringBuilderWriter;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
@@ -40,6 +41,7 @@ import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
@@ -88,6 +90,7 @@ import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveFloat;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveInt;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveLong;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveShort;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
 import static org.codehaus.groovy.ast.ClassHelper.isStringType;
 
@@ -120,8 +123,6 @@ public class JavaStubGenerator {
         dir.mkdirs();
     }
 
-
-    private static final int DEFAULT_BUFFER_SIZE = 8 * 1024; // 8K
     public void generateClass(ClassNode classNode) throws FileNotFoundException {
         // Only attempt to render our self if our super-class is resolved, else wait for it
         if (requireSuperResolved && !classNode.getSuperClass().isResolved()) {
@@ -165,6 +166,8 @@ public class JavaStubGenerator {
         javaStubCompilationUnitSet.add(new RawJavaFileObject(createJavaStubFile(fileName).toPath().toUri()));
     }
 
+    private static final int DEFAULT_BUFFER_SIZE = 8 * 1024; // 8K
+
     private String generateStubContent(ClassNode classNode) {
         Writer writer = new StringBuilderWriter(DEFAULT_BUFFER_SIZE);
 
@@ -450,16 +453,7 @@ public class JavaStubGenerator {
     }
 
     private static boolean sameParameterTypes(final Parameter[] firstParams, final Parameter[] secondParams) {
-        boolean sameParams = firstParams.length == secondParams.length;
-        if (sameParams) {
-            for (int i = 0; i < firstParams.length; i++) {
-                if (!firstParams[i].getType().equals(secondParams[i].getType())) {
-                    sameParams = false;
-                    break;
-                }
-            }
-        }
-        return sameParams;
+        return org.codehaus.groovy.ast.tools.ParameterUtils.parametersEqual(firstParams, secondParams);
     }
 
     private void printConstructors(PrintWriter out, ClassNode classNode) {
@@ -642,73 +636,64 @@ public class JavaStubGenerator {
         return true;
     }
 
-    private void printSpecialConstructorArgs(PrintWriter out, ConstructorNode node, ConstructorCallExpression constrCall) {
+    private void printSpecialConstructorArgs(final PrintWriter out, final ConstructorNode ctor, final ConstructorCallExpression ctorCall) {
         // Select a constructor from our class, or super-class which is legal to call,
         // then write out an invoke w/nulls using casts to avoid ambiguous calls
-
-        Parameter[] params = selectAccessibleConstructorFromSuper(node);
+        Parameter[] params = selectAccessibleConstructorFromSuper(ctor);
         if (params != null) {
             out.print("super (");
-
             for (int i = 0, n = params.length; i < n; i += 1) {
                 printDefaultValue(out, params[i].getType());
                 if (i + 1 < n) {
                     out.print(", ");
                 }
             }
-
             out.println(");");
             return;
         }
 
         // Otherwise try the older method based on the constructor's call expression
-        Expression arguments = constrCall.getArguments();
-
-        if (constrCall.isSuperCall()) {
+        Expression arguments = ctorCall.getArguments();
+        if (ctorCall.isSuperCall()) {
             out.print("super(");
         } else {
             out.print("this(");
         }
-
-        // Else try to render some arguments
         if (arguments instanceof ArgumentListExpression) {
-            ArgumentListExpression argumentListExpression = (ArgumentListExpression) arguments;
-            List<Expression> args = argumentListExpression.getExpressions();
-
+            List<Expression> args = ((ArgumentListExpression) arguments).getExpressions();
+            int i = 0, n = args.size();
             for (Expression arg : args) {
                 if (arg instanceof ConstantExpression) {
-                    ConstantExpression expression = (ConstantExpression) arg;
-                    Object o = expression.getValue();
-
-                    if (o instanceof String) {
+                    Object value = ((ConstantExpression) arg).getValue();
+                    if (value instanceof String) {
                         out.print("(String)null");
                     } else {
-                        out.print(expression.getText());
+                        out.print(arg.getText());
                     }
                 } else {
-                    ClassNode type = getConstructorArgumentType(arg, node);
-                    printDefaultValue(out, type);
+                    printDefaultValue(out, getConstructorArgumentType(arg, ctor));
                 }
-
-                if (arg != args.get(args.size() - 1)) {
+                if (++i < n) {
                     out.print(", ");
                 }
             }
         }
-
         out.println(");");
     }
 
-    private static ClassNode getConstructorArgumentType(Expression arg, ConstructorNode node) {
-        if (!(arg instanceof VariableExpression)) return arg.getType();
-        VariableExpression vexp = (VariableExpression) arg;
-        String name = vexp.getName();
-        for (Parameter param : node.getParameters()) {
-            if (param.getName().equals(name)) {
-                return param.getType();
+    private static ClassNode getConstructorArgumentType(final Expression arg, final ConstructorNode ctor) {
+        if (arg instanceof VariableExpression) {
+            return ((VariableExpression) arg).getAccessedVariable().getType();
+        }
+        if (arg instanceof MethodCallExpression) { // GROOVY-10122
+            MethodCallExpression mce = (MethodCallExpression) arg;
+            if (ExpressionUtils.isThisExpression(mce.getObjectExpression())) {
+                MethodNode mn = ctor.getDeclaringClass().tryFindPossibleMethod(mce.getMethodAsString(), mce.getArguments());
+                if (mn != null) return mn.getReturnType();
             }
+            return null;
         }
-        return vexp.getType();
+        return arg.getType();
     }
 
     private void printMethod(PrintWriter out, ClassNode clazz, MethodNode methodNode) {
@@ -837,13 +822,12 @@ public class JavaStubGenerator {
     }
 
     private void printDefaultValue(final PrintWriter out, final ClassNode type) {
-        if (!isPrimitiveBoolean(type)) {
+        if (type != null && !isPrimitiveBoolean(type)) {
             out.print("(");
             printType(out, type);
             out.print(")");
         }
-
-        if (ClassHelper.isPrimitiveType(type)) {
+        if (type != null && isPrimitiveType(type)) {
             if (isPrimitiveBoolean(type)) {
                 out.print("false");
             } else {
@@ -1077,14 +1061,12 @@ public class JavaStubGenerator {
 
     private static String escapeSpecialChars(String value) {
         return InvokerHelper.escapeBackslashes(value).replace("\"", "\\\"");
-
     }
 
     private static boolean isInterfaceOrTrait(ClassNode cn) {
         return cn.isInterface() || Traits.isTrait(cn);
     }
 
-
     private final Set<JavaFileObject> javaStubCompilationUnitSet = new HashSet<>();
 
     public Set<JavaFileObject> getJavaStubCompilationUnitSet() {
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10122.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10122.groovy
new file mode 100644
index 0000000..0ba0ba4
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10122.groovy
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.tools.stubgenerator
+
+final class Groovy10122 extends StringSourcesStubTestCase {
+
+    @Override
+    Map<String, String> provideSources() {
+        [
+            'A.java': '''
+                public abstract class A {
+                    A(Integer i) {
+                    }
+                }
+            ''',
+            'C.groovy': '''
+                class C extends A {
+                    C() { super(m()) }
+                    static Integer m() { 42 }
+                }
+            ''',
+            'Main.java': '''
+                public class Main {
+                    public static void main(String[] args) {
+                        new C();
+                    }
+                }
+            ''',
+        ]
+    }
+
+    @Override
+    void verifyStubs() {
+        def specialCtorCall = (stubJavaSourceFor('C') =~ /super\s*\((.+?)\);/)
+        assert specialCtorCall.find() && specialCtorCall.group(1) == '(java.lang.Integer)null'
+    }
+}