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());