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;