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/01/30 21:40:05 UTC

[groovy] branch GROOVY_3_0_X updated (287a174 -> bfb29e8)

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

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


    from 287a174  GROOVY-10379: interface default methods in `ClassNode#hasPossibleMethod`
     new e831e7f  GROOVY-10396: StaticImportVisitor: static context skips instance methods
     new 20810a4  GROOVY-5859, GROOVY-10407: stubgen: write param type arguments (not raw)
     new 8ce1678  GROOVY-10419: STC: fix overflow for elvis assignment using setter method
     new bfb29e8  GROOVY-10464: stubgen: super ctor call: handle class cases

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../groovy/control/StaticImportVisitor.java        |  25 +-
 .../groovy/tools/javac/JavaStubGenerator.java      |  50 ++-
 .../transform/stc/StaticTypeCheckingVisitor.java   |  37 +-
 src/test/groovy/StaticImportTest.groovy            | 483 +++++++++++++++------
 .../groovy/transform/stc/STCAssignmentTest.groovy  |  73 +++-
 .../{Groovy10122.groovy => Groovy10122pt2.groovy}  |  17 +-
 .../{Groovy10299.groovy => Groovy10407.groovy}     |  24 +-
 .../{Groovy10122.groovy => Groovy10464.groovy}     |  19 +-
 .../{Groovy10122.groovy => Groovy10464pt2.groovy}  |  15 +-
 .../{Groovy10299.groovy => Groovy5859.groovy}      |  27 +-
 .../tools/stubgenerator/Groovy5859Bug.groovy       |  41 --
 11 files changed, 517 insertions(+), 294 deletions(-)
 copy src/test/org/codehaus/groovy/tools/stubgenerator/{Groovy10122.groovy => Groovy10122pt2.groovy} (82%)
 copy src/test/org/codehaus/groovy/tools/stubgenerator/{Groovy10299.groovy => Groovy10407.groovy} (70%)
 copy src/test/org/codehaus/groovy/tools/stubgenerator/{Groovy10122.groovy => Groovy10464.groovy} (81%)
 copy src/test/org/codehaus/groovy/tools/stubgenerator/{Groovy10122.groovy => Groovy10464pt2.groovy} (82%)
 copy src/test/org/codehaus/groovy/tools/stubgenerator/{Groovy10299.groovy => Groovy5859.groovy} (68%)
 delete mode 100644 src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy

[groovy] 03/04: GROOVY-10419: STC: fix overflow for elvis assignment using setter method

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8ce16783623a8a71df835b7a8fb7274c00f1290e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Dec 16 17:57:40 2021 -0600

    GROOVY-10419: STC: fix overflow for elvis assignment using setter method
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 37 ++++++-----
 .../groovy/transform/stc/STCAssignmentTest.groovy  | 73 +++++++++++++++-------
 2 files changed, 69 insertions(+), 41 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 453040d..01bf8cf 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -189,6 +189,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.elvisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
@@ -965,10 +966,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         // because we need to check if a setter uses @DelegatesTo
         VariableExpression ve = varX("%", setterInfo.receiverType);
         // for compound assignment "x op= y" find type as if it was "x = (x op y)"
-        Expression newRightExpression = isCompoundAssignment(expression)
-                ? binX(leftExpression, getOpWithoutEqual(expression), rightExpression)
-                : rightExpression;
-        MethodCallExpression call = callX(ve, setterInfo.name, newRightExpression);
+        Expression valueExpression = rightExpression;
+        if (isCompoundAssignment(expression)) {
+            Token op = ((BinaryExpression) expression).getOperation();
+            if (op.getType() == ELVIS_EQUAL) { // GROOVY-10419: "x ?= y"
+                valueExpression = elvisX(leftExpression, rightExpression);
+            } else {
+                op = Token.newSymbol(TokenUtil.removeAssignment(op.getType()), op.getStartLine(), op.getStartColumn());
+                valueExpression = binX(leftExpression, op, rightExpression);
+            }
+        }
+        MethodCallExpression call = callX(ve, setterInfo.name, valueExpression);
         call.setImplicitThis(false);
         visitMethodCallExpression(call);
         MethodNode directSetterCandidate = call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
@@ -978,7 +986,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             for (MethodNode setter : setterInfo.setters) {
                 ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
                 if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
-                    call = callX(ve, setterInfo.name, castX(type, newRightExpression));
+                    call = callX(ve, setterInfo.name, castX(type, valueExpression));
                     call.setImplicitThis(false);
                     visitMethodCallExpression(call);
                     directSetterCandidate = call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
@@ -993,14 +1001,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 if (setter == directSetterCandidate) {
                     leftExpression.putNodeMetaData(DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
                     leftExpression.removeNodeMetaData(INFERRED_TYPE); // clear assumption
-                    storeType(leftExpression, getType(newRightExpression));
+                    storeType(leftExpression, getType(valueExpression));
                     break;
                 }
             }
             return false;
         } else {
             ClassNode firstSetterType = setterInfo.setters.get(0).getParameters()[0].getOriginType();
-            addAssignmentError(firstSetterType, getType(newRightExpression), expression);
+            addAssignmentError(firstSetterType, getType(valueExpression), expression);
             return true;
         }
     }
@@ -1010,16 +1018,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private static boolean isCompoundAssignment(final Expression exp) {
-        if (!(exp instanceof BinaryExpression)) return false;
-        int type = ((BinaryExpression) exp).getOperation().getType();
-        return isAssignment(type) && type != ASSIGN;
-    }
-
-    private static Token getOpWithoutEqual(final Expression exp) {
-        if (!(exp instanceof BinaryExpression)) return null; // should never happen
-        Token op = ((BinaryExpression) exp).getOperation();
-        int typeWithoutEqual = TokenUtil.removeAssignment(op.getType());
-        return new Token(typeWithoutEqual, op.getText() /* will do */, op.getStartLine(), op.getStartColumn());
+        if (exp instanceof BinaryExpression) {
+            Token op = ((BinaryExpression) exp).getOperation();
+            return isAssignment(op.getType()) && op.getType() != EQUAL;
+        }
+        return false;
     }
 
     protected ClassNode getOriginalDeclarationType(final Expression lhs) {
diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
index 462334c..13fb434 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -1015,16 +1015,16 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
 
     void testMultiAssign() {
         assertScript '''
-        def m() {
-            def row = ['', '', '']
-            def (left, right) = [row[0], row[1]]
-            left.toUpperCase()
-        }
+            def m() {
+                def row = ['', '', '']
+                def (left, right) = [row[0], row[1]]
+                left.toUpperCase()
+            }
         '''
     }
 
     // GROOVY-8220
-    void testFlowTypingParameterTempTypeAssignmentTracking() {
+    void testFlowTypingParameterTempTypeAssignmentTracking1() {
         assertScript '''
             class Foo {
                 CharSequence makeEnv( env, StringBuilder result = new StringBuilder() ) {
@@ -1039,7 +1039,10 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
             }
             assert new Foo().makeEnv('X=1') == 'export X=1;'
         '''
-        // GROOVY-8237
+    }
+
+    // GROOVY-8237
+    void testFlowTypingParameterTempTypeAssignmentTracking2() {
         assertScript '''
             class Foo {
                 String parse(Reader reader) {
@@ -1053,7 +1056,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testFlowTypingParameterTempTypeAssignmentTrackingWithGenerics() {
+    void testFlowTypingParameterTempTypeAssignmentTracking3() {
         assertScript '''
             class M {
                 Map<String, List<Object>> mvm = new HashMap<String, List<Object>>()
@@ -1083,27 +1086,49 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
 
     void testNarrowingConversion() {
         assertScript '''
-        interface A1{}
-        interface A2 extends A1{}
-
-        class C1 implements A1{}
-
-        def m(A2 a2) {
-            C1 c1 = (C1) a2
-        }
+            interface A {
+            }
+            interface B extends A {
+            }
+            class C implements B {
+            }
+            def m(B b) {
+                C c = (C) b
+            }
         '''
     }
 
     void testFinalNarrowingConversion() {
         shouldFailWithMessages '''
-        interface A1{}
-        interface A2 extends A1{}
-
-        final class C1 implements A1{}
+            interface I {
+            }
+            interface B extends I {
+            }
+            final class C implements I {
+            }
+            def m(B b) {
+                C c = (C) b
+            }
+        ''',
+        'Inconvertible types: cannot cast B to C'
+    }
 
-        def m(A2 a2) {
-            C1 c1 = (C1) a2
-        }
-        ''', 'Inconvertible types: cannot cast A2 to C1'
+    // GROOVY-10419
+    void testElvisAssignmentAndSetter() {
+        assertScript '''
+            class C {
+                def p
+                void setP(p) {
+                    this.p = p
+                }
+            }
+            @groovy.transform.TypeChecked
+            void test(C c) {
+                c.p ?= 'x'
+            }
+            def c = new C()
+            test(c)
+            assert c.p == 'x'
+        '''
     }
 }

[groovy] 01/04: GROOVY-10396: StaticImportVisitor: static context skips instance methods

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e831e7fd346efdedf648d73095f43b09cd0774f5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 30 10:54:18 2021 -0600

    GROOVY-10396: StaticImportVisitor: static context skips instance methods
    
    Conflicts:
    	src/test/groovy/StaticImportTest.groovy
---
 .../groovy/control/StaticImportVisitor.java        |  25 +-
 src/test/groovy/StaticImportTest.groovy            | 483 +++++++++++++++------
 2 files changed, 366 insertions(+), 142 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
index ad24384..e8bbea1 100644
--- a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -119,6 +119,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         inAnnotation = oldInAnnotation;
     }
 
+    @Override
     public Expression transform(Expression exp) {
         if (exp == null) return null;
         Class<? extends Expression> clazz = exp.getClass();
@@ -209,6 +210,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
             if (left instanceof StaticMethodCallExpression) {
                 StaticMethodCallExpression smce = (StaticMethodCallExpression) left;
                 StaticMethodCallExpression result = new StaticMethodCallExpression(smce.getOwnerType(), smce.getMethod(), right);
+                result.copyNodeMetaData(smce);
                 setSourcePosition(result, be);
                 return result;
             }
@@ -249,10 +251,13 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         Expression method = transform(mce.getMethod());
         Expression args = transform(mce.getArguments());
 
+        // GROOVY-10396: skip the instance method checks when the context is static with-respect-to current class
+        boolean staticWrtCurrent = inSpecialConstructorCall || currentMethod != null && currentMethod.isStatic();
+
         if (mce.isImplicitThis()) {
             String name = mce.getMethodAsString();
-            if (currentClass.tryFindPossibleMethod(name, args) == null
-                    && currentClass.getOuterClasses().stream().noneMatch(oc -> oc.tryFindPossibleMethod(name, args) != null)) {
+            boolean thisOrSuperMethod = staticWrtCurrent ? hasPossibleStaticMethod(currentClass, name, args, true) : currentClass.tryFindPossibleMethod(name, args) != null;
+            if (!thisOrSuperMethod && currentClass.getOuterClasses().stream().noneMatch(oc -> oc.tryFindPossibleMethod(name, args) != null)) {
                 Expression result = findStaticMethodImportFromModule(method, args);
                 if (result != null) {
                     setSourcePosition(result, mce);
@@ -267,7 +272,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
                     }
                 }
             }
-        } else if (currentMethod != null && currentMethod.isStatic() && isSuperExpression(object)) {
+        } else if (staticWrtCurrent && isSuperExpression(object)) {
             Expression result = new MethodCallExpression(new ClassExpression(currentClass.getSuperClass()), method, args);
             result.setSourcePosition(mce);
             return result;
@@ -276,7 +281,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         if (method instanceof ConstantExpression && ((ConstantExpression) method).getValue() instanceof String && (mce.isImplicitThis() || isThisOrSuper(object))) {
             String methodName = (String) ((ConstantExpression) method).getValue();
 
-            boolean foundInstanceMethod = (currentMethod != null && !currentMethod.isStatic() && currentClass.hasPossibleMethod(methodName, args));
+            boolean foundInstanceMethod = !staticWrtCurrent && currentClass.hasPossibleMethod(methodName, args);
 
             Predicate<ClassNode> hasPossibleStaticMember = cn -> {
                 if (hasPossibleStaticMethod(cn, methodName, args, true)) {
@@ -362,7 +367,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         if (currentMethod != null && currentMethod.isStatic()
                 && isSuperExpression(pe.getObjectExpression())) {
             PropertyExpression pexp = new PropertyExpression(
-                    new ClassExpression(currentClass.getSuperClass()),
+                    new ClassExpression(currentClass.getUnresolvedSuperClass()),
                     transform(pe.getProperty())
             );
             pexp.setSourcePosition(pe);
@@ -379,7 +384,7 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         if (foundArgs != null && foundConstant != null
                 && !foundConstant.getText().trim().isEmpty()
                 && objectExpression instanceof MethodCallExpression
-                && ((MethodCallExpression)objectExpression).isImplicitThis()) {
+                && ((MethodCallExpression) objectExpression).isImplicitThis()) {
             Expression result = findStaticMethodImportFromModule(foundConstant, foundArgs);
             if (result != null) {
                 objectExpression = result;
@@ -565,14 +570,14 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         return null;
     }
 
-    private static PropertyExpression newStaticPropertyX(ClassNode type, String name) {
-        return new PropertyExpression(new ClassExpression(type.getPlainNodeReference()), name);
-    }
-
     private static StaticMethodCallExpression newStaticMethodCallX(ClassNode type, String name, Expression args) {
         return new StaticMethodCallExpression(type.getPlainNodeReference(), name, args);
     }
 
+    private static PropertyExpression newStaticPropertyX(ClassNode type, String name) {
+        return new PropertyExpression(new ClassExpression(type.getPlainNodeReference()), name);
+    }
+
     @Override
     protected SourceUnit getSourceUnit() {
         return sourceUnit;
diff --git a/src/test/groovy/StaticImportTest.groovy b/src/test/groovy/StaticImportTest.groovy
index 4ef9adc..f04699f 100644
--- a/src/test/groovy/StaticImportTest.groovy
+++ b/src/test/groovy/StaticImportTest.groovy
@@ -18,7 +18,6 @@
  */
 package groovy
 
-import gls.CompilableTestSupport
 import static java.lang.Boolean.FALSE as F
 import static java.text.DateFormat.MEDIUM as M
 import static java.util.regex.Pattern.*
@@ -27,24 +26,21 @@ import static junit.framework.Assert.format
 import static junit.framework.Assert.assertEquals
 import static groovy.StaticImportTarget.x
 import static groovy.StaticImportTarget.z // do not remove
-import static groovy.StaticImportTarget.getCl
 import static java.lang.Math.*
 import static java.util.Calendar.getInstance as now
 import static groovy.API.*
 import static groovy.StaticImportChild.*
-import static groovy.bugs.Groovy4145.foo4145
 import static groovy.Outer1.*
 import static groovy.Outer2.Inner2
 import static groovy.Outer2.Inner2 as InnerAlias2
 import static java.util.jar.Attributes.*
 import static java.util.jar.Attributes.Name as AttrName
-// TODO GROOVY-4287: reinstate next two imports
-//import static Outer3.*
-//import static Outer4.Inner4
 import static groovy.Container5087.*
+import static Foo4964.*
 import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM
 
-class StaticImportTest extends CompilableTestSupport {
+final class StaticImportTest extends groovy.test.GroovyTestCase {
+
     void testFieldWithAliasInExpression() {
         assert !F
     }
@@ -71,15 +67,16 @@ class StaticImportTest extends CompilableTestSupport {
     }
 
     void testFieldAsArgumentList() {
-        assert ("" + PI.toString()).contains('3.14')
+        assert ('' + PI.toString()).contains('3.14')
     }
 
     void testFieldAliasing() {
         assert MEDIUM == M
     }
 
+    // GROOVY-1809
     void testMethodAliasing() {
-        // GROOVY-1809 making this not possible on one line?
+        // making this not possible on one line?
         def now = now().time
         assert now.class == Date
     }
@@ -91,7 +88,7 @@ class StaticImportTest extends CompilableTestSupport {
     private format(a, b, c, ignored) { format(a, b, c) }
 
     void testMethodDefCanUseStaticallyImportedMethodWithSameNameButDiffArgs() {
-        assert format("different", "abc", "aBc", 3) == 'different expected:<abc> but was:<aBc>'
+        assert format('different', 'abc', 'aBc', 3) == 'different expected:<abc> but was:<aBc>'
     }
 
     void testAssertEqualsFromJUnit() {
@@ -103,15 +100,15 @@ class StaticImportTest extends CompilableTestSupport {
     }
 
     void testStaticImportFromGroovy() {
-        def nonstaticval = new StaticImportTarget().y("he", 3)
-        def staticval = x("he", 3)
+        def nonstaticval = new StaticImportTarget().y('he', 3)
+        def staticval = x('he', 3)
         assert nonstaticval == staticval
     }
 
     void testStaticImportWithVarArgs() {
-        assert noArrayMethod("one", 1) == 'noArrayMethod(one, 1)'
-        assert API.arrayMethod("two", 1, 2, 3) == 'arrayMethod(two, 1, 2, 3)'
-        assert arrayMethod("three", 1, 2, 3) == 'arrayMethod(three, 1, 2, 3)'
+        assert noArrayMethod('one', 1) == 'noArrayMethod(one, 1)'
+        assert API.arrayMethod('two', 1, 2, 3) == 'arrayMethod(two, 1, 2, 3)'
+        assert arrayMethod('three', 1, 2, 3) == 'arrayMethod(three, 1, 2, 3)'
     }
 
     void testStaticImportFromParentClass() {
@@ -120,126 +117,284 @@ class StaticImportTest extends CompilableTestSupport {
         assert cfield == 21
         assert pfield == 42
     }
-    
+
     void testStaticImportAndDefaultValue() {
-      assertScript """
-        import static Foo.*
-        import static Bar.*
-        
-        class Bar {
-          static void bar() { 
-            assert foo(10,1000) == 1010 
-            assert foo(10) == 110
-          }
-        }
-        
-        class Foo {
-          static int foo(int x, int y = 100) {x+y}
-        }
-        
-        Bar.bar()
-      """  
+        assertScript '''
+            import static Foo.*
+            import static Bar.*
+
+            class Bar {
+                static void bar() {
+                    assert foo(10,1000) == 1010
+                    assert foo(10) == 110
+                }
+            }
+
+            class Foo {
+                static int foo(int x, int y = 100) {x+y}
+            }
+
+            Bar.bar()
+        '''
     }
 
     void testStaticImportProperty() {
-        def sources = [
-            "class Foo { static x = 'foo'" + " }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' } }",
-            "class Foo { static x = 'foo'" + ";                               static void setX(newx) { x = newx + '_set' } }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }"
-        ]
-        def imports = [
-            "import static Foo.*",
-            "import static Foo.getX; import static Foo.setX"
-        ]
-        def results = [
-            "assert x == 'foo';     x = 'bar'; assert getX() == 'bar';         setX('baz'); assert 'baz'         == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_get';     setX('baz'); assert 'baz_get'     == x",
-            "assert x == 'foo';     x = 'bar'; assert getX() == 'bar_set';     setX('baz'); assert 'baz_set'     == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == x"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.getX; import static Foo.setX', 'import static Foo.*']) {
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert getX() == 'bar'
+                setX('baz')
+                assert 'baz' == x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_get'
+                setX('baz')
+                assert 'baz_get' == x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert getX() == 'bar_set'
+                setX('baz')
+                assert 'baz_set' == x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_set_get'
+                setX('baz')
+                assert 'baz_set_get' == x
+            """
         }
     }
 
     void testStaticImportPropertyBooleanAlternative() {
-        def sources = [
-            "class Foo { static x = null" + "; static boolean isX() { x } }",
-            "class Foo { static x = null" + "; static boolean isX() { x }; static void setX(newx) { x = newx } }"
-        ]
-        def imports = [
-            "import static Foo.*",
-            "import static Foo.x",
-            "import static Foo.isX; import static Foo.setX"
-        ]
-        def results = [
-            "assert !x; x = true ; assert  isX(); setX(false); assert !x",
-            "assert !x; x = false; assert !isX(); setX(true);  assert  x"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.isX; import static Foo.setX', 'import static Foo.x', 'import static Foo.*']) {
+            assertScript """$imports
+                class Foo {
+                    static x
+                    static boolean isX() { !!x }
+                }
+                assert !x
+                x = true
+                assert isX()
+                setX(false)
+                assert !x
+            """
+            assertScript """$imports
+                class Foo {
+                    static x
+                    static boolean isX() { !!x }
+                    static void setX(newx) { x = newx }
+                }
+                assert !x
+                x = false
+                assert !isX()
+                setX(true)
+                assert x
+            """
         }
     }
 
     void testStaticImportPropertyWithPublicField() {
-        def sources = [
-            "class Foo { public static x = 'foo'" + " }",
-            "class Foo { public static x = 'foo'" + "; static getX() { x + '_get' } }",
-            "class Foo { public static x = 'foo'" + ";                               static void setX(newx) { x = newx + '_set' } }",
-            "class Foo { public static x = 'foo'" + "; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }"
-        ]
-        def imports = [
-            "import static Foo.*",
-            "import static Foo.x"
-        ]
-        def results = [
-            "assert x == 'foo';     x = 'bar'; assert      x == 'bar';         x = 'baz'  ; assert 'baz'         == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_get';     x = 'baz'  ; assert 'baz_get'     == x",
-            "assert x == 'foo';     x = 'bar'; assert      x == 'bar_set';     setX('baz'); assert 'baz_set'     == x",
-            "assert x == 'foo_get'; x = 'bar'; assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == x"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.x', 'import static Foo.*']) {
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert x == 'bar'
+                x = 'baz'
+                assert x == 'baz'
+            """
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                    static getX() { x + '_get' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_get'
+                x = 'baz'
+                assert x == 'baz_get'
+            """
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo'
+                x = 'bar'
+                assert x == 'bar_set'
+                setX('baz')
+                assert x == 'baz_set'
+            """
+            assertScript """$imports
+                class Foo {
+                    public static x = 'foo'
+                    static getX() { x + '_get' }
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert x == 'foo_get'
+                x = 'bar'
+                assert getX() == 'bar_set_get'
+                setX('baz')
+                assert x == 'baz_set_get'
+            """
         }
-        assertScript sources[3] + """
+        assertScript '''
             import static Foo.getX; import static Foo.setX
+            class Foo { public static x = 'foo'; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }
             assert getX() == 'foo_get'; setX('bar'); assert getX() == 'bar_set_get'; setX('baz'); assert 'baz_set_get' == getX()
-        """
+        '''
     }
 
     void testStaticImportPropertyWithAliases() {
-        def sources = [
-            "class Foo { static x = 'foo'" + " }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' } }",
-            "class Foo { static x = 'foo'" + ";                               static void setX(newx) { x = newx + '_set' } }",
-            "class Foo { static x = 'foo'" + "; static getX() { x + '_get' }; static void setX(newx) { x = newx + '_set' } }"
-        ]
-        def imports = [
-            "import static Foo.x as z",
-            "import static Foo.getX as getZ; import static Foo.setX as setZ"
-        ]
-        def results = [
-            "assert z == 'foo';     z = 'bar'; assert getZ() == 'bar';         setZ('baz'); assert 'baz'         == z",
-            "assert z == 'foo_get'; z = 'bar'; assert getZ() == 'bar_get';     setZ('baz'); assert 'baz_get'     == z",
-            "assert z == 'foo';     z = 'bar'; assert getZ() == 'bar_set';     setZ('baz'); assert 'baz_set'     == z",
-            "assert z == 'foo_get'; z = 'bar'; assert getZ() == 'bar_set_get'; setZ('baz'); assert 'baz_set_get' == z"
-        ]
-        [0..<sources.size(), 0..<imports.size()].combinations().each { i, j ->
-            assertScript sources[i] + "\n" + imports[j] + "\n" + results[i]
+        for (imports in ['import static Foo.getX as getZ; import static Foo.setX as setZ', 'import static Foo.x as z']) {
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                }
+                assert z == 'foo'
+                z = 'bar'
+                assert getZ() == 'bar'
+                setZ('baz')
+                assert z == 'baz'
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                }
+                assert z == 'foo_get'
+                z = 'bar'
+                assert getZ() == 'bar_get'
+                setZ('baz')
+                assert z == 'baz_get'
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert z == 'foo'
+                z = 'bar'
+                assert getZ() == 'bar_set'
+                setZ('baz')
+                assert z == 'baz_set'
+            """
+            assertScript """$imports
+                class Foo {
+                    static x = 'foo'
+                    static getX() { x + '_get' }
+                    static void setX(newx) { x = newx + '_set' }
+                }
+                assert z == 'foo_get'
+                z = 'bar'
+                assert getZ() == 'bar_set_get'
+                setZ('baz')
+                assert z == 'baz_set_get'
+            """
         }
     }
 
+    // GROOVY-8389
+    void testStaticImportMethodVsLocalMethod() {
+        assertScript '''
+            import static Foo.bar
+            class Foo {
+                static bar = 'foo'
+            }
+            def bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                bar()
+            }
+            assert test() == 'bar'
+        '''
+
+        assertScript '''
+            import static Foo.bar
+            class Foo {
+                static bar = 'foo'
+            }
+            static bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                bar()
+            }
+            assert test() == 'bar'
+        '''
+
+        assertScript '''
+            import static Foo.baz
+            import static Foo.bar
+            class Foo {
+                static bar() { 'foobar' }
+                static baz() { 'foobaz' }
+            }
+            def bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                "${bar()}${baz()}"
+            }
+            assert test() == 'barfoobaz'
+        '''
+
+        assertScript '''
+            import static Foo.baz
+            import static Foo.bar
+            class Foo {
+                static bar() { 'foobar' }
+                static baz() { 'foobaz' }
+            }
+            static bar() {
+                'bar'
+            }
+            @groovy.transform.CompileStatic
+            def test() {
+                "${bar()}${baz()}"
+            }
+            assert test() == 'barfoobaz'
+        '''
+    }
+
     void testConstructorArgsAliasing() {
         // not recommended style to use statics in constructors but supported
-        assertScript """
-        class Foo {
-            static x
-        }
-        import static Foo.x as z
-        new Foo(z:'hi')
-        assert z == 'hi'
-        """
+        assertScript '''
+            class Foo {
+                static x
+            }
+            import static Foo.x as z
+            new Foo(z:'hi')
+            assert z == 'hi'
+        '''
     }
 
     void testMethodCallWithThisTargetIsNotResolvedToStaticallyImportedMethod() {
@@ -258,18 +413,32 @@ class StaticImportTest extends CompilableTestSupport {
         } catch (MissingMethodException expected) {}
     }
 
-    // GROOVY-3945
-    void testStaticImportOfAClosureProperty() {
-        assert cl() == 'StaticImportTarget#static closure called'
+    // GROOVY-3945, GROOVY-10329
+    void testStaticImportOfClosureProperty() {
+        for (imports in ['import static groovy.StaticImportTarget.cl', 'import static groovy.StaticImportTarget.*']) {
+            assertScript """$imports
+                String result = cl()
+                assert result == 'StaticImportTarget#static closure called'
+            """
+        }
     }
 
     // GROOVY-4145
     void testStaticPropertyImportedImplementedAsGetter() {
-        assert foo4145 == 3
+        assertScript '''
+            import static Groovy4145.foo4145
+            class Groovy4145 {
+                static getFoo4145() {
+                    return 3
+                }
+            }
+            assert foo4145 == 3
+        '''
     }
 
-    void testMethodCallExpressionInStaticContextWithInstanceVariableShouldFail() { //GROOVY-4228
-        shouldNotCompile '''
+    // GROOVY-4228
+    void testMethodCallExpressionInStaticContextWithInstanceVariableShouldFail() {
+        def err = shouldFail '''
             class B {
                 def c = new Object()
                 static main(args) {
@@ -277,6 +446,57 @@ class StaticImportTest extends CompilableTestSupport {
                 }
             }
         '''
+        assert err =~ /Apparent variable 'c' was found in a static scope but doesn't refer to a local variable, static field or class/
+    }
+
+    // GROOVY-10396
+    void testStaticImportVersusThisOrSuperMethod1() {
+        assertScript '''
+            import static groovy.Extension10396.*
+
+            static void test() {
+                println 'x'
+            }
+            strings.clear()
+            test()
+
+            assert 'x' in strings
+        '''
+    }
+
+    // GROOVY-10396
+    void testStaticImportVersusThisOrSuperMethod2() {
+        assertScript '''
+            import static groovy.Extension10396.*
+
+            def obj = new Object() { // outer class extends Script
+                String toString() {
+                    println 'AIC::x'
+                    super.toString()
+                }
+            }
+            strings.clear()
+            obj.toString()
+
+            assert 'x' !in strings
+        '''
+    }
+
+    // GROOVY-10396
+    void testStaticImportVersusThisOrSuperMethod3() {
+        assertScript '''
+            import static groovy.Extension10396.*
+
+            static void println(String s) { // static overload
+            }
+            static void test() {
+                println 'x'
+            }
+            strings.clear()
+            test()
+
+            assert 'x' !in strings
+        '''
     }
 
     void testStaticStarImportOfStaticInnerClass() {
@@ -303,15 +523,6 @@ class StaticImportTest extends CompilableTestSupport {
         Bar4964.run()
     }
 
-    // TODO GROOVY-4287: reinstate next two tests
-//    void testStaticStarImportOfStaticInnerClassExternalClass() {
-//        assert Inner3.class.name == 'Outer3$Inner3'
-//    }
-//
-//    void testStaticImportOfStaticInnerClassExternalClass() {
-//        assert Inner4.class.name == 'Outer4$Inner4'
-//    }
-
     void testMapIndexInLeftExpressionOfEquals() {
         holder = 'foo'
         def map = [:]
@@ -339,6 +550,8 @@ class StaticImportTest extends CompilableTestSupport {
     }
 }
 
+//------------------------------------------------------------------------------
+
 class API {
     static noArrayMethod(String s, int value) {
         "noArrayMethod(${s}, ${value})"
@@ -350,13 +563,13 @@ class API {
 }
 
 class StaticImportParent {
-  static pfield = 42
-  static pmethod() { 'hello from parent' }
+    static pfield = 42
+    static pmethod() { 'hello from parent' }
 }
 
 class StaticImportChild extends StaticImportParent {
-  static cfield = 21
-  static cmethod() { 'hello from child' }
+    static cfield = 21
+    static cmethod() { 'hello from child' }
 }
 
 class Outer1 {
@@ -371,7 +584,6 @@ class Foo4964 {
     static doIt() { [k: 'foo'] }
 }
 
-import static Foo4964.*
 class Bar4964 {
     static doIt() { [k: 'bar'] }
 
@@ -407,3 +619,10 @@ class HolderWrapper {
         holder[name] = value
     }
 }
+
+class Extension10396 {
+    static final List<String> strings = []
+    static void println(String s) {
+        strings << s
+    }
+}

[groovy] 02/04: GROOVY-5859, GROOVY-10407: stubgen: write param type arguments (not raw)

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 20810a482c2aad66f5a973345551697fb9c9d5ed
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Dec 12 12:30:03 2021 -0600

    GROOVY-5859, GROOVY-10407: stubgen: write param type arguments (not raw)
---
 .../groovy/tools/javac/JavaStubGenerator.java      | 14 +++++----
 .../{Groovy5859Bug.groovy => Groovy10407.groovy}   | 33 +++++++++++++---------
 .../{Groovy5859Bug.groovy => Groovy5859.groovy}    | 30 ++++++++++++--------
 3 files changed, 47 insertions(+), 30 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 d4f1f03..a780d8e 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -58,6 +58,7 @@ import org.objectweb.asm.Opcodes;
 
 import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -562,11 +563,14 @@ public class JavaStubGenerator {
             Parameter[] parameters = target.getParameters();
             Parameter[] normalized = Arrays.stream(parameters).map(parameter -> {
                 ClassNode normalizedType = parameter.getOriginType();
-                // GROOVY-7306: apply type arguments from declaring type to parameter type
-                normalizedType = correctToGenericsSpec(superTypeGenerics, normalizedType);
-                // workaround for GROOVY-5859: remove generic type info
-                normalizedType = normalizedType.getPlainNodeReference();
-
+                if (superType.getGenericsTypes() == null // GROOVY-10407
+                        && superType.redirect().getGenericsTypes() != null) {
+                    // GROOVY-5859: remove generic type info for raw type
+                    normalizedType = normalizedType.getPlainNodeReference();
+                } else {
+                    // GROOVY-7306: apply type arguments from declaring type to parameter type
+                    normalizedType = correctToGenericsSpec(superTypeGenerics, normalizedType);
+                }
                 return new Parameter(normalizedType, parameter.getName());
             }).toArray(Parameter[]::new);
 
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10407.groovy
similarity index 60%
copy from src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy
copy to src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10407.groovy
index 9d49391..e7d32f4 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10407.groovy
@@ -18,24 +18,31 @@
  */
 package org.codehaus.groovy.tools.stubgenerator
 
-class Groovy5859Bug extends StringSourcesStubTestCase {
+final class Groovy10407 extends StringSourcesStubTestCase {
+
     @Override
     Map<String, String> provideSources() {
-        ['TaggedsMap.groovy': '''import org.codehaus.groovy.tools.stubgenerator.Groovy5859Support
-
-class TaggedsMap extends Groovy5859Support {
-
-    TaggedsMap(SortedMap m) {
-        super()
-        putAll (m)
-    }
-}''',
-        'Blah.java': '''public class Blah { TaggedsMap map; }''']
+        [
+            'Pogo.groovy': '''
+                class Foo {
+                    Foo(Map<String, String> map) {
+                    }
+                }
+                class Bar extends Foo {
+                    Bar(Map<String, String> map) {
+                        super(map)
+                    }
+                }
+            ''',
+            'Main.java': '''
+                public class Main { Foo foo; }
+            ''',
+        ]
     }
 
     @Override
     void verifyStubs() {
-        def stubSource = stubJavaSourceFor('TaggedsMap')
-        assert stubSource.contains('super ((java.util.SortedMap)null);')
+        String stub = stubJavaSourceFor('Bar')
+        assert stub.contains('super ((java.util.Map<java.lang.String, java.lang.String>)null);')
     }
 }
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859.groovy
similarity index 61%
rename from src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy
rename to src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859.groovy
index 9d49391..08d444e 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859Bug.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy5859.groovy
@@ -18,24 +18,30 @@
  */
 package org.codehaus.groovy.tools.stubgenerator
 
-class Groovy5859Bug extends StringSourcesStubTestCase {
+final class Groovy5859 extends StringSourcesStubTestCase {
+
     @Override
     Map<String, String> provideSources() {
-        ['TaggedsMap.groovy': '''import org.codehaus.groovy.tools.stubgenerator.Groovy5859Support
-
-class TaggedsMap extends Groovy5859Support {
+        [
+            'Pogo.groovy': """
+                import ${this.class.name}Support
 
-    TaggedsMap(SortedMap m) {
-        super()
-        putAll (m)
-    }
-}''',
-        'Blah.java': '''public class Blah { TaggedsMap map; }''']
+                class Pogo extends ${this.class.simpleName}Support/*no type args*/ {
+                    Pogo(SortedMap map) {
+                        super(/*null*/)
+                        putAll(map)
+                    }
+                }
+            """,
+            'Main.java': '''
+                public class Main { Pogo pogo; }
+            '''
+        ]
     }
 
     @Override
     void verifyStubs() {
-        def stubSource = stubJavaSourceFor('TaggedsMap')
-        assert stubSource.contains('super ((java.util.SortedMap)null);')
+        String stub = stubJavaSourceFor('Pogo')
+        assert stub.contains('super ((java.util.SortedMap)null);')
     }
 }

[groovy] 04/04: GROOVY-10464: stubgen: super ctor call: handle class cases

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit bfb29e8eeda0e9b516f94d27fc42930567fd279e
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jan 27 11:10:21 2022 -0600

    GROOVY-10464: stubgen: super ctor call: handle class cases
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
---
 .../groovy/tools/javac/JavaStubGenerator.java      | 38 +++++++++------
 .../tools/stubgenerator/Groovy10122pt2.groovy      | 54 ++++++++++++++++++++++
 .../groovy/tools/stubgenerator/Groovy10464.groovy  | 52 +++++++++++++++++++++
 .../tools/stubgenerator/Groovy10464pt2.groovy      | 54 ++++++++++++++++++++++
 4 files changed, 183 insertions(+), 15 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 a780d8e..4bf8e1b 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.DynamicVariable;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.ImportNode;
@@ -33,6 +34,7 @@ import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.ModuleNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.ClassExpression;
@@ -81,6 +83,7 @@ import java.util.stream.Stream;
 
 import static org.apache.groovy.ast.tools.ConstructorNodeUtils.getFirstIfSpecialConstructorCall;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
 
 public class JavaStubGenerator {
@@ -155,11 +158,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);
-
+        Writer writer = new StringBuilderWriter(8192);
         try (PrintWriter out = new PrintWriter(writer)) {
             boolean packageInfo = "package-info".equals(classNode.getNameWithoutPackage());
             String packageName = classNode.getPackageName();
@@ -212,7 +212,7 @@ public class JavaStubGenerator {
                         Map<String, ClassNode> generics = trait.isUsingGenerics() ? createGenericsSpec(trait) : null;
                         for (PropertyNode traitProperty : trait.getProperties()) {
                             ClassNode traitPropertyType = traitProperty.getType();
-                            traitProperty.setType(correctToGenericsSpec(generics, traitPropertyType));
+                            traitProperty.setType(correctToGenericsSpecRecurse(generics, traitPropertyType));
                             super.visitProperty(traitProperty);
                             traitProperty.setType(traitPropertyType);
                         }
@@ -407,15 +407,14 @@ public class JavaStubGenerator {
                         }
                     }
                 }
-                if (existingMethod != null) continue;
-                boolean isCandidate = isCandidateTraitMethod(trait, traitMethod);
-                if (!isCandidate) continue;
-                printMethod(out, classNode, traitMethod);
+                if (existingMethod == null && isCandidateTraitMethod(trait, traitMethod)) {
+                    printMethod(out, classNode, traitMethod);
+                }
             }
         }
     }
 
-    private boolean isCandidateTraitMethod(ClassNode trait, MethodNode traitMethod) {
+    private boolean isCandidateTraitMethod(final ClassNode trait, final MethodNode traitMethod) {
         boolean precompiled = trait.redirect() instanceof DecompiledClassNode;
         if (!precompiled) return !traitMethod.isAbstract();
         List<MethodNode> helperMethods = Traits.findHelper(trait).getMethods();
@@ -569,7 +568,7 @@ public class JavaStubGenerator {
                     normalizedType = normalizedType.getPlainNodeReference();
                 } else {
                     // GROOVY-7306: apply type arguments from declaring type to parameter type
-                    normalizedType = correctToGenericsSpec(superTypeGenerics, normalizedType);
+                    normalizedType = correctToGenericsSpecRecurse(superTypeGenerics, normalizedType);
                 }
                 return new Parameter(normalizedType, parameter.getName());
             }).toArray(Parameter[]::new);
@@ -655,7 +654,17 @@ public class JavaStubGenerator {
 
     private static ClassNode getConstructorArgumentType(final Expression arg, final ConstructorNode ctor) {
         if (arg instanceof VariableExpression) {
-            return ((VariableExpression) arg).getAccessedVariable().getType();
+            Variable variable = ((VariableExpression) arg).getAccessedVariable();
+            if (variable instanceof DynamicVariable) { // GROOVY-10464
+                return ClassHelper.CLASS_Type.getPlainNodeReference();
+            }
+            return variable.getType(); // field, property, parameter
+        }
+        if (arg instanceof PropertyExpression) {
+            if ("class".equals(((PropertyExpression) arg).getPropertyAsString())) {
+                return ClassHelper.CLASS_Type.getPlainNodeReference();
+            }
+            return null;
         }
         if (arg instanceof MethodCallExpression) { // GROOVY-10122
             MethodCallExpression mce = (MethodCallExpression) arg;
@@ -669,7 +678,7 @@ public class JavaStubGenerator {
     }
 
     private void printMethod(PrintWriter out, ClassNode clazz, MethodNode methodNode) {
-        if (methodNode.getName().equals("<clinit>")) return;
+        if (methodNode.isStaticConstructor()) return;
         if (methodNode.isPrivate() || !Utilities.isJavaIdentifier(methodNode.getName())) return;
         if (methodNode.isSynthetic() && methodNode.getName().equals("$getStaticMetaClass")) return;
 
@@ -813,7 +822,6 @@ public class JavaStubGenerator {
             printType(out, type);
             out.print(")");
         }
-
         if (type != null && ClassHelper.isPrimitiveType(type)) {
             if (type.equals(ClassHelper.boolean_TYPE)) {
                 out.print("false");
@@ -960,7 +968,7 @@ public class JavaStubGenerator {
             val = ((Expression) memberValue).getText();
         } else if (memberValue instanceof VariableExpression) {
             val = ((Expression) memberValue).getText();
-            //check for an alias
+            // check for an alias
             ImportNode alias = currentModule.getStaticImports().get(val);
             if (alias != null)
                 val = alias.getClassName() + "." + alias.getFieldName();
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10122pt2.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10122pt2.groovy
new file mode 100644
index 0000000..cf7b245
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10122pt2.groovy
@@ -0,0 +1,54 @@
+/*
+ *  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 Groovy10122pt2 extends StringSourcesStubTestCase {
+
+    @Override
+    Map<String, String> provideSources() {
+        [
+            'A.java': '''
+                public abstract class A<T> {
+                    A(T t) {
+                    }
+                }
+            ''',
+            'C.groovy': '''
+                class C<T> extends A<T> {
+                    C(T t) {
+                        super(t)
+                    }
+                }
+            ''',
+            'Main.java': '''
+                public class Main {
+                    public static void main(String[] args) {
+                        new C(null);
+                    }
+                }
+            ''',
+        ]
+    }
+
+    @Override
+    void verifyStubs() {
+        def specialCtorCall = (stubJavaSourceFor('C') =~ /super\s*\((.+?)\);/)
+        assert specialCtorCall.find() && specialCtorCall.group(1) == '(T)null'
+    }
+}
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10464.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10464.groovy
new file mode 100644
index 0000000..38760a8
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10464.groovy
@@ -0,0 +1,52 @@
+/*
+ *  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 Groovy10464 extends StringSourcesStubTestCase {
+
+    @Override
+    Map<String, String> provideSources() {
+        [
+            'C.groovy': '''
+                public abstract class A<B> {
+                    A(Class<B> class_of_b) {
+                    }
+                }
+                class C extends A<String> {
+                    C() {
+                        super(String.class)
+                    }
+                }
+            ''',
+            '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.Class<java.lang.String>)null'
+    }
+}
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10464pt2.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10464pt2.groovy
new file mode 100644
index 0000000..bef8ae4
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10464pt2.groovy
@@ -0,0 +1,54 @@
+/*
+ *  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 Groovy10464pt2 extends StringSourcesStubTestCase {
+
+    @Override
+    Map<String, String> provideSources() {
+        [
+            'A.java': '''
+                public abstract class A<B> {
+                    A(Class<B> class_of_b) {
+                    }
+                }
+            ''',
+            'C.groovy': '''
+                class C extends A<String> {
+                    C() {
+                        super(String)
+                    }
+                }
+            ''',
+            '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.Class)null'
+    }
+}