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