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 2022/11/19 19:58:56 UTC

[groovy] branch master updated: GROOVY-10797: stubgen: deal with class/method type parameters separately

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 39153104c3 GROOVY-10797: stubgen: deal with class/method type parameters separately
39153104c3 is described below

commit 39153104c318c0ee50ce315c7dd0ea85369ccacf
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 19 13:54:55 2022 -0600

    GROOVY-10797: stubgen: deal with class/method type parameters separately
---
 .../groovy/tools/javac/JavaStubGenerator.java      | 104 ++++++++++++---------
 .../{Groovy7306.groovy => Groovy10797.groovy}      |  29 +++---
 .../groovy/tools/stubgenerator/Groovy7306.groovy   |   2 +-
 .../groovy/tools/stubgenerator/StubTestCase.groovy |  10 +-
 .../TraitAbstractGetterStubTest.groovy             |  43 +++------
 5 files changed, 94 insertions(+), 94 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 add86edd02..a12526305e 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -78,6 +78,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static org.apache.groovy.ast.tools.ConstructorNodeUtils.getFirstIfSpecialConstructorCall;
@@ -105,7 +106,7 @@ import static org.codehaus.groovy.ast.tools.WideningCategories.isFloatingCategor
 import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 
 public class JavaStubGenerator {
-    private final boolean java5;
+
     private final String encoding;
     private final boolean requireSuperResolved;
     private final File outputPath;
@@ -118,40 +119,34 @@ public class JavaStubGenerator {
         this(outputPath, false, Charset.defaultCharset().name());
     }
 
-    public JavaStubGenerator(final File outputPath, final boolean requireSuperResolved, String encoding) {
-        this(outputPath, requireSuperResolved, true, encoding);
-    }
-
-    @Deprecated
-    public JavaStubGenerator(final File outputPath, final boolean requireSuperResolved, final boolean java5, String encoding) {
-        this.outputPath = outputPath;
+    public JavaStubGenerator(final File outputPath, final boolean requireSuperResolved, final String encoding) {
         this.requireSuperResolved = requireSuperResolved;
-        this.java5 = java5;
+        this.outputPath = outputPath;
         this.encoding = encoding;
-        if (null != outputPath) outputPath.mkdirs(); // when outputPath is null, we generate stubs in memory
+
+        // when outputPath is null, generate stubs in memory
+        if (outputPath != null) outputPath.mkdirs();
     }
 
-    private static void mkdirs(File parent, String relativeFile) {
+    private static void mkdirs(final File parent, final String relativeFile) {
         int index = relativeFile.lastIndexOf('/');
         if (index == -1) return;
         File dir = new File(parent, relativeFile.substring(0, index));
         dir.mkdirs();
     }
 
-    public void generateClass(ClassNode classNode) throws FileNotFoundException {
-        // Only attempt to render our self if our super-class is resolved, else wait for it
+    public void generateClass(final ClassNode classNode) throws FileNotFoundException {
+        // only attempt to render if super-class is resolved; else wait for it
         if (requireSuperResolved && !classNode.getSuperClass().isResolved()) {
             return;
         }
-
-        // owner should take care for us
-        if (classNode instanceof InnerClassNode)
+        // skip private class; they are not visible outside the file
+        if ((classNode.getModifiers() & Opcodes.ACC_PRIVATE) != 0) {
             return;
-
-        // don't generate stubs for private classes, as they are only visible in the same file
-        if ((classNode.getModifiers() & Opcodes.ACC_PRIVATE) != 0) return;
-
-
+        }
+        if (classNode instanceof InnerClassNode) {
+            return;
+        }
         if (outputPath == null) {
             generateMemStub(classNode);
         } else {
@@ -357,7 +352,7 @@ public class JavaStubGenerator {
             if (classNode instanceof InnerClassNode)
                 className = className.substring(className.lastIndexOf('$') + 1);
             out.println(className);
-            printGenericsBounds(out, classNode, true);
+            printTypeParameters(out, classNode.getGenericsTypes());
 
             ClassNode superClass = classNode.getUnresolvedSuperClass(false);
 
@@ -730,7 +725,7 @@ public class JavaStubGenerator {
             printModifiers(out, modifiers & ~(clazz.isEnum() ? Opcodes.ACC_ABSTRACT : 0));
         }
 
-        printGenericsBounds(out, methodNode.getGenericsTypes());
+        printTypeParameters(out, methodNode.getGenericsTypes());
         out.print(" ");
         printType(out, methodNode.getReturnType());
         out.print(" ");
@@ -871,18 +866,29 @@ public class JavaStubGenerator {
         }
     }
 
-    private void printType(PrintWriter out, ClassNode type) {
+    private void printType(final PrintWriter out, final ClassNode type) {
         if (type.isArray()) {
             printType(out, type.getComponentType());
             out.print("[]");
-        } else if (java5 && type.isGenericsPlaceHolder()) {
+        } else if (type.isGenericsPlaceHolder()) {
             out.print(type.getUnresolvedName());
         } else {
-            printGenericsBounds(out, type, false);
+            printTypeName(out, type);
+            if (!isCachedType(type)) {
+                printGenericsBounds(out, type.getGenericsTypes());
+            }
         }
     }
 
-    private void printTypeName(PrintWriter out, ClassNode type) {
+    private String getTypeName(final ClassNode type) {
+        String name = type.getName();
+        // check for an alias
+        ClassNode alias = currentModule.getImportType(name);
+        if (alias != null) name = alias.getName();
+        return name.replace('$', '.');
+    }
+
+    private void printTypeName(final PrintWriter out, final ClassNode type) {
         if (isPrimitiveType(type)) {
             if (isPrimitiveBoolean(type)) {
                 out.print("boolean");
@@ -904,32 +910,43 @@ public class JavaStubGenerator {
                 out.print("void");
             }
         } else {
-            String name = type.getName();
-            // check for an alias
-            ClassNode alias = currentModule.getImportType(name);
-            if (alias != null) name = alias.getName();
-            out.print(name.replace('$', '.'));
+            out.print(getTypeName(type));
         }
     }
 
-    private void printGenericsBounds(PrintWriter out, ClassNode type, boolean skipName) {
-        if (!skipName) printTypeName(out, type);
-        if (java5 && !isCachedType(type)) {
-            printGenericsBounds(out, type.getGenericsTypes());
+    private void printTypeParameters(final PrintWriter out, final GenericsType[] typeParams) {
+        if (typeParams == null || typeParams.length == 0) return;
+        StringJoiner sj = new StringJoiner(", ", "<", ">");
+        for (GenericsType tp : typeParams) {
+            ClassNode[] bounds = tp.getUpperBounds();
+            if (bounds == null || bounds.length == 0) {
+                sj.add(tp.getName());
+            } else {
+                sj.add(tp.getName() + " extends " + Arrays.stream(bounds).map(cn -> {
+                    GenericsType[] typeArguments = cn.getGenericsTypes();
+                    if (typeArguments == null) return getTypeName(cn);
+
+                    StringJoiner parameterized = new StringJoiner(", ", getTypeName(cn) + "<", ">");
+                    for (GenericsType ta : typeArguments) {
+                        parameterized.add(ta.toString().replace('$', '.'));
+                    }
+                    return parameterized.toString();
+                }).collect(Collectors.joining(" & ")));
+            }
         }
+        out.print(sj.toString());
     }
 
-    private static void printGenericsBounds(PrintWriter out, GenericsType[] genericsTypes) {
+    private static void printGenericsBounds(final PrintWriter out, final GenericsType[] genericsTypes) {
         if (genericsTypes == null || genericsTypes.length == 0) return;
-        out.print('<');
-        for (int i = 0; i < genericsTypes.length; i++) {
-            if (i != 0) out.print(", ");
-            out.print(genericsTypes[i].toString().replace("$","."));
+        StringJoiner sj = new StringJoiner(", ", "<", ">");
+        for (GenericsType gt : genericsTypes) {
+            sj.add(gt.toString().replace('$', '.'));
         }
-        out.print('>');
+        out.print(sj.toString());
     }
 
-    private void printParams(PrintWriter out, MethodNode methodNode) {
+    private void printParams(final PrintWriter out, final MethodNode methodNode) {
         out.print("(");
         Parameter[] parameters = methodNode.getParameters();
         if (parameters != null && parameters.length != 0) {
@@ -954,7 +971,6 @@ public class JavaStubGenerator {
     }
 
     private void printAnnotations(final PrintWriter out, final AnnotatedNode annotated) {
-        if (!java5) return;
         for (AnnotationNode annotation : annotated.getAnnotations()) {
             printAnnotation(out, annotation);
         }
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10797.groovy
similarity index 63%
copy from src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy
copy to src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10797.groovy
index fec232a30d..05b4d43df6 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10797.groovy
@@ -18,30 +18,29 @@
  */
 package org.codehaus.groovy.tools.stubgenerator
 
-final class Groovy7306 extends StringSourcesStubTestCase {
+final class Groovy10797 extends StringSourcesStubTestCase {
 
     @Override
     Map<String, String> provideSources() {
         [
-            'A7306.groovy': '''
-                abstract class A7306<T extends Number> {
-                    final T value
-                    A7306(T value) {
-                        this.value = value
-                    }
+            'A.java': '''
+                public class A<T> {
+                }
+            ''',
+            'B.java': '''
+                public class B<T extends A<?>> {
                 }
             ''',
-            'C7306.groovy': '''
-                class C7306 extends A7306<Integer> {
-                    C7306(Integer value) {
-                        super(value)
+            'C.groovy': '''
+                class C {
+                    static <T extends A<?>> B<T> test() {
                     }
                 }
             ''',
             'Main.java': '''
                 public class Main {
                     public static void main(String[] args) {
-                        new C7306();
+                        C.test();
                     }
                 }
             ''',
@@ -50,9 +49,7 @@ final class Groovy7306 extends StringSourcesStubTestCase {
 
     @Override
     void verifyStubs() {
-        compile([new File(stubDir,'A7306.java'), new File(stubDir,'C7306.java')])
-
-        def specialCtorCall = (stubJavaSourceFor('C7306') =~ /super\s*\((.+?)\);/)
-        assert specialCtorCall.find() && specialCtorCall.group(1) == '(java.lang.Integer)null'
+        String stub = stubJavaSourceFor('C')
+        assert stub.contains('public static <T extends A<?>> B<T> test() { return (B<T>)null;}');
     }
 }
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy
index fec232a30d..6b49936d5b 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7306.groovy
@@ -41,7 +41,7 @@ final class Groovy7306 extends StringSourcesStubTestCase {
             'Main.java': '''
                 public class Main {
                     public static void main(String[] args) {
-                        new C7306();
+                        new C7306(1234);
                     }
                 }
             ''',
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/StubTestCase.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/StubTestCase.groovy
index 441abafa84..02e9c4dab7 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/StubTestCase.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/StubTestCase.groovy
@@ -182,25 +182,25 @@ abstract class StubTestCase extends GroovyTestCase {
 
                 println "Verifying the stubs"
             }
-        } catch(Throwable t) {
+        } catch (Throwable t) {
             compileError = t
         } finally {
             try {
                 use (QDoxCategory) {
                     verifyStubs()
                 }
-            } catch(ex) {
+            } catch (AssertionError | RuntimeException e) {
                 if (compileError) {
-                    println "Unable to verify stubs: $ex.message\nPerhaps due to earlier error?"
+                    println "Unable to verify stubs: $e.message\nPerhaps due to earlier error?"
                     throw compileError
                 }
-                throw ex
+                throw e
             }
             if (sourceRootPath.getAbsolutePath() =~ 'stubgentests') {
                 sourceRootPath.deleteDir()
             }
         }
-
+        if (compileError) throw compileError
     }
 
     /**
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/TraitAbstractGetterStubTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/TraitAbstractGetterStubTest.groovy
index d2df4c5a69..4b5d228bc7 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/TraitAbstractGetterStubTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/TraitAbstractGetterStubTest.groovy
@@ -21,48 +21,35 @@ package org.codehaus.groovy.tools.stubgenerator
 /**
  * GROOVY-8895: Checks that a trait with an abstract getter isn't included in stub by mistake
  */
-class TraitAbstractGetterStubTest extends StringSourcesStubTestCase {
+final class TraitAbstractGetterStubTest extends StringSourcesStubTestCase {
 
     @Override
     Map<String, String> provideSources() {
         [
-            'Foo8895.java': '''
-                public class Foo8895 { }
-            ''',
-
-            'GetFoo.groovy': '''
-                trait GetFoo {
-                    abstract Foo8895 getFoo()
+            'Pogo.java': '''
+                public class Pogo {
                 }
             ''',
-
-            'BaseFooSpec.groovy': '''
-                class BaseFooSpec {
-                    Foo8895 foo = new Foo8895()
+            'GetPogo.groovy': '''
+                trait GetPogo {
+                    abstract Pogo getPogo()
                 }
             ''',
-
-            'FooSpec.groovy': '''
-                class FooSpec extends BaseFooSpec implements GetFoo { }
+            'BaseSpec.groovy': '''
+                class BaseSpec {
+                    Pogo pogo = new Pogo()
+                }
             ''',
-
-            'Control.groovy': '''
-                class Control implements GetFoo { }
+            'PogoSpec.groovy': '''
+                class PogoSpec extends BaseSpec implements GetPogo {
+                }
             ''',
         ]
     }
 
-//    protected void init() {
-//        debug = true
-//        delete = false
-//    }
-
     @Override
     void verifyStubs() {
-        String stubSource = stubJavaSourceFor('FooSpec')
-        assert !stubSource.contains('Foo8895 getFoo()')
-        stubSource = stubJavaSourceFor('Control')
-        assert !stubSource.contains('Foo8895 getFoo()')
+        String stub = stubJavaSourceFor('PogoSpec')
+        assert !stub.contains('Pogo getPogo()')
     }
-
 }