Adds support for Class.getSuperclass() needed to implement Enum.getDeclaringClass(). The corresponding test cases were updated accordingly.
Patch by: mmendez
Review by: scottb (postmortem, tweaked in r1605)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1590 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
index ba4fd33..ff8a95e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -55,10 +55,32 @@
JMethod method = program.getIndexedMethod(type.getClassLiteralFactoryMethod());
assert method != null;
- JMethodCall call = new JMethodCall(program, null, null,
- method);
+ JMethodCall call = new JMethodCall(program, null, null, method);
call.getArgs().add(program.getLiteralString(getPackageName(typeName)));
call.getArgs().add(program.getLiteralString(getClassName(typeName)));
+
+ if (type instanceof JClassType && !(type instanceof JArrayType)) {
+ /*
+ * For non-array classes and enums, determine the class literal of the
+ * supertype, if there is one. Arrays are excluded because they always
+ * have Object as their superclass.
+ */
+ assert (type instanceof JClassType);
+ JClassType classType = (JClassType) type;
+
+ JLiteral superclassLiteral;
+
+ if (classType.extnds != null) {
+ superclassLiteral = program.getLiteralClass(classType.extnds);
+ } else {
+ superclassLiteral = program.getLiteralNull();
+ }
+
+ call.getArgs().add(superclassLiteral);
+ } else {
+ assert (type instanceof JArrayType || type instanceof JInterfaceType ||
+ type instanceof JPrimitiveType);
+ }
classObjectAllocation = call;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index ef6877b..eaa2eb9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -22,6 +22,7 @@
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
import com.google.gwt.dev.jjs.ast.JArrayRef;
+import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
@@ -1150,16 +1151,43 @@
}
private void generateClassLiterals(JsVars vars) {
+ Set<JType> alreadyGenerated = new HashSet<JType>();
for (Object element : classLits.keySet()) {
JType type = (JType) element;
- JsName jsName = classLits.get(type);
- JsExpression classObjectAlloc = classObjects.get(jsName);
- JsVar var = new JsVar(jsName);
- var.setInitExpr(classObjectAlloc);
- vars.add(var);
+ generateClassLiteralsRecursive(alreadyGenerated, type, vars);
}
}
+ private void generateClassLiteralsRecursive(Set<JType> alreadyGenerated,
+ JType type, JsVars vars) {
+ if (alreadyGenerated.contains(type)) {
+ return;
+ }
+ alreadyGenerated.add(type);
+
+ if (type instanceof JClassType && !(type instanceof JArrayType)) {
+ /*
+ * If this type is a regular class or an enum, then ensure that its
+ * superclasses' class literal is generated before its own.
+ *
+ * NOTE: JInterfaceTypes can have their JReferenceType.extnds member
+ * set to its first implemented interface. JArrayTypes always have
+ * Object as their superclass so there is no need to explicitly set it
+ * here.
+ */
+ JClassType classType = (JClassType) type;
+ if (classType.extnds != null) {
+ generateClassLiteralsRecursive(alreadyGenerated, classType.extnds, vars);
+ }
+ }
+
+ JsName jsName = classLits.get(type);
+ JsExpression classObjectAlloc = classObjects.get(jsName);
+ JsVar var = new JsVar(jsName);
+ var.setInitExpr(classObjectAlloc);
+ vars.add(var);
+ }
+
private void generateClassSetup(JClassType x, List<JsStatement> globalStmts) {
generateSeedFuncAndPrototype(x, globalStmts);
generateVTables(x, globalStmts);
diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java
index b0630aa..2f5876a 100644
--- a/user/super/com/google/gwt/emul/java/lang/Class.java
+++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -38,6 +38,7 @@
Class<?> clazz = new Class();
clazz.typeName = packageName + className;
clazz.modifiers = ARRAY;
+ clazz.superclass = Object.class;
return clazz;
}
@@ -46,10 +47,11 @@
*
* @skip
*/
- static Class<?> createForClass(String packageName, String className) {
+ static Class<?> createForClass(String packageName, String className, Class<?> superclass) {
// Initialize here to avoid method inliner
Class<?> clazz = new Class<Object>();
clazz.typeName = packageName + className;
+ clazz.superclass = superclass;
return clazz;
}
@@ -58,11 +60,12 @@
*
* @skip
*/
- static Class<?> createForEnum(String packageName, String className) {
+ static Class<?> createForEnum(String packageName, String className, Class<?> superclass) {
// Initialize here to avoid method inliner
Class<?> clazz = new Class<Object>();
clazz.typeName = packageName + className;
clazz.modifiers = ENUM;
+ clazz.superclass = superclass;
return clazz;
}
@@ -96,6 +99,8 @@
private String typeName;
+ private Class<?> superclass;
+
/**
* Not publicly instantiable.
*
@@ -113,6 +118,10 @@
return typeName;
}
+ public Class<? super T> getSuperclass() {
+ return (Class<? super T>) superclass;
+ }
+
public boolean isArray() {
return (modifiers & ARRAY) != 0;
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Enum.java b/user/super/com/google/gwt/emul/java/lang/Enum.java
index 90ebc08..98272ed 100644
--- a/user/super/com/google/gwt/emul/java/lang/Enum.java
+++ b/user/super/com/google/gwt/emul/java/lang/Enum.java
@@ -69,8 +69,10 @@
}
public final Class<E> getDeclaringClass() {
- throw new UnsupportedOperationException(
- "Enum.getDeclaringClass() not yet implemented");
+ Class clazz = getClass();
+ Class superclass = clazz.getSuperclass();
+
+ return (superclass == Enum.class) ? clazz : superclass;
}
@Override
diff --git a/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java b/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java
index 511dc4f..7cd0685 100644
--- a/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/ClassObjectTest.java
@@ -39,6 +39,7 @@
public void testArray() {
Object o = new Foo[3];
assertEquals(Foo[].class, o.getClass());
+ assertEquals(Object.class, o.getClass().getSuperclass());
assertEquals("[Lcom.google.gwt.dev.jjs.test.ClassObjectTest$Foo;",
o.getClass().getName());
assertEquals("class [Lcom.google.gwt.dev.jjs.test.ClassObjectTest$Foo;",
@@ -56,6 +57,7 @@
public void testClass() {
Object o = new Foo();
assertEquals(Foo.class, o.getClass());
+ assertEquals(Object.class, o.getClass().getSuperclass());
assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Foo",
Foo.class.getName());
assertEquals("class com.google.gwt.dev.jjs.test.ClassObjectTest$Foo",
@@ -69,6 +71,7 @@
public void testEnum() {
Object o = Bar.BAR;
assertEquals(Bar.class, o.getClass());
+ assertEquals(Enum.class, o.getClass().getSuperclass());
assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
o.getClass().getName());
assertEquals("class com.google.gwt.dev.jjs.test.ClassObjectTest$Bar",
@@ -80,6 +83,7 @@
}
public void testInterface() {
+ assertNull(IFoo.class.getSuperclass());
assertEquals("com.google.gwt.dev.jjs.test.ClassObjectTest$IFoo",
IFoo.class.getName());
assertEquals("interface com.google.gwt.dev.jjs.test.ClassObjectTest$IFoo",
@@ -91,6 +95,7 @@
}
public void testPrimitive() {
+ assertNull(int.class.getSuperclass());
assertEquals("int", int.class.getName());
assertEquals("int", int.class.toString());
assertFalse(int.class.isArray());
diff --git a/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java b/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java
index 460ee10..e971fa7 100644
--- a/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/EnumsTest.java
@@ -87,6 +87,12 @@
assertEquals("Z", Complex.C.value);
}
+ public void testGetDeclaringClass() {
+ assertEquals(Basic.class, Basic.A.getDeclaringClass());
+ assertEquals(Complex.class, Complex.A.getDeclaringClass());
+ assertEquals(Subclassing.class, Subclassing.A.getDeclaringClass());
+ }
+
public void testMethod() {
assertEquals("X", Complex.A.value());
assertEquals("Y", Complex.B.value());