You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/05/11 02:12:26 UTC
groovy git commit: Extract util method `findParameterizedType` and
change some error messages
Repository: groovy
Updated Branches:
refs/heads/master 936a7a9fc -> 62f5ce6ff
Extract util method `findParameterizedType` and change some error messages
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/62f5ce6f
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/62f5ce6f
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/62f5ce6f
Branch: refs/heads/master
Commit: 62f5ce6ffe8d0dad30808944201723e02d3666fd
Parents: 936a7a9
Author: sunlan <su...@apache.org>
Authored: Fri May 11 10:11:52 2018 +0800
Committer: sunlan <su...@apache.org>
Committed: Fri May 11 10:12:19 2018 +0800
----------------------------------------------------------------------
.../groovy/ast/tools/GenericsUtils.java | 65 ++++++
.../stc/StaticTypeCheckingSupport.java | 55 +----
.../groovy/transform/stc/GenericsSTCTest.groovy | 10 +-
.../groovy/ast/tools/GenericsUtilsTest.groovy | 212 +++++++++++++++++++
4 files changed, 288 insertions(+), 54 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/62f5ce6f/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
----------------------------------------------------------------------
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 31f6c6e..98057d0 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -43,6 +43,7 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@@ -649,4 +650,68 @@ public class GenericsUtils {
}
return newTypes;
}
+
+ /**
+ * Get the parameterized type by search the whole class hierarchy according to generics class and actual receiver
+ *
+ * @param genericsClass the generics class
+ * @param actualReceiver the actual receiver
+ * @return the parameterized type
+ */
+ public static ClassNode findParameterizedType(ClassNode genericsClass, ClassNode actualReceiver) {
+ ClassNode parameterizedType = null;
+
+ if (null == genericsClass.getGenericsTypes()) {
+ return parameterizedType;
+ }
+
+ GenericsType[] declaringGenericsTypes = genericsClass.getGenericsTypes();
+
+ List<ClassNode> classNodeList = new LinkedList<>(getAllSuperClassesAndInterfaces(actualReceiver));
+ classNodeList.add(0, actualReceiver);
+
+ for (ClassNode cn : classNodeList) {
+ if (cn == genericsClass) {
+ continue;
+ }
+
+ if (!genericsClass.equals(cn.redirect())) {
+ continue;
+ }
+
+ if (isGenericsTypeArraysLengthEqual(declaringGenericsTypes, cn.getGenericsTypes())) {
+ parameterizedType = cn;
+ break;
+ }
+ }
+
+ 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;
+ }
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/62f5ce6f/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index fa924a6..314473a 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -20,7 +20,6 @@
package org.codehaus.groovy.transform.stc;
import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.MethodNode;
@@ -62,6 +61,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
@@ -1216,32 +1216,16 @@ public abstract class StaticTypeCheckingSupport {
* so we need actual types: T: String, S: Long
*/
private static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMap(ClassNode declaringClass, ClassNode actualReceiver) {
- GenericsType[] declaringGenericsTypes = declaringClass.getGenericsTypes();
- GenericsType[] actualGenericsTypes = actualReceiver.getGenericsTypes();
+ ClassNode parameterizedType = GenericsUtils.findParameterizedType(declaringClass, actualReceiver);
- if (null == declaringGenericsTypes) {
+ if (null == parameterizedType) {
return Collections.emptyMap();
}
- if (null == actualGenericsTypes) {
- List<ClassNode> superClassAndInterfaceList = getAllSuperClassesAndInterfaces(actualReceiver);
-
- for (ClassNode cn : superClassAndInterfaceList) {
- if (declaringClass.equals(cn.redirect())) {
- actualGenericsTypes = cn.getGenericsTypes();
-
- if (isGenericsTypeArraysLengthEqual(declaringGenericsTypes, actualGenericsTypes)) {
- break;
- }
- }
- }
- }
-
- if (!isGenericsTypeArraysLengthEqual(declaringGenericsTypes, actualGenericsTypes)) {
- return Collections.emptyMap();
- }
+ GenericsType[] declaringGenericsTypes = declaringClass.getGenericsTypes();
+ GenericsType[] actualGenericsTypes = parameterizedType.getGenericsTypes();
- Map<GenericsType, GenericsType> result = new HashMap<>();
+ Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
for (int i = 0, n = declaringGenericsTypes.length; i < n; i++) {
result.put(declaringGenericsTypes[i], actualGenericsTypes[i]);
}
@@ -1249,33 +1233,6 @@ public abstract class StaticTypeCheckingSupport {
return result;
}
- 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;
- }
-
private static Parameter[] makeRawTypes(Parameter[] params, Map<GenericsType, GenericsType> genericsPlaceholderAndTypeMap) {
Parameter[] newParam = new Parameter[params.length];
for (int i = 0; i < params.length; i++) {
http://git-wip-us.apache.org/repos/asf/groovy/blob/62f5ce6f/src/test/groovy/transform/stc/GenericsSTCTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 9c42e3e..3a89bcb 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -116,14 +116,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
List<Integer> list = new LinkedList<>()
list.add 'Hello'
- ''', '[Static type checking] - Cannot find matching method java.util.LinkedList#add(java.lang.String)'
+ ''', '[Static type checking] - Cannot call java.util.LinkedList <java.lang.Integer>#add(java.lang.Integer) with arguments [java.lang.String]'
}
void testAddOnListWithDiamondAndWrongTypeUsingLeftShift() {
shouldFailWithMessages '''
List<Integer> list = new LinkedList<>()
list << 'Hello'
- ''', '[Static type checking] - Cannot find matching method java.util.LinkedList#leftShift(java.lang.String)'
+ ''', '[Static type checking] - Cannot call <T> java.util.LinkedList <java.lang.Integer>#leftShift(T) with arguments [java.lang.String]'
}
void testAddOnListWithDiamondAndNullUsingLeftShift() {
@@ -424,7 +424,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
shouldFailWithMessages '''
Map<String, Integer> map = new HashMap<String,Integer>()
map.put('hello', new Object())
- ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.lang.String, java.lang.Object)'
+ ''', '[Static type checking] - Cannot call java.util.HashMap <String, Integer>#put(java.lang.String, java.lang.Integer) with arguments [java.lang.String, java.lang.Object]'
}
void testPutMethodWithPrimitiveValueAndArrayPut() {
@@ -749,7 +749,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
})
Map<Date, Date> map = new HashMap<>()
map.put('foo', new Date())
- ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.lang.String, java.util.Date)'
+ ''', '[Static type checking] - Cannot call java.util.HashMap <java.util.Date, java.util.Date>#put(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]'
}
void testInferDiamondForAssignmentWithDatesAndIllegalKeyUsingSquareBracket() {
shouldFailWithMessages '''
@@ -787,7 +787,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
})
Map<Date, Date> map = new HashMap<>()
map.put(new Date(), 'foo')
- ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.util.Date, java.lang.String)'
+ ''', '[Static type checking] - Cannot call java.util.HashMap <java.util.Date, java.util.Date>#put(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]'
}
void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingSquareBracket() {
shouldFailWithMessages '''
http://git-wip-us.apache.org/repos/asf/groovy/blob/62f5ce6f/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
new file mode 100644
index 0000000..cf2fb49
--- /dev/null
+++ b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
@@ -0,0 +1,212 @@
+/*
+ * 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.ast.tools
+
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.GenericsType
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.Phases
+
+class GenericsUtilsTest extends GroovyTestCase {
+ void testFindParameterizedType1() {
+ def code = '''
+ 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)
+ 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())
+ }
+
+ void testFindParameterizedType2() {
+ def code = '''
+ 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)
+ 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())
+ }
+
+ void testFindParameterizedType3() {
+ def code = '''
+ 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)
+ 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())
+ }
+
+ void testFindParameterizedType4() {
+ def code = '''
+ 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)
+ 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())
+ }
+
+ void testFindParameterizedType5() {
+ def code = '''
+ 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)
+ 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())
+ }
+
+ 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 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)
+ 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())
+ }
+
+ 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 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)
+ 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())
+ }
+
+ static ClassNode findClassNode(String name, List<ClassNode> classNodeList) {
+ return classNodeList.find { it.name == name }
+ }
+}