Fix ICE due to incorrect naming of method reference classes.

Naming of sythetic classes for method references and lambdas should
follow the normal conventions, i.e. that the name should start with
the name of the enclosing class.

Bug: #9426
Bug-Link: https://github.com/gwtproject/gwt/issues/9426
Change-Id: Id9c80a6064864611ed18dd1626fa92e29b946e98
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
index 06b972e..3f42bcb 100755
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -284,6 +284,10 @@
       return new String[] { getShortName() };
     }
 
+    assert getShortName().startsWith(enclosingType.getShortName())
+        : "Innerclass name  " + getShortName() + " does not start with enclosing class name "
+        + enclosingType.getShortName();
+
     String className = StringInterner.get().intern(
         getShortName().substring(enclosingType.getShortName().length() + 1));
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 55c5968..15d44e7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -110,6 +110,7 @@
 import com.google.gwt.dev.util.StringInterner;
 import com.google.gwt.dev.util.collect.Stack;
 import com.google.gwt.thirdparty.guava.common.base.Function;
+import com.google.gwt.thirdparty.guava.common.base.Joiner;
 import com.google.gwt.thirdparty.guava.common.base.Preconditions;
 import com.google.gwt.thirdparty.guava.common.base.Predicate;
 import com.google.gwt.thirdparty.guava.common.base.Predicates;
@@ -1223,9 +1224,9 @@
       // Create an inner class to implement the interface and SAM method.
       // class lambda$0$Type implements T {}
 
-      String innerLambdaClassName =
-          JdtUtil.getClassName(x.binding.declaringClass) + "$" + String.valueOf(x.binding.selector);
-      JClassType innerLambdaClass = createInnerClass(innerLambdaClassName, x, info, funcType);
+      String innerLambdaImplementationClassShortName = String.valueOf(x.binding.selector);
+      JClassType innerLambdaClass = createInnerClass(
+          curClass.getClassOrInterface(), innerLambdaImplementationClassShortName, info, funcType);
       JConstructor ctor = new JConstructor(info, innerLambdaClass, AccessModifier.PRIVATE);
 
       // locals captured by the lambda and saved as fields on the anonymous inner class
@@ -1467,11 +1468,12 @@
       return ctor.createFinalParameter(info, paramName, paramType);
     }
 
-    private JClassType createInnerClass(String name, FunctionalExpression x, SourceInfo info,
-        JInterfaceType... funcType) {
-      JClassType innerLambdaClass = new JClassType(info, name + "$Type", false, true);
-      innerLambdaClass.setEnclosingType((JDeclaredType) typeMap.get(x.binding.declaringClass));
-      for (JInterfaceType type : funcType) {
+    private JClassType createInnerClass(JDeclaredType enclosingType, String shortNname,
+        SourceInfo info, JInterfaceType... superInterfaces) {
+      JClassType innerLambdaClass = new JClassType(info,
+          Joiner.on('$').join(enclosingType.getName(), shortNname, "Type"), false, true);
+      innerLambdaClass.setEnclosingType(enclosingType);
+      for (JInterfaceType type : superInterfaces) {
         innerLambdaClass.addImplements(type);
       }
       innerLambdaClass.setSuperClass(javaLangObject);
@@ -1785,14 +1787,14 @@
 
       // Constructors, overloading and generics means that the safest approach is to consider
       // each different member reference as a different lambda implementation.
-      String lambdaName =  JdtUtil.getClassName(curClass.typeDecl.binding) + "$"
-          + String.valueOf(nextReferenceExpressionId++) + "methodref$"
-          + (x.binding.isConstructor() ? "ctor" : String.valueOf(x.binding.selector));
-
+      String lambdaImplementationClassShortName =
+          String.valueOf(nextReferenceExpressionId++) + "methodref$"
+              + (x.binding.isConstructor() ? "ctor" : String.valueOf(x.binding.selector));
       List<JExpression> enclosingThisRefs = Lists.newArrayList();
 
       // Create an inner class to hold the implementation of the interface
-      JClassType innerLambdaClass = createInnerClass(lambdaName, x, info, funcType);
+      JClassType innerLambdaClass = createInnerClass(
+          curClass.getClassOrInterface(), lambdaImplementationClassShortName, info, funcType);
       newTypes.add(innerLambdaClass);
 
       JConstructor ctor = new JConstructor(info, innerLambdaClass, AccessModifier.PRIVATE);
@@ -1806,7 +1808,7 @@
       if (hasQualifier) {
         // this.$$outer = $$outer
         JField outerField = createAndBindCapturedLambdaParameter(info, OUTER_LAMBDA_PARAM_NAME,
-            innerLambdaClass.getEnclosingType(), ctor, ctorBody);
+            referredMethod.getEnclosingType(), ctor, ctorBody);
         instance = new JFieldRef(info,
             new JThisRef(info, innerLambdaClass), outerField, innerLambdaClass);
       } else if (referredMethod instanceof JConstructor) {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
index 23c6d6f..b7f4ba9 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
@@ -720,12 +720,10 @@
     assertTrue(ctor instanceof JConstructor);
     // instance capture
     assertEquals(1, ctor.getParams().size());
-    assertEquals(lambdaInnerClass.getEnclosingType(), ctor.getOriginalParamTypes().get(0));
-
     // should have 1 field to store the captured instance
     assertEquals(1, lambdaInnerClass.getFields().size());
-    assertEquals(lambdaInnerClass.getEnclosingType(),
-        lambdaInnerClass.getFields().get(0).getType());
+    assertEquals(lambdaInnerClass.getFields().get(0).getType(),
+        ctor.getOriginalParamTypes().get(0));
 
     // should extends test.Lambda
     assertTrue(lambdaInnerClass.getImplements().contains(program.getFromTypeMap("test.Lambda")));
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
index a50dbf8..8d896cb 100644
--- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -1666,4 +1666,16 @@
     assertEquals("Hello",
         ((FunctionalExpressionBridges_I<String>) functionalExpression).apply("Hello"));
   }
+
+  static class ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName {
+    public static String m() {
+      return null;
+    }
+  }
+   // Regression test for bug: #9426.
+  public void testCorrectNaming() {
+    Function<String> f = ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName::m;
+    assertNotNull(f);
+  }
 }
+
diff --git a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
index 6ec27ac..ff90ce9 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -304,6 +304,10 @@
     assertFalse(isGwtSourceLevel8());
   }
 
+  public void testCorrectNaming() {
+    assertFalse(isGwtSourceLevel8());
+  }
+
   private boolean isGwtSourceLevel8() {
     return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA8) >= 0;
   }