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