Fixes a bug in JavaScriptObject support in DevMode that prevents dispatching
through an interface to a method defined in a super-interface. The change
also includes a new test to serve as a regression test.
Review at http://gwt-code-reviews.appspot.com/1287801
Review by: bobv, scottb, cromwellian
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9542 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java
index e676987..215dcc6 100644
--- a/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java
+++ b/dev/core/src/com/google/gwt/dev/shell/rewrite/RewriteSingleJsoImplDispatches.java
@@ -34,8 +34,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* Effects the renaming of {@code @SingleJsoImpl} methods from their original
@@ -181,9 +181,9 @@
* may be referenced via a more specific interface.
*/
if (inSingleJsoImplInterfaceType) {
- for (Map.Entry<String, List<Method>> entry : toImplement(currentTypeName).entrySet()) {
- for (Method method : entry.getValue()) {
- writeEmptyMethod(entry.getKey(), method);
+ for (String mangledName : toImplement(currentTypeName)) {
+ for (Method method : jsoData.getDeclarations(mangledName)) {
+ writeEmptyMethod(mangledName, method);
}
}
}
@@ -265,29 +265,23 @@
* Given a resource name of a class, find all mangled method names that must
* be implemented.
*/
- private SortedMap<String, List<Method>> toImplement(String typeName) {
+ private SortedSet<String> toImplement(String typeName) {
String name = typeName.replace('/', '_');
String prefix = name + "_";
String suffix = name + "`";
- SortedMap<String, List<Method>> toReturn = new TreeMap<String, List<Method>>();
-
+ SortedSet<String> toReturn = new TreeSet<String>();
for (String mangledName : jsoData.getMangledNames().subSet(prefix, suffix)) {
- toReturn.put(mangledName, jsoData.getImplementations(mangledName));
+ if (!implementedMethods.contains(mangledName)) {
+ toReturn.add(mangledName);
+ }
}
- toReturn.keySet().removeAll(implementedMethods);
return toReturn;
}
-
- private void writeEmptyMethod(String mangledMethodName, Method method) {
- assert method.getArgumentTypes().length > 0;
- // Remove the first argument, which would be the implementing JSO type
- String descriptor = "("
- + method.getDescriptor().substring(
- 1 + method.getArgumentTypes()[0].getDescriptor().length());
-
- // Create the stub method entry in the interface
+
+ private void writeEmptyMethod(String mangledMethodName, Method declMethod) {
MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC
- | Opcodes.ACC_ABSTRACT, mangledMethodName, descriptor, null, null);
+ | Opcodes.ACC_ABSTRACT, mangledMethodName, declMethod.getDescriptor(),
+ null, null);
mv.visitEnd();
}
@@ -303,20 +297,14 @@
* semantics of the dispatches that would make a common implementation far
* more awkward than the duplication of code.
*/
- for (Map.Entry<String, List<Method>> entry : toImplement(stubIntr).entrySet()) {
- for (Method method : entry.getValue()) {
- String mangledName = entry.getKey();
+ for (String mangledName : toImplement(stubIntr)) {
+ for (Method method : jsoData.getDeclarations(mangledName)) {
- String descriptor = "("
- + method.getDescriptor().substring(
- 1 + method.getArgumentTypes()[0].getDescriptor().length());
- String localName = method.getName().substring(0,
- method.getName().length() - 1);
- Method toCall = new Method(localName, descriptor);
+ Method toCall = new Method(method.getName(), method.getDescriptor());
// Must not be final
MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC
- | Opcodes.ACC_SYNTHETIC, mangledName, descriptor, null, null);
+ | Opcodes.ACC_SYNTHETIC, mangledName, method.getDescriptor(), null, null);
if (mv != null) {
mv.visitCode();
diff --git a/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java b/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
index c0f93d4..03d38ac 100644
--- a/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
@@ -123,6 +123,45 @@
static class Wide {
}
+ private interface Element extends Node {
+ }
+
+ private static class JvmNode implements Node {
+ @Override
+ public JvmNode appendChild(Node node) {
+ return (JvmNode)node;
+ }
+ }
+
+ private final static class JvmElement extends JvmNode implements Element {
+ static Element create() {
+ return new JvmElement();
+ }
+ }
+
+ private final static class JsElement extends JsNode implements Element {
+ static Element create() {
+ return (Element) JavaScriptObject.createObject();
+ }
+
+ protected JsElement() {
+ }
+ }
+
+ private static class JsNode extends JavaScriptObject implements Node {
+ @Override
+ public final native JsNode appendChild(Node node) /*-{
+ return node;
+ }-*/;
+
+ protected JsNode() {
+ }
+ }
+
+ private interface Node {
+ Node appendChild(Node node);
+ }
+
@Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -149,7 +188,7 @@
IA b2 = new B2();
assertEquals("B2", b2.whoAmI());
}
-
+
public void testCase3() {
IA a = A.create();
assertEquals("A", a.whoAmI());
@@ -171,6 +210,17 @@
IDiamond2B d2b = DiamondImpl.create();
assertEquals(42, d2b.size());
}
+
+ /**
+ * Tests that dispatches through a hierarchy of interfaces works properly.
+ */
+ public void testInterfaceHierarchyDispatch() {
+ Element jsElement = JsElement.create();
+ assertEquals(jsElement, jsElement.appendChild(jsElement));
+
+ Element jvmElement = JvmElement.create();
+ assertEquals(jvmElement, jvmElement.appendChild(jvmElement));
+ }
public void testVirtualOverrides() {
Arrayish array = PlainJsoWithInterface.create();