Revision: 6872
Author: j...@google.com
Date: Thu Nov 12 08:22:02 2009
Log: Fix a problem with local static classes, plus clean up naming, comments
and formatting.

Patch by: jat
Review by: rice

http://code.google.com/p/google-web-toolkit/source/detail?r=6872

Modified:
  /trunk/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
  /trunk/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java
  /trunk/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java
  /trunk/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
  /trunk/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java        
 
Thu Nov 12 06:59:32 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java        
 
Thu Nov 12 08:22:02 2009
@@ -93,6 +93,9 @@
    /**
     * Returns the binary name of a type. This is the same name that would be
     * returned by {...@link Class#getName()} for this type.
+   *
+   * @param type TypeOracle type to get the name for
+   * @return binary name for a type
     */
    public static String computeBinaryClassName(JType type) {
      JPrimitiveType primitiveType = type.isPrimitive();
@@ -231,10 +234,18 @@

    private Resolver resolver;

+  /**
+   * Construct a TypeOracleMediator.
+   */
    public TypeOracleMediator() {
      this(null);
    }

+  /**
+   * Construct a TypeOracleMediator.
+   *
+   * @param typeOracle TypeOracle instance to use, or null to create a new  
one
+   */
    // @VisibleForTesting
    public TypeOracleMediator(TypeOracle typeOracle) {
      if (typeOracle == null) {
@@ -272,8 +283,12 @@

    /**
     * Adds new units to an existing TypeOracle.
+   *
+   * @param logger logger to use
+   * @param units collection of compilation units to process
     */
-  public void addNewUnits(TreeLogger logger, Collection<CompilationUnit>  
units) {
+  public void addNewUnits(TreeLogger logger,
+      Collection<CompilationUnit> units) {
      PerfLogger.start("TypeOracleMediator.addNewUnits");
      // First collect all class data.
      classMap = new HashMap<String, CollectClassData>();
@@ -349,10 +364,16 @@
      PerfLogger.end();
    }

+  /**
+   * @return a map from binary class names to JRealClassType.
+   */
    public Map<String, JRealClassType> getBinaryMapper() {
      return binaryMapper;
    }

+  /**
+   * @return the TypeOracle managed by the mediator.
+   */
    public TypeOracle getTypeOracle() {
      return typeOracle;
    }
@@ -390,7 +411,7 @@
      String jpkgName = compiledClass.getPackageName();
      JPackage pkg = typeOracle.getOrCreatePackage(jpkgName);
      boolean isIntf = (access & Opcodes.ACC_INTERFACE) != 0;
-    boolean isLocalType = classData.isLocal();
+    boolean isLocalType = classData.hasNoExternalName();
      String enclosingTypeName = null;
      if (enclosingClassData != null) {
        enclosingTypeName =  
InternalName.toSourceName(InternalName.getClassName(enclosingClassData.getName()));
@@ -526,7 +547,7 @@
    private CollectClassData processClass(CompiledClass compiledClass) {
      byte[] classBytes = compiledClass.getBytes();
      ClassReader reader = new ClassReader(classBytes);
-    CollectClassData mcv = new CollectClassData(classBytes);
+    CollectClassData mcv = new CollectClassData();
      ClassVisitor cv = mcv;
      if (false) {
        cv = new TraceClassVisitor(cv, new PrintWriter(System.out));
@@ -688,7 +709,7 @@
      assert classData != null;
      int access = classData.getAccess();

-    assert (!classData.getClassType().isLocal());
+    assert (!classData.getClassType().hasNoExternalName());

      logger = logger.branch(TreeLogger.SPAM, "Found type '"
          + type.getQualifiedSourceName() + "'", null);
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java      
 
Thu Nov 12 06:32:35 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/asm/CollectClassData.java      
 
Thu Nov 12 08:22:02 2009
@@ -60,47 +60,44 @@
       */
      Anonymous {
        @Override
-      public boolean hasOuter() {
+      public boolean hasNoExternalName() {
          return true;
        }
-
-      @Override
-      public boolean isLocal() {
-        return true;
-      }
      },

      /**
       * A named class defined inside a method.
       */
      Local {
-      @Override
-      public boolean hasHiddenConstructorArg() {
-        return true;
-      }
+      /*
+       * Note that we do not return true for hasHiddenConstructorArg since  
Local
+       * classes inside a static method will not have one and AFAICT there  
is no
+       * way to distinguish these cases without looking up the declaring  
method.
+       * However, since we are dropping any classes for which
+       * hasNoExternalName() returns true in  
TypeOracleMediator.addNewUnits, it
+       * doesn't matter if we leave the synthetic argument in the list.
+       */

        @Override
-      public boolean hasOuter() {
+      public boolean hasNoExternalName() {
          return true;
        }
-
-      @Override
-      public boolean isLocal() {
-        return true;
-      }
      };

+    /**
+     * @return true if this class type has a hidden constructor argument
+     * for the containing instance (ie, this$0).
+     */
      public boolean hasHiddenConstructorArg() {
        return false;
      }

-    public boolean hasOuter() {
+   /**
+    * @return true if this class type is not visible outside a method.
+    */
+    public boolean hasNoExternalName() {
        return false;
      }
-
-    public boolean isLocal() {
-      return false;
-    }
    }

    /**
@@ -110,20 +107,26 @@
      private final String desc;
      private final String value;

+    /**
+     * Construct the value of an Enum-valued annotation.
+     *
+     * @param desc type descriptor of this enum
+     * @param value actual value in this enum
+     */
      public AnnotationEnum(String desc, String value) {
        this.desc = desc;
        this.value = value;
      }

      /**
-     * @return the descriptor
+     * @return the type descriptor of the enum type.
       */
      public String getDesc() {
        return desc;
      }

      /**
-     * @return the value
+     * @return the annotation value.
       */
      public String getValue() {
        return value;
@@ -144,7 +147,6 @@

    // internal names of interfaces
    private String[] interfaces;
-  private byte[] bytes;
    private List<CollectMethodData> methods = new  
ArrayList<CollectMethodData>();
    private List<CollectFieldData> fields = new  
ArrayList<CollectFieldData>();
    private int access;
@@ -153,30 +155,25 @@
    private String outerMethodDesc;
    private CollectClassData.ClassType classType = ClassType.TopLevel;

-  public CollectClassData(byte[] bytes) {
-    this.bytes = bytes;
+  /**
+   * Construct a visitor that will collect data about a class.
+   */
+  public CollectClassData() {
    }

    /**
-   * @return the access
+   * @return the access flags for this class (ie, bitwise or of  
Opcodes.ACC_*).
     */
    public int getAccess() {
      return access;
    }

    /**
-   * @return annotations on this class
+   * @return a list of annotations on this class.
     */
    public List<CollectAnnotationData> getAnnotations() {
      return annotations;
    }
-
-  /**
-   * @return the bytes
-   */
-  public byte[] getBytes() {
-    return bytes;
-  }

    /**
     * @return the class type.
@@ -186,21 +183,14 @@
    }

    /**
-   * @return the fields
+   * @return a list of fields in this class.
     */
    public List<CollectFieldData> getFields() {
      return fields;
    }
-
-//  /**
-//   * @return the innerClasses
-//   */
-//  public List<Resource> getInnerClasses() {
-//    return innerClasses;
-//  }

    /**
-   * @return the interfaces
+   * @return an array of internal names of interfaces implemented by this  
class.
     */
    public String[] getInterfaces() {
      return interfaces;
@@ -262,20 +252,20 @@
      return superName;
    }

+  /**
+   * @return true if this class has no external name (ie, is defined inside
+   * a method).
+   */
    public boolean hasNoExternalName() {
-    return classType == ClassType.Anonymous || classType ==  
ClassType.Local;
+    return classType.hasNoExternalName();
    }

+  /**
+   * @return true if this class has no source name at all.
+   */
    public boolean isAnonymous() {
      return classType == ClassType.Anonymous;
    }
-
-  public boolean isLocal() {
-    if (name.matches("\\$\\d") && !isAnonymous()) {
-      throw new IllegalStateException("Not anonymous with name of " +  
name);
-    }
-    return classType.isLocal();
-  }

    @Override
    public String toString() {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java     
 
Thu Nov 12 06:32:35 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/asm/CollectMethodData.java     
 
Thu Nov 12 08:22:02 2009
@@ -43,7 +43,17 @@
    private int access;
    private int syntheticArgs;

-  @SuppressWarnings("unchecked")
+  /**
+   * Prepare to collect data for a method from bytecode.
+   *
+   * @param classType
+   * @param access
+   * @param name
+   * @param desc
+   * @param signature
+   * @param exceptions
+   */
+  @SuppressWarnings("unchecked") // for new List[]
    public CollectMethodData(CollectClassData.ClassType classType, int  
access,
        String name, String desc, String signature, String[] exceptions) {
      this.access = access;
@@ -55,9 +65,16 @@
      argTypes = Type.getArgumentTypes(desc);
      // Non-static instance methods and constructors of non-static inner
      // classes have an extra synthetic parameter that isn't in the source,
-    // so we remove it.
+    // so we remove it.  Note that for local classes, they may or may not
+    // have this synthetic parameter depending on whether the containing
+    // method is static, but we can't get that info here.  However, since
+    // local classes are dropped from TypeOracle, we don't care.
      if (classType.hasHiddenConstructorArg() && "<init>".equals(name)) {
        // remove "this$1" as a parameter
+      if (argTypes.length < 1) {
+        throw new IllegalStateException(
+            "Missing synthetic argument in constructor");
+      }
        syntheticArgs = 1;
        int n = argTypes.length - syntheticArgs;
        Type[] newArgTypes = new Type[n];
=======================================
---  
/trunk/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java       
 
Tue Nov 10 20:42:30 2009
+++  
/trunk/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java       
 
Thu Nov 12 08:22:02 2009
@@ -46,6 +46,9 @@
  import java.util.Map;
  import java.util.Set;

+/**
+ * Test TypeOracleMediator.
+ */
  public class TypeOracleMediatorTest extends TestCase {

    private abstract class MutableJavaResource extends MockJavaResource {
@@ -128,6 +131,38 @@
      }
    };

+
+  protected CheckedJavaResource CU_AnonymousClass = new  
CheckedJavaResource(
+      "test", "Enclosing") {
+
+    @Override
+    public void check(JClassType type) {
+      final String name = type.getSimpleSourceName();
+      assertEquals("Enclosing", name);
+      checkEnclosing(type);
+    }
+
+    public void checkEnclosing(JClassType type) {
+      assertEquals("Enclosing", type.getSimpleSourceName());
+      assertEquals("test.Enclosing", type.getQualifiedSourceName());
+      // verify the anonymous class doesn't show up
+      JClassType[] nested = type.getNestedTypes();
+      assertEquals(0, nested.length);
+    }
+
+    @Override
+    public String getSource() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package test;\n");
+      sb.append("public class Enclosing {\n");
+      sb.append("   public static Object getLocal() {");
+      sb.append("     return new Object() { };\n");
+      sb.append("   }\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+  };
+
    protected CheckedJavaResource CU_Assignable = new CheckedJavaResource(
        "test.sub", "Derived", "BaseInterface", "DerivedInterface",
        "Derived.Nested") {
@@ -631,7 +666,7 @@
    };

    protected CheckedJavaResource CU_LocalClass = new  
CheckedJavaResource("test",
-      "Enclosing", "Enclosing.1") {
+      "Enclosing") {

      @Override
      public void check(JClassType type) {
@@ -643,7 +678,7 @@
      public void checkEnclosing(JClassType type) {
        assertEquals("Enclosing", type.getSimpleSourceName());
        assertEquals("test.Enclosing", type.getQualifiedSourceName());
-      // verify the anonymous class doesn't show up
+      // verify the local class doesn't show up
        JClassType[] nested = type.getNestedTypes();
        assertEquals(0, nested.length);
      }
@@ -654,13 +689,49 @@
        sb.append("package test;\n");
        sb.append("public class Enclosing {\n");
        sb.append("   public static Object getLocal() {");
-      sb.append("     return new Object() { };\n");
+      sb.append("     class MyObject { }\n");
+      sb.append("     return new MyObject();\n");
        sb.append("   }\n");
        sb.append("}\n");
        return sb.toString();
      }
    };

+  protected CheckedJavaResource CU_LocalClass2 = new  
CheckedJavaResource("test",
+      "Enclosing") {
+
+    @Override
+    public void check(JClassType type) {
+      final String name = type.getSimpleSourceName();
+      assertEquals("Enclosing", name);
+      checkEnclosing(type);
+    }
+
+    public void checkEnclosing(JClassType type) {
+      assertEquals("Enclosing", type.getSimpleSourceName());
+      assertEquals("test.Enclosing", type.getQualifiedSourceName());
+      // verify the local class doesn't show up
+      JClassType[] nested = type.getNestedTypes();
+      assertEquals(0, nested.length);
+    }
+
+    @Override
+    public String getSource() {
+      StringBuffer sb = new StringBuffer();
+      sb.append("package test;\n");
+      sb.append("public class Enclosing {\n");
+      sb.append("   public int foo;\n");
+      sb.append("   public Object getLocal() {\n");
+      sb.append("     class MyObject {\n");
+      sb.append("       int getFoo() { return foo; }\n");
+      sb.append("     }\n");
+      sb.append("     return new MyObject() {};\n");
+      sb.append("   }\n");
+      sb.append("}\n");
+      return sb.toString();
+    }
+  };
+
    protected CheckedJavaResource CU_MethodsAndParams = new  
CheckedJavaResource(
        "test", "Methods") {

@@ -1189,6 +1260,14 @@
      JClassType[] types = typeOracle.getTypes();
      assertEquals(2, types.length);
    }
+
+  public void testLocalWithSynthetic() throws TypeOracleException {
+    resources.add(CU_Object);
+    resources.add(CU_LocalClass2);
+    compileAndRefresh();
+    JClassType[] types = typeOracle.getTypes();
+    assertEquals(2, types.length);
+  }

    public void testMethodsAndParams() throws TypeOracleException {
      resources.add(CU_Object);
=======================================
---  
/trunk/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java     
 
Thu Nov 12 06:32:35 2009
+++  
/trunk/dev/core/test/com/google/gwt/dev/javac/asm/CollectClassDataTest.java     
 
Thu Nov 12 08:22:02 2009
@@ -72,6 +72,37 @@
        annotatedField = field;
      }
    }
+
+  /**
+   * Test local classes.
+   */
+  public static class Three {
+
+    public int foo;
+
+    /**
+     * Static method that has a local class in it.
+     */
+    public static void methodWithLocalStatic() {
+      class Foo {
+      }
+
+      Foo x = new Foo();
+    }
+
+    /**
+     * Method that has a local class in it.
+     */
+    public void methodWithLocal() {
+      class Foo {
+        Foo() {
+          foo = 1;
+        }
+      }
+
+      Foo x = new Foo();
+    }
+  }

    public void testAnonymous() {
      CollectClassData cd = collect(One.class.getName() + "$1");
@@ -215,6 +246,22 @@
      assertEquals(Opcodes.ACC_PUBLIC , cd.getAccess() & ~Opcodes.ACC_SUPER);
      assertEquals(ClassType.Inner, cd.getClassType());
    }
+
+  public void testLocal() {
+    CollectClassData cd = collect(Three.class.getName() + "$2Foo");
+    // Don't check for super bit, as it will depend on the JDK used to  
compile.
+    assertEquals(0, cd.getAccess() & ~Opcodes.ACC_SUPER);
+    assertEquals(ClassType.Local, cd.getClassType());
+    assertEquals("methodWithLocal", cd.getOuterMethodName());
+  }
+
+  public void testLocalStatic() {
+    CollectClassData cd = collect(Three.class.getName() + "$1Foo");
+    // Don't check for super bit, as it will depend on the JDK used to  
compile.
+    assertEquals(0, cd.getAccess() & ~Opcodes.ACC_SUPER);
+    assertEquals(ClassType.Local, cd.getClassType());
+    assertEquals("methodWithLocalStatic", cd.getOuterMethodName());
+  }

    private CollectClassData collect(Class<?> clazz) {
      return collect(clazz.getName());
@@ -223,7 +270,7 @@
    private CollectClassData collect(String className) {
      byte[] bytes = getClassBytes(className);
      assertNotNull("Couldn't load bytes for " + className, bytes);
-    CollectClassData cv = new CollectClassData(bytes);
+    CollectClassData cv = new CollectClassData();
      ClassReader reader = new ClassReader(bytes);
      reader.accept(cv, 0);
      return cv;

-- 
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to