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/08/18 17:32:39 UTC

[groovy] 02/02: GROOVY-10102: trait SelfType: continue checking self type for self types

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 2c43daa690d12c1698778f72a09b66fb4eae3fb5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed May 26 09:48:31 2021 -0500

    GROOVY-10102: trait SelfType: continue checking self type for self types
    
    Conflicts:
    	src/test/groovy/transform/stc/BugsSTCTest.groovy
---
 .../codehaus/groovy/transform/trait/Traits.java    | 46 ++++++++-------
 src/test/groovy/transform/stc/BugsSTCTest.groovy   | 69 ++++++++++++++++------
 2 files changed, 75 insertions(+), 40 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
index e051ad2..a2c5110 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/Traits.java
@@ -298,13 +298,12 @@ public abstract class Traits {
      * Collects all the self types that a type should extend or implement, given
      * the traits is implements. Collects from interfaces and superclasses too.
      * @param receiver a class node that may implement a trait
-     * @param selfTypes a collection where the list of self types will be written
-     * @return the selfTypes collection itself
+     * @param selfTypes a set where the self types will be put
+     * @return the {@code selfTypes} collection
+     *
      * @since 2.4.0
      */
-    public static LinkedHashSet<ClassNode> collectSelfTypes(
-            ClassNode receiver,
-            LinkedHashSet<ClassNode> selfTypes) {
+    public static LinkedHashSet<ClassNode> collectSelfTypes(final ClassNode receiver, final LinkedHashSet<ClassNode> selfTypes) {
         return collectSelfTypes(receiver, selfTypes, true, true);
     }
 
@@ -312,28 +311,30 @@ public abstract class Traits {
      * Collects all the self types that a type should extend or implement, given
      * the traits is implements.
      * @param receiver a class node that may implement a trait
-     * @param selfTypes a collection where the list of self types will be written
+     * @param selfTypes a set where the self types will be put
      * @param checkInterfaces should the interfaces that the node implements be collected too
-     * @param checkSuper should we collect from the superclass too
-     * @return the selfTypes collection itself
+     * @param checkSuperClass should we collect from the superclass too
+     * @return the {@code selfTypes} collection
+     *
      * @since 2.4.0
      */
-    public static LinkedHashSet<ClassNode> collectSelfTypes(
-            ClassNode receiver,
-            LinkedHashSet<ClassNode> selfTypes,
-            boolean checkInterfaces,
-            boolean checkSuper) {
+    public static LinkedHashSet<ClassNode> collectSelfTypes(final ClassNode receiver, final LinkedHashSet<ClassNode> selfTypes, final boolean checkInterfaces, final boolean checkSuperClass) {
         if (Traits.isTrait(receiver)) {
             List<AnnotationNode> annotations = receiver.getAnnotations(SELFTYPE_CLASSNODE);
             for (AnnotationNode annotation : annotations) {
                 Expression value = annotation.getMember("value");
                 if (value instanceof ClassExpression) {
-                    selfTypes.add(value.getType());
+                    ClassNode selfType = value.getType();
+                    if (selfTypes.add(selfType)) {
+                        collectSelfTypes(selfType, selfTypes, checkInterfaces, checkSuperClass);
+                    }
                 } else if (value instanceof ListExpression) {
-                    List<Expression> expressions = ((ListExpression) value).getExpressions();
-                    for (Expression expression : expressions) {
+                    for (Expression expression : ((ListExpression) value).getExpressions()) {
                         if (expression instanceof ClassExpression) {
-                            selfTypes.add(expression.getType());
+                            ClassNode selfType = expression.getType();
+                            if (selfTypes.add(selfType)) {
+                                collectSelfTypes(selfType, selfTypes, checkInterfaces, checkSuperClass);
+                            }
                         }
                     }
                 }
@@ -341,14 +342,15 @@ public abstract class Traits {
         }
         if (checkInterfaces) {
             ClassNode[] interfaces = receiver.getInterfaces();
-            for (ClassNode anInterface : interfaces) {
-                collectSelfTypes(anInterface, selfTypes, true, checkSuper);
+            for (ClassNode interFace : interfaces) {
+                if (!selfTypes.contains(interFace)) {
+                    collectSelfTypes(interFace, selfTypes, true, checkSuperClass);
+                }
             }
         }
-
-        if (checkSuper) {
+        if (checkSuperClass) {
             ClassNode superClass = receiver.getSuperClass();
-            if (superClass != null) {
+            if (superClass != null && !superClass.equals(ClassHelper.OBJECT_TYPE)) {
                 collectSelfTypes(superClass, selfTypes, checkInterfaces, true);
             }
         }
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 887fc86..393845f 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -90,34 +90,67 @@ class BugsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-7929
     void testShouldDetectInvalidMethodUseWithinTraitWithCompileStaticAndSelfType() {
         shouldFailWithMessages '''
-            class C1 {
-                def c1() { }
+            class C {
+                def m() { }
             }
             @groovy.transform.CompileStatic
-            @groovy.transform.SelfType(C1)
-            trait TT {
-                def foo() {
-                    c2()
+            @groovy.transform.SelfType(C)
+            trait T {
+                void test() {
+                    x()
                 }
             }
-        ''', 'Cannot find matching method <UnionType:C1+TT>#c2'
+        ''', 'Cannot find matching method <UnionType:C+T>#x'
     }
 
-    void testGroovy5444() {
+    // GROOVY-10102
+    void testShouldDetectValidMethodUseWithinTraitWithCompileStaticAndSelfType() {
         assertScript '''
-                def curr = { System.currentTimeMillis() }
+            import groovy.transform.*
 
-                5.times {
-                    @ASTTest(phase=INSTRUCTION_SELECTION, value= {
-                        assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
-                    })
-                    def t0 = curr()
-                    100000.times {
-                        "echo"
+            trait A {
+                String foo = 'foo'
+                String m(String s, Closure x) {
+                    s + x()
+                }
+            }
+            @SelfType(A)
+            trait B {
+            }
+            @SelfType(B)
+            trait C {
+            }
+            @CompileStatic
+            @SelfType(C)
+            trait D {
+                def test() {
+                    String s = foo
+                    m(s) {
+                        s.toUpperCase()
                     }
-                    println (curr() - t0)
-                }'''
+                }
+            }
 
+            class E implements A, B, C, D { }
+            assert new E().test() == 'fooFOO'
+        '''
+    }
+
+    void testGroovy5444() {
+        assertScript '''
+            def millis = { System.currentTimeMillis() }
+
+            5.times {
+                @ASTTest(phase=INSTRUCTION_SELECTION, value= {
+                    assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE
+                })
+                def t0 = millis()
+                1000.times {
+                    "echo"
+                }
+                def elapsed = millis() - t0
+            }
+        '''
     }
 
     void testGroovy5487ReturnNull() {