blob: 5082227f80aa57fc4051ffda1a724ab62ac335d6 [file] [log] [blame]
/*
* Copyright 2009 Google Inc.
*
* Licensed 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 com.google.gwt.dev.jjs;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JNonNullType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JTypeOracle;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Test basic operations on the types used by the JJS compiler. See
* {@link com.google.gwt.dev.jjs.ast.JType}.
*/
public class JjsTypeTest extends TestCase {
private JArrayType arrayOfA;
private JArrayType arrayOfArrayOfB;
private JReferenceType arrayOfArrayOfInt;
private JArrayType arrayOfB;
private JArrayType arrayOfBSub;
private JArrayType arrayOfC;
private JReferenceType arrayOfInt;
private JArrayType arrayOfObject;
private JClassType classA;
private JClassType classB;
private JClassType classBase;
private JNonNullType classBaseNn;
private JNonNullType classBnn;
private JClassType classBSub;
private JClassType classC;
private JClassType classJso;
private JClassType classJso1;
private JClassType classJso2;
private JClassType classObject;
private JClassType classString;
private JInterfaceType intfI;
private JInterfaceType intfIBase;
private JInterfaceType intfJ;
private JInterfaceType intfK;
private JProgram program;
private SourceInfo synthSource;
private JReferenceType typeNull;
private JTypeOracle typeOracle;
private JReferenceType intfSerializable;
private JReferenceType intfCloneable;
public void testCanTheoreticallyCast() {
assertFalse(typeOracle.canTheoreticallyCast(classBnn, typeNull));
assertTrue(typeOracle.canTheoreticallyCast(classBSub, classB));
assertTrue(typeOracle.canTheoreticallyCast(classB, classBSub));
assertTrue(typeOracle.canTheoreticallyCast(classB, classBnn));
assertTrue(typeOracle.canTheoreticallyCast(classBnn, classB));
assertTrue(typeOracle.canTheoreticallyCast(classB, classB));
assertTrue(typeOracle.canTheoreticallyCast(classObject, arrayOfB));
assertFalse(typeOracle.canTheoreticallyCast(arrayOfA, arrayOfArrayOfB));
assertTrue(typeOracle.canTheoreticallyCast(arrayOfObject, arrayOfArrayOfB));
assertTrue(typeOracle.canTheoreticallyCast(arrayOfB, arrayOfBSub));
assertTrue(typeOracle.canTheoreticallyCast(classBase, intfI));
assertFalse(typeOracle.canTheoreticallyCast(classA, intfJ));
assertTrue(typeOracle.canTheoreticallyCast(intfIBase, intfI));
assertTrue(typeOracle.canTheoreticallyCast(intfIBase, classBase));
assertFalse(typeOracle.canTheoreticallyCast(intfJ, classA));
assertTrue(typeOracle.canTheoreticallyCast(arrayOfA, intfSerializable));
assertTrue(typeOracle.canTheoreticallyCast(intfSerializable, arrayOfA));
assertTrue(typeOracle.canTheoreticallyCast(arrayOfA, intfCloneable));
assertTrue(typeOracle.canTheoreticallyCast(intfCloneable, arrayOfA));
}
public void testCanTriviallyCast() {
assertTrue(typeOracle.canTriviallyCast(classB, classB));
assertTrue(typeOracle.canTriviallyCast(classBSub, classB));
assertFalse(typeOracle.canTriviallyCast(classB, classBSub));
assertFalse(typeOracle.canTriviallyCast(classC, classA));
assertFalse(typeOracle.canTriviallyCast(classA, classC));
assertTrue(typeOracle.canTriviallyCast(classB, intfI));
assertFalse(typeOracle.canTriviallyCast(intfI, classB));
assertTrue(typeOracle.canTriviallyCast(classB, classObject));
assertFalse(typeOracle.canTriviallyCast(classObject, classB));
assertTrue(typeOracle.canTriviallyCast(classB, intfI));
assertFalse(typeOracle.canTriviallyCast(intfI, classB));
assertTrue(typeOracle.canTriviallyCast(classBnn, classB));
assertFalse(typeOracle.canTriviallyCast(classB, classBnn));
assertTrue(typeOracle.canTriviallyCast(typeNull, classB));
assertFalse(typeOracle.canTriviallyCast(classB, typeNull));
assertTrue(typeOracle.canTriviallyCast(arrayOfBSub, arrayOfB));
assertFalse(typeOracle.canTriviallyCast(arrayOfB, arrayOfBSub));
assertFalse(typeOracle.canTriviallyCast(arrayOfA, arrayOfB));
assertFalse(typeOracle.canTriviallyCast(arrayOfB, arrayOfA));
assertFalse(typeOracle.canTriviallyCast(arrayOfArrayOfB, arrayOfB));
assertFalse(typeOracle.canTriviallyCast(arrayOfB, arrayOfArrayOfB));
assertTrue(typeOracle.canTriviallyCast(arrayOfArrayOfB, arrayOfObject));
assertFalse(typeOracle.canTriviallyCast(arrayOfObject, arrayOfArrayOfB));
assertTrue(typeOracle.canTheoreticallyCast(classJso1, classJso2));
assertTrue(typeOracle.canTheoreticallyCast(classJso2, classJso1));
assertTrue(typeOracle.canTheoreticallyCast(classJso1, intfK));
assertTrue(typeOracle.canTheoreticallyCast(intfK, classJso1));
assertTrue(typeOracle.canTheoreticallyCast(intfJ, intfK));
assertTrue(typeOracle.canTheoreticallyCast(intfK, intfJ));
assertTrue(typeOracle.canTriviallyCast(classJso1, classJso));
assertTrue(typeOracle.canTriviallyCast(arrayOfA, intfSerializable));
assertFalse(typeOracle.canTriviallyCast(intfSerializable, arrayOfA));
assertTrue(typeOracle.canTriviallyCast(arrayOfA, intfCloneable));
assertFalse(typeOracle.canTriviallyCast(intfCloneable, arrayOfA));
/*
* Test that two types cannot both be trivially castable to each other,
* unless they are the same type.
*/
for (JReferenceType type1 : severalTypes()) {
for (JReferenceType type2 : severalTypes()) {
if (type1 != type2) {
assertFalse(typeOracle.canTriviallyCast(type1, type2)
&& typeOracle.canTriviallyCast(type2, type1));
}
}
}
}
public void testGeneralizeTypes() {
assertSame(classA, generalizeTypes(classA, classA));
assertSame(classB, generalizeTypes(classB, classBnn));
assertSame(classB, generalizeTypes(classBnn, classB));
assertSame(classBaseNn, generalizeTypes(classBnn, classBaseNn));
assertSame(classB, generalizeTypes(classB, typeNull));
assertSame(classB, generalizeTypes(typeNull, classB));
assertSame(intfIBase, generalizeTypes(intfI, intfIBase));
assertSame(intfIBase, generalizeTypes(intfIBase, intfI));
assertSame(classObject, generalizeTypes(intfJ, intfI));
assertSame(classObject, generalizeTypes(arrayOfB, arrayOfInt));
assertSame(classObject, generalizeTypes(arrayOfC, arrayOfArrayOfB));
assertSame(arrayOfObject, generalizeTypes(arrayOfC, arrayOfB));
assertSame(arrayOfObject, generalizeTypes(arrayOfObject, arrayOfArrayOfInt));
assertSame(intfI, generalizeTypes(classB, intfI));
assertSame(classObject, generalizeTypes(classB, intfJ));
assertSame(classObject, generalizeTypes(intfI, arrayOfInt));
assertSame(intfSerializable, generalizeTypes(intfSerializable, arrayOfA));
assertSame(intfCloneable, generalizeTypes(intfCloneable, arrayOfA));
for (JReferenceType type1 : severalTypes()) {
for (JReferenceType type2 : severalTypes()) {
JReferenceType generalized = generalizeTypes(type1, type2);
assertTrue(typeOracle.canTriviallyCast(type1, generalized));
assertTrue(typeOracle.canTriviallyCast(type2, generalized));
}
}
}
public void testStrongerType() {
assertSame(classA, program.strongerType(classA, classA));
assertSame(classBnn, program.strongerType(classB, classBnn));
assertSame(classB, program.strongerType(classB, classBase));
assertSame(classB, program.strongerType(classBase, classB));
assertSame(intfI, program.strongerType(intfI, intfJ));
assertSame(arrayOfA, program.strongerType(intfSerializable, arrayOfA));
assertSame(arrayOfA, program.strongerType(intfCloneable, arrayOfA));
}
@Override
protected void setUp() {
createSampleProgram();
}
private JClassType createClass(String className, JClassType superClass,
boolean isAbstract, boolean isFinal) {
JClassType clazz = program.createClass(synthSource, className, isAbstract,
isFinal);
clazz.setSuperClass(superClass);
return clazz;
}
private JInterfaceType createInterface(String className) {
JInterfaceType intf = program.createInterface(synthSource, className);
return intf;
}
private void createSampleProgram() {
// Make the program itself
program = new JProgram();
typeOracle = program.typeOracle;
synthSource = program.createSourceInfoSynthetic(JjsTypeTest.class);
classObject = createClass("java.lang.Object", null, false, false);
classString = createClass("java.lang.String", classObject, false, true);
createClass("com.google.gwt.lang.Array", classObject, false, true);
classJso = createClass("com.google.gwt.core.client.JavaScriptObject",
classObject, false, false);
intfSerializable = createInterface("java.io.Serializable");
intfCloneable = createInterface("java.lang.Cloneable");
intfIBase = createInterface("IBase");
intfI = createInterface("I");
intfI.addImplements(intfIBase);
intfJ = createInterface("J");
intfK = createInterface("K");
classBase = createClass("Base", classObject, false, false);
classA = createClass("A", classBase, false, false);
classB = createClass("B", classBase, false, false);
classB.addImplements(intfI);
classC = createClass("C", classObject, false, false);
classC.addImplements(intfI);
classBSub = createClass("BSub", classB, false, false);
classJso1 = createClass("Jso1", classJso, false, false);
classJso1.addImplements(intfJ);
classJso2 = createClass("Jso2", classJso, false, false);
classJso2.addImplements(intfK);
program.typeOracle.computeBeforeAST();
// Save off some miscellaneous types to test against
typeNull = program.getTypeNull();
classBnn = classB.getNonNull();
classBaseNn = classBase.getNonNull();
arrayOfA = program.getTypeArray(classA);
arrayOfB = program.getTypeArray(classB);
arrayOfBSub = program.getTypeArray(classBSub);
arrayOfC = program.getTypeArray(classC);
arrayOfObject = program.getTypeArray(classObject);
arrayOfInt = program.getTypeArray(program.getTypePrimitiveInt());
arrayOfArrayOfInt = program.getTypeArray(program.getTypePrimitiveInt(), 2);
arrayOfArrayOfB = program.getTypeArray(classB, 2);
}
private JReferenceType generalizeTypes(JReferenceType type1,
JReferenceType type2) {
List<JReferenceType> types = new ArrayList<JReferenceType>(2);
types.add(type1);
types.add(type2);
return program.generalizeTypes(types);
}
/**
* Return several types, for exhaustively testing basic properties.
*/
private Collection<JReferenceType> severalTypes() {
List<JReferenceType> types = new ArrayList<JReferenceType>();
types.add(arrayOfA);
types.add(arrayOfB);
types.add(arrayOfArrayOfB);
types.add(arrayOfBSub);
types.add(arrayOfObject);
types.add(classA);
types.add(classB);
types.add(classBSub);
types.add(classBnn);
types.add(classBase);
types.add(classC);
types.add(classObject);
types.add(classString);
types.add(intfI);
types.add(intfJ);
types.add(intfK);
types.add(intfIBase);
types.add(classJso1);
types.add(classJso2);
types.add(classJso);
types.add(typeNull);
return types;
}
}