Fix NullPointerException introduced by covariant array fix.
Happens when a root type is an array whose leaf type is a type parameter.
Review by: mdempsky@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11380 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
index 8c8f90f..6900fcf 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilder.java
@@ -1541,14 +1541,29 @@
* the given array's leaf type and its instantiable subtypes. (Note: this adds O(S * R)
* array types to the output where S is the number of subtypes and R is the rank.)
* Prerequisite: The leaf type's tic and its subtypes must already be created.
+ * @see #checkArrayInstantiable
*/
private void markArrayTypes(TreeLogger logger, JArrayType array, TypePath path,
ProblemReport problems) {
logger = logger.branch(TreeLogger.DEBUG, "Adding array types for " + array);
JType leafType = array.getLeafType();
+ JTypeParameter isLeafTypeParameter = leafType.isTypeParameter();
+ if (isLeafTypeParameter != null) {
+ if (typeParametersInRootTypes.contains(isLeafTypeParameter)) {
+ leafType = isLeafTypeParameter.getFirstBound(); // to match computeTypeInstantiability
+ } else {
+ // skip non-root leaf parameters, to match checkArrayInstantiable
+ return;
+ }
+ }
+
TypeInfoComputed leafTic = typeToTypeInfoComputed.get(leafType);
- assert leafTic != null : "not computed: " + leafType;
+ if (leafTic == null) {
+ problems.add(array, "internal error: leaf type not computed: " +
+ leafType.getQualifiedSourceName(), Priority.FATAL);
+ return;
+ }
JClassType leafClass = leafType.isClassOrInterface();
if (leafClass == null) {
diff --git a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
index ee3fcd1..556326e 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
@@ -50,6 +50,7 @@
import junit.framework.TestCase;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@@ -1932,7 +1933,24 @@
*/
public void testSubclassUsedInArray() throws NotFoundException, UnableToCompleteException {
JClassType expected = arrayType(SubclassUsedInArray.LeafType.class);
- checkSerializable(expected, SubclassUsedInArray.Base.class, SubclassUsedInArray.HasArray.class);
+ checkSerializable(expected,
+ eachJType(SubclassUsedInArray.Base.class, SubclassUsedInArray.HasArray.class));
+ }
+
+ /**
+ * Test the case where a root array type has a type parameter as its leaf.
+ */
+ public void testArrayOfTypeParameterExtendsSubclass() throws Exception {
+ JClassType expected = arrayType(SubclassUsedInArray.LeafType.class);
+
+ TypeOracle oracle = getTestTypeOracle();
+ JGenericType genericHasArray = oracle
+ .getType(SubclassUsedInArray.GenericHasArray.class.getCanonicalName()).isGenericType();
+ JTypeParameter typeParameter = genericHasArray.getTypeParameters()[0];
+
+ checkSerializable(expected,
+ oracle.getType(SubclassUsedInArray.Base.class.getCanonicalName()),
+ oracle.getArrayType(typeParameter));
}
/**
@@ -2038,7 +2056,7 @@
JClassType foo = to.getType("Foo");
JClassType bar = to.getType("Bar");
JClassType intfOfString =
- to.getParameterizedType(intf, new JClassType[] {to.getType(String.class.getName())});
+ to.getParameterizedType(intf, new JClassType[]{to.getType(String.class.getName())});
JClassType ser = to.getType("Ser");
SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(logger, to);
@@ -2312,7 +2330,7 @@
JTypeParameter typeParam = c.getTypeParameters()[0];
- JParameterizedType parameterizedType = to.getParameterizedType(a, new JClassType[] {typeParam});
+ JParameterizedType parameterizedType = to.getParameterizedType(a, new JClassType[]{typeParam});
SerializableTypeOracleBuilder sob = createSerializableTypeOracleBuilder(logger, to);
sob.addRootType(logger, parameterizedType);
SerializableTypeOracle so = sob.build(logger);
@@ -2381,12 +2399,12 @@
* Checks that a type is serializable when searching from the given roots.
* Also, check that the root order doesn't matter.
*/
- private void checkSerializable(JClassType expected, Class... roots)
+ private void checkSerializable(JClassType expected, JType... roots)
throws UnableToCompleteException {
+ roots = Arrays.copyOf(roots, roots.length);
// find serializable types in forward and reverse order
SerializableTypeOracle forwardResult = findSerializable(roots);
- roots = Arrays.copyOf(roots, roots.length);
Collections.reverse(Arrays.asList(roots));
SerializableTypeOracle reverseResult = findSerializable(roots);
@@ -2404,21 +2422,27 @@
checkSameSerializables(forwardResult, reverseResult);
}
- /**
- * Finds serializable types from the given roots (in order).
- */
- private SerializableTypeOracle findSerializable(Class... roots)
+ private SerializableTypeOracle findSerializable(JType... rootTypes)
throws UnableToCompleteException {
TreeLogger logger = createLogger();
TypeOracle oracle = getTestTypeOracle();
SerializableTypeOracleBuilder builder =
createSerializableTypeOracleBuilder(logger, oracle);
- for (Class root : roots) {
- builder.addRootType(logger, oracle.findType(root.getCanonicalName()));
+ for (JType root : rootTypes) {
+ builder.addRootType(logger, root);
}
return builder.build(logger);
}
+ private JType[] eachJType(Class... classes) throws UnableToCompleteException {
+ TypeOracle oracle = getTestTypeOracle();
+ List<JType> result = new ArrayList<JType>();
+ for (Class aClass : classes) {
+ result.add(oracle.findType(aClass.getCanonicalName()));
+ }
+ return result.toArray(new JType[result.size()]);
+ }
+
private void checkSameSerializables(SerializableTypeOracle first, SerializableTypeOracle second) {
String firstTypes = join("\n", first.getSerializableTypes());
String secondTypes = join("\n", second.getSerializableTypes());
diff --git a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/SubclassUsedInArray.java b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/SubclassUsedInArray.java
index 903e8d9..247875f 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/testcases/client/SubclassUsedInArray.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/testcases/client/SubclassUsedInArray.java
@@ -42,6 +42,11 @@
private Subtype[] array;
}
+ /** Used to create a type parameter with Subtype as its upper bound */
+ public static class GenericHasArray<T extends Subtype> implements Serializable {
+ private T[] array;
+ }
+
/** Just a field. */
public static class FieldType implements Serializable {
}