Enum unboxing and lambda cf to cf

Bug: 204174455
Change-Id: I5e65ba322ebcc5179c5bb5992946f1b81369247b
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
index 0353705..dd5b328 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
 import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
@@ -26,6 +27,8 @@
 import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -78,15 +81,34 @@
         isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
     List<DexValue> newArgs =
         rewriteBootstrapArguments(callSite.bootstrapArgs, methodHandleUse, context);
+    DexString newMethodName = computeNewMethodName(callSite, context, isLambdaMetaFactory);
     if (!newMethodProto.equals(callSite.methodProto)
+        || newMethodName != callSite.methodName
         || newBootstrapMethod != callSite.bootstrapMethod
         || !newArgs.equals(callSite.bootstrapArgs)) {
       return dexItemFactory.createCallSite(
-          callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
+          newMethodName, newMethodProto, newBootstrapMethod, newArgs);
     }
     return callSite;
   }
 
+  private DexString computeNewMethodName(
+      DexCallSite callSite, ProgramMethod context, boolean isLambdaMetaFactory) {
+    if (!isLambdaMetaFactory) {
+      return callSite.methodName;
+    }
+    assert callSite.getBootstrapArgs().size() > 0;
+    assert callSite.getBootstrapArgs().get(0).isDexValueMethodType();
+    // The targeted method may have been renamed, we need to update the name if that is the case.
+    DexMethod method =
+        LambdaDescriptor.getMainFunctionalInterfaceMethodReference(
+            callSite, definitions.dexItemFactory());
+    return graphLens
+        .lookupMethod(method, context.getReference(), Invoke.Type.INTERFACE)
+        .getReference()
+        .getName();
+  }
+
   public DexMethodHandle rewriteDexMethodHandle(
       DexMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) {
     if (methodHandle.isMethodHandle()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index edfa934..887f18e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -255,6 +255,15 @@
     return descriptor == MATCH_FAILED ? null : descriptor;
   }
 
+  public static DexMethod getMainFunctionalInterfaceMethodReference(
+      DexCallSite callSite, DexItemFactory factory) {
+    DexProto proto = callSite.getBootstrapArgs().get(0).asDexValueMethodType().value;
+    DexProto lambdaFactoryProto = callSite.methodProto;
+    DexType mainInterface = lambdaFactoryProto.returnType;
+    DexString funcMethodName = callSite.methodName;
+    return factory.createMethod(mainInterface, proto, funcMethodName);
+  }
+
   public static boolean isLambdaMetafactoryMethod(
       DexCallSite callSite, DexDefinitionSupplier definitions) {
     return callSite.bootstrapMethod.type.isInvokeStatic()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
new file mode 100644
index 0000000..288ace4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, 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.NoVerticalClassMerging;
+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 LambdaEnumUnboxingEmptyEnumTest 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(getTestParameters().withAllRuntimesAndApiLevels().build());
+  }
+
+  public LambdaEnumUnboxingEmptyEnumTest(
+      TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+    this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
+  }
+
+  @Test
+  public void testEnumUnboxing() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addKeepRules(enumKeepRules.getKeepRules())
+        .enableNeverClassInliningAnnotations()
+        .noMinification()
+        .enableNoVerticalClassMergingAnnotations()
+        .enableInliningAnnotations()
+        .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+        .addEnumUnboxingInspector(
+            inspector -> inspector.assertUnboxedIf(enumKeepRules.isNone(), MyEnum.class))
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("null");
+  }
+
+  @NeverClassInline
+  enum MyEnum {}
+
+  @NoVerticalClassMerging
+  interface MyEnumConsumer {
+
+    void accept(MyEnum e);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      execute(e -> System.out.println(String.valueOf(e)));
+    }
+
+    @NeverInline
+    static void execute(MyEnumConsumer consumer) {
+      consumer.accept(null);
+    }
+  }
+}