Fixes a bug with calling private instance methods in web mode from
native methods; private methods could effectively override each
other. This patch adjusts the mangled name of private instance
methods by adding the class name at the beginning.
Review by: bobv
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5197 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 e335ad4..f95c9d0 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
@@ -1978,13 +1978,25 @@
}
String mangleNameForPolyImpl(JMethod x) {
- String s = getNameString(x) + "__";
+ StringBuffer sb = new StringBuffer();
+ if (x.isPrivate() && !x.isStatic()) {
+ /*
+ * Private instance methods in different classes should not override each
+ * other, so they must have distinct polymorphic names. Therefore, add the
+ * class name to the mangled name.
+ */
+ sb.append("private$");
+ sb.append(getNameString(x.getEnclosingType()));
+ sb.append("$");
+ }
+ sb.append(getNameString(x));
+ sb.append("__");
for (int i = 0; i < x.getOriginalParamTypes().size(); ++i) {
JType type = x.getOriginalParamTypes().get(i);
- s += type.getJavahSignatureName();
+ sb.append(type.getJavahSignatureName());
}
- s += x.getOriginalReturnType().getJavahSignatureName();
- return s;
+ sb.append(x.getOriginalReturnType().getJavahSignatureName());
+ return sb.toString();
}
String mangleNameSpecialObfuscate(JField x) {
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
index a900136..d62627f 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -27,7 +27,6 @@
*/
@SuppressWarnings("unused")
public class CompilerTest extends GWTTestCase {
-
interface MyMap {
Object get(String key);
}
@@ -172,6 +171,84 @@
}
}
+ /**
+ * Used in test {@link #testPrivateOverride()}.
+ */
+ private static class TpoChild extends TpoParent {
+ @Override
+ public int foo() {
+ return callSuper();
+ }
+
+ private int callSuper() {
+ return super.foo();
+ }
+ }
+
+ /**
+ * Used in test {@link #testPrivateOverride()}.
+ */
+ private static class TpoGrandparent {
+ public int foo() {
+ return 0;
+ }
+ }
+
+ /**
+ * Used in test {@link #testPrivateOverride()}.
+ */
+ private static class TpoJsniChild extends TpoJsniParent {
+ @Override
+ public native int foo() /*-{
+ return this.@com.google.gwt.dev.jjs.test.CompilerTest$TpoJsniChild::callSuper()();
+ }-*/;
+
+ private int callSuper() {
+ return super.foo();
+ }
+ }
+
+ /**
+ * Used in test {@link #testPrivateOverride()}.
+ */
+ private static class TpoJsniGrandparent {
+ public int foo() {
+ return 0;
+ }
+ }
+
+ /**
+ * Used in test {@link #testPrivateOverride()}.
+ */
+ private static class TpoJsniParent extends TpoJsniGrandparent {
+ @Override
+ public native int foo() /*-{
+ // This should call callSuper in TpoJsniParent, not the one
+ // in TpoJsniChild
+ return this.@com.google.gwt.dev.jjs.test.CompilerTest$TpoJsniParent::callSuper()();
+ }-*/;
+
+ private int callSuper() {
+ return super.foo();
+ }
+ }
+
+ /**
+ * Used in test {@link #testPrivateOverride()}.
+ */
+ private static class TpoParent extends TpoGrandparent {
+ @Override
+ public int foo() {
+ // This should call the callSuper in TpoJsniParent, not the one
+ // in TpoJsniChild
+ return callSuper();
+ }
+
+ private int callSuper() {
+ return super.foo();
+ }
+ }
+
private static final class UninstantiableType {
public Object field;
public int intField;
@@ -905,6 +982,16 @@
new B();
}
+ /**
+ * Test that calling a private instance method does not accidentally call
+ * another private method that appears to override it. Private methods don't
+ * truly override each other.
+ */
+ public void testPrivateOverride() {
+ assertEquals(0, new TpoChild().foo());
+ assertEquals(0, new TpoJsniChild().foo());
+ }
+
public void testReturnStatementInCtor() {
class Foo {
int i;