Enum unboxing: fix name overlap

Bug:160939354
Change-Id: Ib54bbf2c6d70e9a5606f211281d1b8ca95771226
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 591394e..e98ecfa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -57,6 +57,7 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -738,7 +739,11 @@
                   });
           clazz.getMethodCollection().removeMethods(methodsToRemove);
         } else {
-          clazz.getMethodCollection().replaceMethods(this::fixupEncodedMethod);
+          IntBox index = new IntBox(0);
+          clazz
+              .getMethodCollection()
+              .replaceMethods(
+                  encodedMethod -> fixupEncodedMethod(encodedMethod, index.getAndIncrement()));
           fixupFields(clazz.staticFields(), clazz::setStaticField);
           fixupFields(clazz.instanceFields(), clazz::setInstanceField);
         }
@@ -775,6 +780,7 @@
       DexProto proto =
           encodedMethod.isStatic() ? method.proto : factory.prependHolderToProto(method);
       DexMethod newMethod = factory.createMethod(newHolder, fixupProto(proto), newMethodName);
+      assert appView.definitionFor(encodedMethod.holder()).lookupMethod(newMethod) == null;
       lensBuilder.move(method, encodedMethod.isStatic(), newMethod, true);
       encodedMethod.accessFlags.promoteToPublic();
       encodedMethod.accessFlags.promoteToStatic();
@@ -783,9 +789,17 @@
       return encodedMethod.toTypeSubstitutedMethod(newMethod);
     }
 
-    private DexEncodedMethod fixupEncodedMethod(DexEncodedMethod encodedMethod) {
-      DexMethod newMethod = fixupMethod(encodedMethod.method);
-      if (newMethod != encodedMethod.method) {
+    private DexEncodedMethod fixupEncodedMethod(DexEncodedMethod encodedMethod, int index) {
+      DexProto newProto = fixupProto(encodedMethod.proto());
+      if (newProto != encodedMethod.proto()) {
+        DexString newMethodName =
+            factory.createString(
+                EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_METHOD_PREFIX
+                    + index
+                    + "$"
+                    + encodedMethod.getName().toString());
+        DexMethod newMethod = factory.createMethod(encodedMethod.holder(), newProto, newMethodName);
+        assert appView.definitionFor(encodedMethod.holder()).lookupMethod(newMethod) == null;
         boolean isStatic = encodedMethod.isStatic();
         lensBuilder.move(encodedMethod.method, isStatic, newMethod, isStatic);
         return encodedMethod.toTypeSubstitutedMethod(newMethod);
@@ -815,14 +829,6 @@
       }
     }
 
-    private DexMethod fixupMethod(DexMethod method) {
-      return fixupMethod(method, method.holder, method.name);
-    }
-
-    private DexMethod fixupMethod(DexMethod method, DexType newHolder, DexString newMethodName) {
-      return factory.createMethod(newHolder, fixupProto(method.proto), newMethodName);
-    }
-
     private DexProto fixupProto(DexProto proto) {
       DexType returnType = fixupType(proto.returnType);
       DexType[] arguments = fixupTypes(proto.parameters.values);
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java
index 4f724d3..758ed36 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingClassStaticizerTest.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ir.optimize.enums.EnumUnboxingRewriter;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.util.List;
@@ -70,7 +71,11 @@
       assertThat(codeInspector.clazz(Companion.class).uniqueMethodWithName("method"), isPresent());
       return;
     }
-    MethodSubject method = codeInspector.clazz(CompanionHost.class).uniqueMethodWithName("method");
+    MethodSubject method =
+        codeInspector
+            .clazz(CompanionHost.class)
+            .uniqueMethodWithName(
+                EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "1$method");
     assertThat(method, isPresent());
     assertEquals("int", method.getMethod().method.proto.parameters.toString());
   }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/OverloadingEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/OverloadingEnumUnboxingTest.java
new file mode 100644
index 0000000..8e206b8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/OverloadingEnumUnboxingTest.java
@@ -0,0 +1,141 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.enumunboxing;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestParameters;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class OverloadingEnumUnboxingTest extends EnumUnboxingTestBase {
+
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final EnumKeepRules enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
+    return enumUnboxingTestParameters();
+  }
+
+  public OverloadingEnumUnboxingTest(
+      TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+    this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
+  }
+
+  @Test
+  public void testEnumUnboxing() throws Exception {
+    Class<?> classToTest = TestClass.class;
+    R8TestRunResult run =
+        testForR8(parameters.getBackend())
+            .addInnerClasses(OverloadingEnumUnboxingTest.class)
+            .addKeepMainRule(classToTest)
+            .addKeepRules(enumKeepRules.getKeepRules())
+            .enableNeverClassInliningAnnotations()
+            .enableInliningAnnotations()
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+            .allowDiagnosticInfoMessages()
+            .setMinApi(parameters.getApiLevel())
+            .compile()
+            .inspectDiagnosticMessages(
+                m -> {
+                  assertEnumIsUnboxed(MyEnum1.class, MyEnum1.class.getSimpleName(), m);
+                  assertEnumIsUnboxed(MyEnum2.class, MyEnum2.class.getSimpleName(), m);
+                })
+            .run(parameters.getRuntime(), classToTest)
+            .assertSuccess();
+    assertLines2By2Correct(run.getStdOut());
+  }
+
+  @SuppressWarnings("SameParameterValue")
+  @NeverClassInline
+  enum MyEnum1 {
+    A,
+    B,
+    C;
+  }
+
+  @NeverClassInline
+  enum MyEnum2 {
+    A,
+    B,
+    C;
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      virtualTest();
+      staticTest();
+    }
+
+    @NeverInline
+    private static void staticTest() {
+      staticMethod(42);
+      System.out.println("42");
+      staticMethod(MyEnum1.A);
+      System.out.println("0");
+      staticMethod(MyEnum1.B);
+      System.out.println("1");
+      staticMethod(MyEnum2.A);
+      System.out.println("0");
+      staticMethod(MyEnum2.B);
+      System.out.println("1");
+    }
+
+    @NeverInline
+    private static void virtualTest() {
+      TestClass testClass = new TestClass();
+      testClass.virtualMethod(42);
+      System.out.println("42");
+      testClass.virtualMethod(MyEnum1.A);
+      System.out.println("0");
+      testClass.virtualMethod(MyEnum1.B);
+      System.out.println("1");
+      testClass.virtualMethod(MyEnum2.A);
+      System.out.println("0");
+      testClass.virtualMethod(MyEnum2.B);
+      System.out.println("1");
+    }
+
+    @NeverInline
+    public void virtualMethod(MyEnum1 e1) {
+      System.out.println(e1.ordinal());
+    }
+
+    @NeverInline
+    public void virtualMethod(MyEnum2 e1) {
+      System.out.println(e1.ordinal());
+    }
+
+    @NeverInline
+    public void virtualMethod(int i) {
+      System.out.println(i);
+    }
+
+    @NeverInline
+    public static void staticMethod(MyEnum1 e1) {
+      System.out.println(e1.ordinal());
+    }
+
+    @NeverInline
+    public static void staticMethod(MyEnum2 e1) {
+      System.out.println(e1.ordinal());
+    }
+
+    @NeverInline
+    public static void staticMethod(int i) {
+      System.out.println(i);
+    }
+  }
+}