Change the JsInterop bridge direction.

Earlier we were forwarding jsmethod at the first place it was exposed:

  parent.prototype.m = function() { return this.m_obfuscated() };

This caused a code regression in Closure based apps as Closure fail
to prune anything due to missing type information. This basically left
an alias bride method for every jsmethod.

I changed the implementation so that the direction is reversed.
So we generate methods with pretty js names and then create a bridge
from obfuscated name only if
 - method override a non-jsmethod
 - there is no parent who created such bridge.

Change-Id: I3ae2b023c8406abe42dcb2acc1a1271a873364e9
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index d01a2f0..ed39c7c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -107,10 +107,10 @@
   }
 
   private boolean isJsInterfaceMethod() {
-    return isInterFaceMethod() && enclosingType.isJsType();
+    return isInterfaceMethod() && enclosingType.isJsType();
   }
 
-  private boolean isInterFaceMethod() {
+  private boolean isInterfaceMethod() {
     return enclosingType instanceof JInterfaceType;
   }
 
@@ -157,26 +157,25 @@
   }
 
   /**
-   * Returns {@code true} if this method is the first method in the method hierarchy that exposes a
-   * JsMethod inside a class.
+   * Returns {@code true} if this method is the first JsMethod in the method hierarchy that exposes
+   * an existing non-JsMethod inside a class.
    */
-  public boolean exposesJsMethod() {
-    if (isInterFaceMethod()) {
+  public boolean exposesNonJsMethod() {
+    if (isInterfaceMethod() || !isOrOverridesJsMethod()) {
       return false;
     }
 
-    boolean isJsMethod = jsName != null;
-    for (JMethod override : getOverriddenMethods()) {
-      if (override.jsName == null) {
-        continue;
+    boolean hasNonJsMethodParent = false;
+    for (JMethod overriddenMethod : overriddenMethods) {
+      if (!overriddenMethod.isOrOverridesJsMethod()) {
+        hasNonJsMethodParent = true;
       }
-      isJsMethod = true;
-      if (!override.isInterFaceMethod()) {
+      if (overriddenMethod.exposesNonJsMethod()) {
         return false; // some other method already exposed this method.
       }
     }
 
-    return isJsMethod;
+    return hasNonJsMethodParent;
   }
 
   public boolean isOrOverridesJsMethod() {
@@ -484,7 +483,7 @@
 
     boolean hasPackageVisibleParent = false;
     for (JMethod overriddenMethod : overriddenMethods) {
-      if (overriddenMethod.isInterFaceMethod()) {
+      if (overriddenMethod.isInterfaceMethod()) {
         continue;
       }
       if (!overriddenMethod.isPackagePrivate()) {
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 fce135d..833c070 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
@@ -558,7 +558,11 @@
           } else if (x.isPackagePrivate()) {
             polyName = interfaceScope.declareName(mangleNameForPackagePrivatePoly(x), name);
           } else {
-            polyName = interfaceScope.declareName(mangleNameForPoly(x), name);
+            boolean isJsMethod = x.isOrOverridesJsMethod() && !x.isJsPropertyAccessor();
+            polyName =
+                isJsMethod
+                    ? interfaceScope.declareUnobfuscatableName(x.getJsName())
+                    : interfaceScope.declareName(mangleNameForPoly(x));
           }
           polymorphicNames.put(x, polyName);
         }
@@ -1380,7 +1384,7 @@
     private JsExpression dispatchToInstanceMethod(
         JsExpression instance, JMethod method, List<JsExpression> args, SourceInfo sourceInfo) {
       JsNameRef reference =
-          method.isOrOverridesJsMethod()
+          method.isJsPropertyAccessor()
               ? new JsNameRef(sourceInfo, method.getJsName())
               : polymorphicNames.get(method).makeRef(sourceInfo);
       reference.setQualifier(instance);
@@ -2633,9 +2637,9 @@
           generateVTableAssignment(globalStmts, method, polymorphicNames.get(method), rhs);
         }
 
-        if (method.exposesJsMethod()) {
-          JsName jsName = interfaceScope.declareUnobfuscatableName(method.getJsName());
-          generateVTableAlias(globalStmts, method, jsName);
+        if (method.exposesNonJsMethod()) {
+          JsName internalMangledName = interfaceScope.declareName(mangleNameForPoly(method));
+          generateVTableAlias(globalStmts, method, internalMangledName);
         }
 
         if (method.exposesPackagePrivateMethod()) {
diff --git a/user/test/com/google/gwt/core/client/interop/ConcreteJsType.java b/user/test/com/google/gwt/core/client/interop/ConcreteJsType.java
index ba5c362..74c89e4 100644
--- a/user/test/com/google/gwt/core/client/interop/ConcreteJsType.java
+++ b/user/test/com/google/gwt/core/client/interop/ConcreteJsType.java
@@ -26,6 +26,10 @@
     return 10;
   }
 
+  public int publicMethodAlsoExposedAsNonJsMethod() {
+    return 100;
+  }
+
   public static void publicStaticMethod() {
   }
 
diff --git a/user/test/com/google/gwt/core/client/interop/ConcreteJsTypeJsSubclass.java b/user/test/com/google/gwt/core/client/interop/ConcreteJsTypeJsSubclass.java
new file mode 100644
index 0000000..9e89e41
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/interop/ConcreteJsTypeJsSubclass.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.client.interop;
+
+import com.google.gwt.core.client.js.JsType;
+
+/**
+ * This test class exposes parent jsmethod as non-jsmethod.
+ */
+@JsType
+class ConcreteJsTypeJsSubclass extends ConcreteJsType implements SubclassInterface {
+}
+
+interface SubclassInterface {
+  int publicMethodAlsoExposedAsNonJsMethod();
+}
diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
index edaf15c..3c6fe94 100644
--- a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
@@ -137,6 +137,16 @@
     // RevealedOverrideSubType defines no functions itself, it only inherits them, but it still
     // exports run() because it implements the @JsType interface JsTypeRunnable.
     assertTrue(hasField(revealedOverrideSubType, "run"));
+
+    ConcreteJsTypeJsSubclass subclass = new ConcreteJsTypeJsSubclass();
+    assertEquals(100, subclass.publicMethodAlsoExposedAsNonJsMethod());
+    SubclassInterface subclassInterface = alwaysTrue() ? subclass : new SubclassInterface() {
+      @Override
+      public int publicMethodAlsoExposedAsNonJsMethod() {
+        return 0;
+      }
+    };
+    assertEquals(100, subclassInterface.publicMethodAlsoExposedAsNonJsMethod());
   }
 
   public void testConcreteNativeType() {