Unbox enums through Objects#toString

Bug: b/185222995
Change-Id: Iaa308ded60fbd986dbeabce8e8fdd90a13a2a35c
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 7b8fd7a..bea580f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -1556,6 +1556,10 @@
           || singleTargetReference == factory.objectsMethods.requireNonNullWithMessage) {
         return Reason.ELIGIBLE;
       }
+      if (singleTargetReference == factory.objectsMethods.toStringWithObject) {
+        addRequiredNameData(enumClass);
+        return Reason.ELIGIBLE;
+      }
       return new UnsupportedLibraryInvokeReason(singleTargetReference);
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index 789c542..a1f987b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -499,6 +499,8 @@
               getSharedUtilityClass()
                   .ensureCheckNotZeroWithMessageMethod(appView, context, eventConsumer));
         }
+      } else if (invokedMethod == factory.objectsMethods.toStringWithObject) {
+        rewriteStringValueOf(invoke, context, convertedEnums, instructionIterator, eventConsumer);
       }
       return;
     }
@@ -506,17 +508,7 @@
     // Calls to java.lang.String.
     if (invokedMethod.getHolderType() == factory.stringType) {
       if (invokedMethod == factory.stringMembers.valueOf) {
-        assert invoke.arguments().size() == 1;
-        Value argument = invoke.getFirstArgument();
-        DexType enumType = getEnumClassTypeOrNull(argument, convertedEnums);
-        if (enumType != null) {
-          ProgramMethod stringValueOfMethod =
-              getLocalUtilityClass(enumType)
-                  .ensureStringValueOfMethod(appView, context, eventConsumer);
-          instructionIterator.replaceCurrentInstruction(
-              new InvokeStatic(
-                  stringValueOfMethod.getReference(), invoke.outValue(), invoke.arguments()));
-        }
+        rewriteStringValueOf(invoke, context, convertedEnums, instructionIterator, eventConsumer);
       }
       return;
     }
@@ -574,6 +566,24 @@
     }
   }
 
+  private void rewriteStringValueOf(
+      InvokeStatic invoke,
+      ProgramMethod context,
+      Map<Instruction, DexType> convertedEnums,
+      InstructionListIterator instructionIterator,
+      EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+    assert invoke.arguments().size() == 1;
+    Value argument = invoke.getFirstArgument();
+    DexType enumType = getEnumClassTypeOrNull(argument, convertedEnums);
+    if (enumType != null) {
+      ProgramMethod stringValueOfMethod =
+          getLocalUtilityClass(enumType).ensureStringValueOfMethod(appView, context, eventConsumer);
+      instructionIterator.replaceCurrentInstruction(
+          new InvokeStatic(
+              stringValueOfMethod.getReference(), invoke.outValue(), invoke.arguments()));
+    }
+  }
+
   public void rewriteNullCheck(
       InstructionListIterator iterator,
       InvokeMethod invoke,
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java
index d8c656d..a09183d 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestParameters;
 import java.util.List;
+import java.util.Objects;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -60,9 +61,17 @@
       System.out.println(MyEnum.A.ordinal());
       System.out.println(0);
       stringValueOf();
+      objectsToString();
       stringBuilder();
     }
 
+    private static void objectsToString() {
+      System.out.println(getStringThroughObjects(MyEnum.A));
+      System.out.println("A");
+      System.out.println(getStringThroughObjects(null));
+      System.out.println("null");
+    }
+
     private static void stringValueOf() {
       System.out.println(getString(MyEnum.A));
       System.out.println("A");
@@ -133,5 +142,10 @@
     private static String getString(MyEnum e) {
       return String.valueOf(e);
     }
+
+    @NeverInline
+    private static String getStringThroughObjects(MyEnum e) {
+      return Objects.toString(e);
+    }
   }
 }