Reviewers: skybrian,
Description:
Fix GeneratedClassnameFinder for OpenJDK 7 javac.
Please review this at http://gwt-code-reviews.appspot.com/1867803/
Affected files:
M dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
M dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
Index: dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
===================================================================
--- dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java (revision
11367)
+++ dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java (working
copy)
@@ -60,8 +60,20 @@
*/
List<String> classNames = new ArrayList<String>();
+ int expectCode;
+ int sawCode;
+
public List<String> getInnerClassNames() {
return classNames;
+ }
+
+ /**
+ * Return whether or not the class file visited was well-formed.
+ * Currently, this only checks that all non-abstract, non-native
methods
+ * have a Code attribute.
+ */
+ public boolean isWellFormed() {
+ return expectCode == sawCode;
}
@Override
@@ -69,6 +81,20 @@
if ((access & Opcodes.ACC_SYNTHETIC) == 0) {
classNames.add(name);
}
+ }
+
+ @Override
+ public AnonymousClassVisitor visitMethod(int access, String name,
String desc, String signature,
+ String[] exceptions) {
+ if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) == 0) {
+ ++expectCode;
+ }
+ return this;
+ }
+
+ @Override
+ public void visitCode() {
+ ++sawCode;
}
}
@@ -101,6 +127,18 @@
continue;
}
+ AnonymousClassVisitor cv = new AnonymousClassVisitor();
+ new ClassReader(classBytes).accept(cv, 0);
+ if (!cv.isWellFormed()) {
+ /*
+ * Weird case #2: As of OpenJDK 7, javac in the above case now
does
+ * generate a class file, but an incomplete one that fails to
load
+ * with a ClassFormatError "Absent Code attribute in method that
+ * is not native or abstract in class file" error.
+ */
+ continue;
+ }
+
/*
* Add the class to the list only if it can be loaded to get
around the
* javac weirdness issue where javac refers a class but does not
@@ -109,8 +147,6 @@
if (isClassnameGenerated(lookupName)
&& !allGeneratedClasses.contains(lookupName)) {
allGeneratedClasses.add(lookupName);
}
- AnonymousClassVisitor cv = new AnonymousClassVisitor();
- new ClassReader(classBytes).accept(cv, 0);
List<String> innerClasses = cv.getInnerClassNames();
for (String innerClass : innerClasses) {
// The innerClass has to be an inner class of the lookupName
Index:
dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
===================================================================
---
dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
(revision 11367)
+++
dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
(working copy)
@@ -89,6 +89,10 @@
+ "$MainClass$NestedClass").getClassNames().size());
}
+ public void testAbstractNative() {
+ assertEquals(2, new
AbstractNativeTester().getGeneratedClasses().size());
+ }
+
public void testAnonymous() {
assertEquals(1, new AnonymousTester().getGeneratedClasses().size());
}
@@ -124,6 +128,27 @@
assertEquals(1, new TopLevelTester().getGeneratedClasses().size());
}
+
+}
+
+/**
+ * For testing a class containing an anonymous abstract and native inner
classes.
+ */
+class AbstractNativeTester {
+ void foo() {
+ abstract class Fooer {
+ abstract void foo();
+ }
+ Fooer a = new Fooer() {
+ native void foo();
+ };
+ a.foo();
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new
GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
}
/**