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/17 16:01:01 UTC

[groovy] branch GROOVY_3_0_X updated (05e8066 -> ab42daf)

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 05e8066  GROOVY-10191: catch LinkageError during static inline
     new ee5d20e  GROOVY-9945: findParameterizedType: fill type parameters of super types
     new ab42daf  GROOVY-10196: add test case

The 2 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:
 .../codehaus/groovy/ast/tools/GenericsUtils.java   | 153 +++----
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  38 ++
 .../groovy/ast/tools/GenericsUtilsTest.groovy      | 443 +++++++++------------
 3 files changed, 296 insertions(+), 338 deletions(-)

[groovy] 01/02: GROOVY-9945: findParameterizedType: fill type parameters of super types

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 ee5d20ecdbb2313cf23690fb1597fc3598c7cb2b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Feb 16 15:10:04 2021 -0600

    GROOVY-9945: findParameterizedType: fill type parameters of super types
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   | 153 +++----
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  17 +
 .../groovy/ast/tools/GenericsUtilsTest.groovy      | 443 +++++++++------------
 3 files changed, 275 insertions(+), 338 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index bea8533..eddfb9d 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -43,11 +43,13 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
@@ -704,108 +706,78 @@ public class GenericsUtils {
 
     /**
      * Try to get the parameterized type from the cache.
-     * If no cached item found, cache and return the result of {@link #findParameterizedType(ClassNode, ClassNode, boolean)}
+     * <p>
+     * If no cached item found, cache and return the result of {@link #findParameterizedType(ClassNode,ClassNode,boolean)}
      */
     public static ClassNode findParameterizedTypeFromCache(final ClassNode genericsClass, final ClassNode actualType, boolean tryToFindExactType) {
         if (!PARAMETERIZED_TYPE_CACHE_ENABLED) {
             return findParameterizedType(genericsClass, actualType, tryToFindExactType);
         }
 
-        SoftReference<ClassNode> sr = PARAMETERIZED_TYPE_CACHE.getAndPut(new ParameterizedTypeCacheKey(genericsClass, actualType), key -> new SoftReference<>(findParameterizedType(key.getGenericsClass(), key.getActualType(), tryToFindExactType)));
+        SoftReference<ClassNode> sr = PARAMETERIZED_TYPE_CACHE.getAndPut(
+                new ParameterizedTypeCacheKey(genericsClass, actualType),
+                key -> new SoftReference<>(findParameterizedType(key.getGenericsClass(), key.getActualType(), tryToFindExactType)));
 
-        return null == sr ? null : sr.get();
+        return sr == null ? null : sr.get();
     }
 
     /**
-     * Convenience method for {@link #findParameterizedType(ClassNode, ClassNode, boolean)}
-     * when the {@code tryToFindExactType} boolean is {@code false}.
+     * Convenience method for {@link #findParameterizedType(ClassNode,ClassNode,boolean)} when {@code tryToFindExactType} is {@code false}.
      */
     public static ClassNode findParameterizedType(final ClassNode genericsClass, final ClassNode actualType) {
         return findParameterizedType(genericsClass, actualType, false);
     }
 
     /**
-     * Get the parameterized type by searching the whole class hierarchy according to generics class and actual receiver.
-     * {@link #findParameterizedTypeFromCache(ClassNode, ClassNode, boolean)} is strongly recommended for better performance.
-     *
-     * @param genericsClass the generics class
-     * @param actualType the actual type
-     * @param tryToFindExactType whether to try to find exact type
-     * @return the parameterized type
+     * Gets the parameterized type by searching the whole class hierarchy according to generics class and actual receiver.
+     * <p>
+     * {@link #findParameterizedTypeFromCache(ClassNode,ClassNode,boolean)} is strongly recommended for better performance.
      */
-    public static ClassNode findParameterizedType(ClassNode genericsClass, ClassNode actualType, boolean tryToFindExactType) {
-        ClassNode parameterizedType = null;
-
-        if (null == genericsClass.getGenericsTypes()) {
-            return parameterizedType;
+    public static ClassNode findParameterizedType(final ClassNode genericsClass, final ClassNode actualType, final boolean tryToFindExactType) {
+        final GenericsType[] genericsTypes = genericsClass.getGenericsTypes();
+        if (genericsTypes == null || genericsClass.isGenericsPlaceHolder()) {
+            return null;
         }
 
-        GenericsType[] declaringGenericsTypes = genericsClass.getGenericsTypes();
-
-        List<ClassNode> classNodeList = new LinkedList<>(getAllSuperClassesAndInterfaces(actualType));
-        classNodeList.add(0, actualType);
-
-        LinkedList<ClassNode> parameterizedTypeCandidateList = new LinkedList<>();
-
-        for (ClassNode cn : classNodeList) {
-            if (cn == genericsClass) {
-                continue;
-            }
-
-            if (tryToFindExactType && null != cn.getGenericsTypes() && hasNonPlaceHolders(cn)) {
-                parameterizedTypeCandidateList.add(cn);
-            }
+        if (actualType.equals(genericsClass)) {
+            return actualType;
+        }
 
-            if (!(genericsClass.equals(cn.redirect()))) {
-                continue;
-            }
+        LinkedList<ClassNode> todo = new LinkedList<>();
+        Set<ClassNode> done = new HashSet<>();
+        todo.add(actualType);
+        ClassNode type;
 
-            if (isGenericsTypeArraysLengthEqual(declaringGenericsTypes, cn.getGenericsTypes())) {
-                parameterizedType = cn;
-                break;
+        while ((type = todo.poll()) != null) {
+            if (type.equals(genericsClass)) {
+                return type;
             }
-        }
-
-        if (null == parameterizedType) {
-            if (!parameterizedTypeCandidateList.isEmpty()) {
-                parameterizedType = parameterizedTypeCandidateList.getLast();
+            if (done.add(type)) {
+                boolean parameterized = (type.getGenericsTypes() != null);
+                for (ClassNode cn : type.getInterfaces()) {
+                    if (parameterized)
+                        cn = parameterizeType(type, cn);
+                    todo.add(cn);
+                }
+                if (!actualType.isInterface()) {
+                    ClassNode cn = type.getUnresolvedSuperClass();
+                    if (cn != null && cn.redirect() != ClassHelper.OBJECT_TYPE) {
+                        if (parameterized)
+                            cn = parameterizeType(type, cn);
+                        todo.add(cn);
+                    }
+                }
             }
         }
 
-        return parameterizedType;
-    }
-
-    private static boolean isGenericsTypeArraysLengthEqual(GenericsType[] declaringGenericsTypes, GenericsType[] actualGenericsTypes) {
-        return null != actualGenericsTypes && declaringGenericsTypes.length == actualGenericsTypes.length;
-    }
-
-    private static List<ClassNode> getAllSuperClassesAndInterfaces(ClassNode actualReceiver) {
-        List<ClassNode> superClassAndInterfaceList = new LinkedList<>();
-        List<ClassNode> allSuperClassNodeList = getAllUnresolvedSuperClasses(actualReceiver);
-        superClassAndInterfaceList.addAll(allSuperClassNodeList);
-        superClassAndInterfaceList.addAll(actualReceiver.getAllInterfaces());
-
-        for (ClassNode superClassNode : allSuperClassNodeList) {
-            superClassAndInterfaceList.addAll(superClassNode.getAllInterfaces());
-        }
-
-        return superClassAndInterfaceList;
-    }
-
-    private static List<ClassNode> getAllUnresolvedSuperClasses(ClassNode actualReceiver) {
-        List<ClassNode> superClassNodeList = new LinkedList<>();
-
-        for (ClassNode cn = actualReceiver.getUnresolvedSuperClass(); null != cn && ClassHelper.OBJECT_TYPE != cn; cn = cn.getUnresolvedSuperClass()) {
-            superClassNodeList.add(cn);
-        }
-
-        return superClassNodeList;
+        return null;
     }
 
     private static final EvictableCache<ParameterizedTypeCacheKey, SoftReference<ClassNode>> PARAMETERIZED_TYPE_CACHE = new ConcurrentSoftCache<>(64);
 
     /**
-     * Clear the parameterized type cache
+     * Clears the parameterized type cache.
+     * <p>
      * It is useful to IDE as the type being compiled are continuously being edited/altered, see GROOVY-8675
      */
     public static void clearParameterizedTypeCache() {
@@ -825,7 +797,7 @@ public class GenericsUtils {
      * The resolved types can not help us to choose methods correctly if the argument is a string:  T: Object, S: Serializable
      * so we need actual types:  T: String, S: Long
      */
-    public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMap(ClassNode declaringClass, ClassNode actualReceiver) {
+    public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver) {
         return doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, false).getV1();
     }
 
@@ -837,38 +809,33 @@ public class GenericsUtils {
      * @param declaringClass the generics class node declaring the generics types
      * @param actualReceiver the sub-class class node
      * @return the placeholder-to-actualtype mapping
+     *
      * @since 3.0.0
      */
-    public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(ClassNode declaringClass, ClassNode actualReceiver) {
-        List<ClassNode> parameterizedTypeList = new LinkedList<>();
-
-        Map<GenericsType, GenericsType> result = makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClass, actualReceiver, parameterizedTypeList);
-
-        return connectGenericsTypes(result);
+    public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(final ClassNode declaringClass, final ClassNode actualReceiver) {
+        return makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClass, actualReceiver, new HashSet<>());
     }
 
-    private static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(ClassNode declaringClass, ClassNode actualReceiver, List<ClassNode> parameterizedTypeList) {
-        Tuple2<Map<GenericsType, GenericsType>, ClassNode> resultAndParameterizedTypeTuple = doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, true);
-        ClassNode parameterizedType = resultAndParameterizedTypeTuple.getV2();
-        Map<GenericsType, GenericsType> result = resultAndParameterizedTypeTuple.getV1();
+    private static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(final ClassNode declaringClass, final ClassNode actualReceiver, final Set<ClassNode> parameterizedTypes) {
+        Tuple2<Map<GenericsType, GenericsType>, ClassNode> tuple = doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, true);
+        Map<GenericsType, GenericsType> result = tuple.getV1();
+        ClassNode parameterizedType = tuple.getV2();
 
-        if (hasPlaceHolders(parameterizedType) && !parameterizedTypeList.contains(parameterizedType)) {
-            parameterizedTypeList.add(parameterizedType);
-            result.putAll(makeDeclaringAndActualGenericsTypeMapOfExactType(parameterizedType, actualReceiver, parameterizedTypeList));
+        if (parameterizedTypes.add(parameterizedType) && hasPlaceHolders(parameterizedType)) {
+            result.putAll(makeDeclaringAndActualGenericsTypeMapOfExactType(parameterizedType, actualReceiver, parameterizedTypes));
+            result = connectGenericsTypes(result);
         }
 
-        return connectGenericsTypes(result);
+        return result;
     }
 
-    private static Tuple2<Map<GenericsType, GenericsType>, ClassNode> doMakeDeclaringAndActualGenericsTypeMap(ClassNode declaringClass, ClassNode actualReceiver, boolean tryToFindExactType) {
+    private static Tuple2<Map<GenericsType, GenericsType>, ClassNode> doMakeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver, final boolean tryToFindExactType) {
         ClassNode parameterizedType = findParameterizedTypeFromCache(declaringClass, actualReceiver, tryToFindExactType);
-
-        if (null == parameterizedType) {
+        if (parameterizedType == null) {
             return tuple(Collections.emptyMap(), parameterizedType);
         }
 
         Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
-
         result.putAll(makePlaceholderAndParameterizedTypeMap(declaringClass));
         result.putAll(makePlaceholderAndParameterizedTypeMap(parameterizedType));
 
@@ -877,7 +844,7 @@ public class GenericsUtils {
         return tuple(result, parameterizedType);
     }
 
-    private static Map<GenericsType, GenericsType> makePlaceholderAndParameterizedTypeMap(ClassNode declaringClass) {
+    private static Map<GenericsType, GenericsType> makePlaceholderAndParameterizedTypeMap(final ClassNode declaringClass) {
         if (null == declaringClass) {
             return Collections.emptyMap();
         }
@@ -897,7 +864,7 @@ public class GenericsUtils {
         return result;
     }
 
-    private static Map<GenericsType, GenericsType> connectGenericsTypes(Map<GenericsType, GenericsType> genericsTypeMap) {
+    private static Map<GenericsType, GenericsType> connectGenericsTypes(final Map<GenericsType, GenericsType> genericsTypeMap) {
         Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
 
         outer:
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index be9319e..bfe7836 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -769,6 +769,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-9945
+    void testShouldUseMethodGenericType9() {
+        assertScript '''
+            interface I<T> {
+            }
+            class A<T> implements I<String> {
+                def m(T t) { 'works' }
+            }
+            class B<T> extends A<T> {
+            }
+
+            def bee = new B<Float>()
+            def obj = bee.m(3.14f)
+            assert obj == 'works'
+        '''
+    }
+
     // GROOVY-5516
     void testAddAllWithCollectionShouldBeAllowed() {
         assertScript '''import org.codehaus.groovy.transform.stc.ExtensionMethodNode
diff --git a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
index 598b5ce..1b30f71 100644
--- a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
@@ -19,307 +19,260 @@
 
 package org.codehaus.groovy.ast.tools
 
-import groovy.test.GroovyTestCase
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.ast.GenericsType
-import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.Phases
+import org.codehaus.groovy.control.CompilePhase
+import org.junit.Test
 
-import java.util.function.BiFunction
+final class GenericsUtilsTest {
 
-import static groovy.lang.Tuple.tuple
+    private static List<ClassNode> compile(String code) {
+        def compiler = new org.codehaus.groovy.ast.builder.AstStringCompiler()
+        compiler.compile(code, CompilePhase.SEMANTIC_ANALYSIS, false).tail()
+    }
+
+    private static ClassNode findClassNode(String name, List<ClassNode> list) {
+        list.find { it.name == name }
+    }
 
-class GenericsUtilsTest extends GroovyTestCase {
+    //--------------------------------------------------------------------------
+
+    @Test
     void testFindParameterizedType1() {
-        def code = '''
-        class Base<T, S> {}
-        class Derived extends Base<String, List> {}
+        def classNodeList = compile '''
+            class Base<T, S> {}
+            class Derived extends Base<String, List> {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
+    @Test
     void testFindParameterizedType2() {
-        def code = '''
-        class Base<T, S> {}
-        class Derived2 extends Base<String, List> {}
-        class Derived extends Derived2 {}
+        def classNodeList = compile '''
+            class Base<T, S> {}
+            class Derived2 extends Base<String, List> {}
+            class Derived extends Derived2 {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
+    @Test
     void testFindParameterizedType3() {
-        def code = '''
-        class Base0 {}
-        class Base<T, S> extends Base0 {}
-        class Derived2 extends Base<String, List> {}
-        class Derived extends Derived2 {}
+        def classNodeList = compile '''
+            class Base0 {}
+            class Base<T, S> extends Base0 {}
+            class Derived2 extends Base<String, List> {}
+            class Derived extends Derived2 {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
+    @Test
     void testFindParameterizedType4() {
-        def code = '''
-        interface Base<T, S> {}
-        class Derived2 implements Base<String, List> {}
-        class Derived extends Derived2 {}
+        def classNodeList = compile '''
+            interface Base<T, S> {}
+            class Derived2 implements Base<String, List> {}
+            class Derived extends Derived2 {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
+    @Test
     void testFindParameterizedType5() {
-        def code = '''
-        interface Base<T, S> {}
-        interface Base2 extends Base<String, List> {}
-        class Derived2 implements Base2 {}
-        class Derived extends Derived2 {}
+        def classNodeList = compile '''
+            interface Base<T, S> {}
+            interface Base2 extends Base<String, List> {}
+            class Derived2 implements Base2 {}
+            class Derived extends Derived2 {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
+    @Test
     void testFindParameterizedType6() {
-        def code = '''
-        interface Base<T, S> {}
-        interface Base2 extends Base<String, List> {}
-        class Derived2 implements Base2 {}
-        class Derived3 extends Derived2 {}
-        class Derived extends Derived3 {}
+        def classNodeList = compile '''
+            interface Base<T, S> {}
+            interface Base2 extends Base<String, List> {}
+            class Derived2 implements Base2 {}
+            class Derived3 extends Derived2 {}
+            class Derived extends Derived3 {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
+    @Test
     void testFindParameterizedType7() {
-        def code = '''
-        interface Base0 {}
-        interface Base<T, S> extends Base0 {}
-        interface Base2 extends Base<String, List> {}
-        class Derived2 implements Base2 {}
-        class Derived3 extends Derived2 {}
-        class Derived extends Derived3 {}
+        def classNodeList = compile '''
+            interface Base0 {}
+            interface Base<T, S> extends Base0 {}
+            interface Base2 extends Base<String, List> {}
+            class Derived2 implements Base2 {}
+            class Derived3 extends Derived2 {}
+            class Derived extends Derived3 {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('Base', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        ClassNode parameterizedClass = GenericsUtils.findParameterizedType(genericsClass, actualReceiver, false)
-        assert parameterizedClass.isUsingGenerics()
-        assert 'Base' == parameterizedClass.name
-        GenericsType[] genericsTypes = parameterizedClass.getGenericsTypes()
-        assert 2 == genericsTypes.length
-        assert 'java.lang.String' == genericsTypes[0].type.name
-        assert 'java.util.List' == genericsTypes[1].type.name
-        assert genericsClass.is(parameterizedClass.redirect())
+        ClassNode target = findClassNode('Base', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
+
+        assert 'Base' == result.name
+        assert result.isUsingGenerics()
+        assert 2 == result.genericsTypes.length
+        assert 'java.lang.String' == result.genericsTypes[0].type.name
+        assert 'java.util.List'   == result.genericsTypes[1].type.name
+        assert target === result.redirect()
     }
 
-    void testMakeDeclaringAndActualGenericsTypeMapOfExactType() {
-        def code = '''
-        import java.util.function.*
-        interface Derived extends BinaryOperator<Integer> {}
+    @Test // GROOVY-9945
+    void testFindParameterizedType8() {
+        def classNodeList = compile '''
+            interface I<T> {}
+            class A<T> implements I<String> {}
+            class B<T> extends A<T> {}
+            class C extends B<Number> {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
+        ClassNode target = findClassNode('A', classNodeList)
+        ClassNode source = findClassNode('C', classNodeList)
+        ClassNode result = GenericsUtils.findParameterizedType(target, source)
 
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = ClassHelper.makeWithoutCaching(BiFunction.class)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
+        assert result.toString(false) == 'A <java.lang.Number>'
+    }
+
+    @Test
+    void testMakeDeclaringAndActualGenericsTypeMapOfExactType() {
+        def classNodeList = compile '''
+            import java.util.function.*
+            interface Derived extends BinaryOperator<Integer> {}
+        '''
+        ClassNode target = ClassHelper.makeWithoutCaching(java.util.function.BiFunction.class)
+        ClassNode source = findClassNode('Derived', classNodeList)
 
-        Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(genericsClass, actualReceiver)
+        Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(target, source)
 
-        assert m.entrySet().every { it.value.type.getTypeClass() == Integer }
-        assert m.entrySet().grep { it.key.name == 'T' }[0].value.type.getTypeClass() == Integer
-        assert m.entrySet().grep { it.key.name == 'U' }[0].value.type.getTypeClass() == Integer
-        assert m.entrySet().grep { it.key.name == 'R' }[0].value.type.getTypeClass() == Integer
+        assert m.entrySet().find { it.key.name == 'T' }.value.type.name == 'java.lang.Integer'
+        assert m.entrySet().find { it.key.name == 'U' }.value.type.name == 'java.lang.Integer'
+        assert m.entrySet().find { it.key.name == 'R' }.value.type.name == 'java.lang.Integer'
     }
 
+    @Test
     void testMakeDeclaringAndActualGenericsTypeMapOfExactType2() {
-        def code = '''
-        interface IBase<T, U> {}
-        class Base<U> implements IBase<String, U> {}
-        class Derived extends Base<Integer> {}
+        def classNodeList = compile '''
+            interface IBase<T, U> {}
+            class Base<U> implements IBase<String, U> {}
+            class Derived extends Base<Integer> {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
+        ClassNode target = findClassNode('IBase', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
 
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('IBase', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
+        Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(target, source)
 
-        Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(genericsClass, actualReceiver)
-
-        assert m.entrySet().grep { it.key.name == 'T' }[0].value.type.getTypeClass() == String
-        assert m.entrySet().grep { it.key.name == 'U' }[0].value.type.getTypeClass() == Integer
+        assert m.entrySet().find { it.key.name == 'T' }.value.type.name == 'java.lang.String'
+        assert m.entrySet().find { it.key.name == 'U' }.value.type.name == 'java.lang.Integer'
+        assert m.size() == 2
     }
 
+    @Test
     void testMakeDeclaringAndActualGenericsTypeMapOfExactType3() {
-        def code = '''
-        interface IBase<T, U, R> {}
-        class Base<X, Y> implements IBase<Y, String, X> {}
-        class Derived extends Base<Boolean, Integer> {}
+        def classNodeList = compile '''
+            interface IBase<T, U, R> {}
+            class Base<X,Y> implements IBase<Y,String,X> {}
+            class Derived extends Base<Boolean, Integer> {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode genericsClass = findClassNode('IBase', classNodeList)
-        ClassNode actualReceiver = findClassNode('Derived', classNodeList)
-
-        Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(genericsClass, actualReceiver)
-        println m
-
-        assert m.entrySet().grep { it.key.name == 'X' }[0].value.type.getTypeClass() == Boolean
-        assert m.entrySet().grep { it.key.name == 'Y' }[0].value.type.getTypeClass() == Integer
-        assert m.entrySet().grep { it.key.name == 'T' }[0].value.type.getTypeClass() == Integer
-        assert m.entrySet().grep { it.key.name == 'U' }[0].value.type.getTypeClass() == String
-        assert m.entrySet().grep { it.key.name == 'R' }[0].value.type.getTypeClass() == Boolean
-    }
+        ClassNode target = findClassNode('IBase', classNodeList)
+        ClassNode source = findClassNode('Derived', classNodeList)
+
+        Map<GenericsType, GenericsType> m = GenericsUtils.makeDeclaringAndActualGenericsTypeMapOfExactType(target, source)
 
-    static ClassNode findClassNode(String name, List<ClassNode> classNodeList) {
-        return classNodeList.find { it.name == name }
+        assert m.entrySet().find { it.key.name == 'R' }.value.type.name == 'java.lang.Boolean'
+        assert m.entrySet().find { it.key.name == 'T' }.value.type.name == 'java.lang.Integer'
+        assert m.entrySet().find { it.key.name == 'U' }.value.type.name == 'java.lang.String'
+        assert m.size() == 3
     }
 
+    @Test
     void testParameterizeSAM() {
-        def code = '''
-        import java.util.function.*
-        interface T extends Function<String, Integer> {}
+        def classNodeList = compile '''
+            import java.util.function.*
+            interface T extends Function<String, Integer> {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode parameterizedClassNode = findClassNode('T', classNodeList).getAllInterfaces().find { it.name.equals('java.util.function.Function') }
-
-        Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(parameterizedClassNode)
-        assert 1 == typeInfo.getV1().length
-        assert ClassHelper.STRING_TYPE == typeInfo.getV1()[0]
-        assert ClassHelper.Integer_TYPE == typeInfo.getV2()
+        ClassNode samType = findClassNode('T', classNodeList).interfaces.find { it.name == 'java.util.function.Function' }
+
+        def typeInfo = GenericsUtils.parameterizeSAM(samType)
+
+        assert 1 == typeInfo[0].length
+        assert ClassHelper.STRING_TYPE == typeInfo[0][0]
+
+        assert ClassHelper.Integer_TYPE == typeInfo[1]
     }
 
+    @Test
     void testParameterizeSAM2() {
-        def code = '''
-        import java.util.function.*
-        interface T extends BinaryOperator<Integer> {}
+        def classNodeList = compile '''
+            import java.util.function.*
+            interface T extends BinaryOperator<Integer> {}
         '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode parameterizedClassNode = findClassNode('T', classNodeList).getAllInterfaces().find { it.name.equals('java.util.function.BinaryOperator') }
-
-        Tuple2<ClassNode[], ClassNode> typeInfo = GenericsUtils.parameterizeSAM(parameterizedClassNode)
-        assert 2 == typeInfo.getV1().length
-        assert ClassHelper.Integer_TYPE == typeInfo.getV1()[0]
-        assert ClassHelper.Integer_TYPE == typeInfo.getV1()[1]
-        assert ClassHelper.Integer_TYPE == typeInfo.getV2()
+        ClassNode samType = findClassNode('T', classNodeList).interfaces.find { it.name == 'java.util.function.BinaryOperator' }
+
+        def typeInfo = GenericsUtils.parameterizeSAM(samType)
+
+        assert 2 == typeInfo[0].length
+        assert ClassHelper.Integer_TYPE == typeInfo[0][0]
+        assert ClassHelper.Integer_TYPE == typeInfo[0][1]
+
+        assert ClassHelper.Integer_TYPE == typeInfo[1]
     }
 }

[groovy] 02/02: GROOVY-10196: add test case

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 ab42daf603d2a7f4ca520d66ad1a2ad21d7e6cf1
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Aug 17 10:18:10 2021 -0500

    GROOVY-10196: add test case
---
 .../groovy/transform/stc/GenericsSTCTest.groovy     | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index bfe7836..3d47868 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1566,6 +1566,27 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10196
+    void testShouldFindMethodEvenWithRepeatNames() {
+        assertScript '''
+            interface M<K,V> {
+            }
+            interface MM<K,V> extends M<K,List<V>> {
+                void add(K key, V val)
+            }
+            class MMA<K,V> implements MM<K,V> {
+                @Override
+                void add(K key, V val) {
+                }
+            }
+            class LMM<K,V> extends MMA<K,V> {
+            }
+
+            MM<String,String> map = new LMM<>()
+            map.add('foo','bar')
+        '''
+    }
+
     // GROOVY-5893
     @NotYetImplemented
     void testPlusInClosure() {