Enum unboxing: parametrize tests

- Add enumValueOpt parameter, since the
  enumValueOptimization have important side
  effects on enumUnboxing.
- Add enumKeepRules parameter, since big
  apps such as Youtube do not have these
  keep rules but all apps on studio have it.
- Fix a bug where EnumUnboxing would raise
  an assertion error when the input was
  invalid (don't unbox instead).

Bug: 147860220
Change-Id: I6a7562ad218fdacb82412ca50dbcc15f7c14db19
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 5d737b5..b3a25d0 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
@@ -143,7 +143,13 @@
       assert enumClass != null;
 
       DexEncodedMethod initializer = enumClass.lookupDirectMethod(factory.enumMethods.constructor);
-      assert initializer != null;
+      if (initializer == null) {
+        // This case typically happens when a programmer uses EnumSet/EnumMap without using the
+        // enum keep rules. The code is incorrect in this case (EnumSet/EnumMap won't work).
+        // We bail out.
+        markEnumAsUnboxable(Reason.NO_INIT, enumClass);
+        continue;
+      }
       if (initializer.getOptimizationInfo().mayHaveSideEffects()) {
         markEnumAsUnboxable(Reason.INVALID_INIT, enumClass);
         continue;
@@ -325,6 +331,7 @@
     VIRTUAL_METHOD,
     UNEXPECTED_DIRECT_METHOD,
     INVALID_PHI,
+    NO_INIT,
     INVALID_INIT,
     INVALID_CLINIT,
     INVALID_INVOKE,
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ComparisonEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ComparisonEnumUnboxingAnalysisTest.java
index ddcb725..a15dc08 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/ComparisonEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ComparisonEnumUnboxingAnalysisTest.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -19,16 +19,22 @@
 @RunWith(Parameterized.class)
 public class ComparisonEnumUnboxingAnalysisTest extends EnumUnboxingTestBase {
 
-  private final TestParameters parameters;
-  private final Class<?>[] INPUTS = new Class<?>[] {NullCheck.class, EnumComparison.class};
+  private static final Class<?>[] INPUTS = new Class<?>[] {NullCheck.class, EnumComparison.class};
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public ComparisonEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public ComparisonEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
   @Test
@@ -37,9 +43,9 @@
         testForR8(parameters.getBackend())
             .addInnerClasses(ComparisonEnumUnboxingAnalysisTest.class)
             .addKeepMainRules(INPUTS)
-            .addKeepRules(KEEP_ENUM)
             .enableInliningAnnotations()
-            .addOptionsModification(this::enableEnumOptions)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .setMinApi(parameters.getApiLevel())
             .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
index 332ad2e..b7ebc83 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
@@ -10,9 +10,9 @@
 import com.android.tools.r8.Diagnostic;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestDiagnosticMessages;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.List;
@@ -34,8 +34,9 @@
     }
   }
 
-  void enableEnumOptions(InternalOptions options) {
+  void enableEnumOptions(InternalOptions options, boolean enumValueOptimization) {
     options.enableEnumUnboxing = true;
+    options.enableEnumValueOptimization = enumValueOptimization;
     options.testing.enableEnumUnboxingDebugLogs = true;
   }
 
@@ -55,12 +56,15 @@
         diagnostic.getDiagnosticMessage().contains(enumClass.getSimpleName()));
   }
 
-  static TestParametersCollection enumUnboxingTestParameters() {
-    return getTestParameters()
-        .withCfRuntime(CfVm.JDK9)
-        .withDexRuntime(DexVm.Version.first())
-        .withDexRuntime(DexVm.Version.last())
-        .withAllApiLevels()
-        .build();
+  static List<Object[]> enumUnboxingTestParameters() {
+    return buildParameters(
+        getTestParameters()
+            .withCfRuntime(CfVm.JDK9)
+            .withDexRuntime(DexVm.Version.first())
+            .withDexRuntime(DexVm.Version.last())
+            .withAllApiLevels()
+            .build(),
+        BooleanUtils.values(),
+        BooleanUtils.values());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/FailingEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/FailingEnumUnboxingAnalysisTest.java
index 9c4872f..c0eeaf4 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/FailingEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/FailingEnumUnboxingAnalysisTest.java
@@ -12,13 +12,13 @@
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.enumunboxing.FailingEnumUnboxingAnalysisTest.EnumInstanceFieldMain.EnumInstanceField;
 import com.android.tools.r8.enumunboxing.FailingEnumUnboxingAnalysisTest.EnumInterfaceMain.EnumInterface;
 import com.android.tools.r8.enumunboxing.FailingEnumUnboxingAnalysisTest.EnumStaticFieldMain.EnumStaticField;
 import com.android.tools.r8.enumunboxing.FailingEnumUnboxingAnalysisTest.EnumStaticMethodMain.EnumStaticMethod;
 import com.android.tools.r8.enumunboxing.FailingEnumUnboxingAnalysisTest.EnumVirtualMethodMain.EnumVirtualMethod;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -36,14 +36,19 @@
   };
 
   private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public FailingEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public FailingEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
   @Test
@@ -57,8 +62,8 @@
         r8FullTestBuilder
             .noTreeShaking() // Disabled to avoid merging Itf into EnumInterface.
             .enableInliningAnnotations()
-            .addKeepRules(KEEP_ENUM)
-            .addOptionsModification(this::enableEnumOptions)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .setMinApi(parameters.getApiLevel())
             .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingAnalysisTest.java
index c7ad117..944c9c3 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/FailingMethodEnumUnboxingAnalysisTest.java
@@ -11,9 +11,9 @@
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.util.EnumSet;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -31,14 +31,19 @@
   };
 
   private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public FailingMethodEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public FailingMethodEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
   @Test
@@ -47,13 +52,10 @@
         testForR8(parameters.getBackend())
             .addInnerClasses(FailingMethodEnumUnboxingAnalysisTest.class)
             .addKeepMainRules(FAILURES)
-            .addKeepRules(KEEP_ENUM)
-            .addOptionsModification(this::enableEnumOptions)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .enableInliningAnnotations()
-            .addOptionsModification(
-                // Disabled to avoid toString() being removed.
-                opt -> opt.enableEnumValueOptimization = false)
             .setMinApi(parameters.getApiLevel())
             .compile()
             .inspect(this::assertEnumsAsExpected);
@@ -64,9 +66,14 @@
                   m ->
                       assertEnumIsBoxed(
                           failure.getDeclaredClasses()[0], failure.getSimpleName(), m))
-              .run(parameters.getRuntime(), failure)
-              .assertSuccess();
-      assertLines2By2Correct(run.getStdOut());
+              .run(parameters.getRuntime(), failure);
+      if (failure == EnumSetTest.class && !enumKeepRules) {
+        // EnumSet and EnumMap cannot be used without the enumKeepRules.
+        run.assertFailure();
+      } else {
+        run.assertSuccess();
+        assertLines2By2Correct(run.getStdOut());
+      }
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingAnalysisTest.java
index 8811ee5..daaf504 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/FieldPutEnumUnboxingAnalysisTest.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -19,17 +19,23 @@
 @RunWith(Parameterized.class)
 public class FieldPutEnumUnboxingAnalysisTest extends EnumUnboxingTestBase {
 
-  private final TestParameters parameters;
   private static final Class<?>[] INPUTS =
       new Class<?>[] {InstanceFieldPut.class, StaticFieldPut.class};
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public FieldPutEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public FieldPutEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
   @Test
@@ -38,8 +44,8 @@
         testForR8(parameters.getBackend())
             .addInnerClasses(FieldPutEnumUnboxingAnalysisTest.class)
             .addKeepMainRules(INPUTS)
-            .addKeepRules(KEEP_ENUM)
-            .addOptionsModification(this::enableEnumOptions)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .enableInliningAnnotations()
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/OrdinalEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/OrdinalEnumUnboxingAnalysisTest.java
index 2570a12..afd2e6a 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/OrdinalEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/OrdinalEnumUnboxingAnalysisTest.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -15,19 +15,24 @@
 @RunWith(Parameterized.class)
 public class OrdinalEnumUnboxingAnalysisTest extends EnumUnboxingTestBase {
 
-  private final TestParameters parameters;
+  private static final Class<?> ENUM_CLASS = MyEnum.class;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public OrdinalEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public OrdinalEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
-  private static final Class<?> ENUM_CLASS = MyEnum.class;
-
   @Test
   public void testEnumUnboxing() throws Exception {
     Class<Ordinal> classToTest = Ordinal.class;
@@ -35,8 +40,8 @@
         testForR8(parameters.getBackend())
             .addProgramClasses(classToTest, ENUM_CLASS)
             .addKeepMainRule(classToTest)
-            .addKeepRules(KEEP_ENUM)
-            .addOptionsModification(this::enableEnumOptions)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .setMinApi(parameters.getApiLevel())
             .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/PhiEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/PhiEnumUnboxingAnalysisTest.java
index 2abd358..b231d32 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/PhiEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/PhiEnumUnboxingAnalysisTest.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -16,19 +16,24 @@
 @RunWith(Parameterized.class)
 public class PhiEnumUnboxingAnalysisTest extends EnumUnboxingTestBase {
 
-  private final TestParameters parameters;
+  private static final Class<?> ENUM_CLASS = MyEnum.class;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public PhiEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public PhiEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
-  private static final Class<?> ENUM_CLASS = MyEnum.class;
-
   @Test
   public void testEnumUnboxing() throws Exception {
     Class<?> classToTest = Phi.class;
@@ -36,9 +41,9 @@
         testForR8(parameters.getBackend())
             .addProgramClasses(classToTest, ENUM_CLASS)
             .addKeepMainRule(classToTest)
-            .addKeepRules(KEEP_ENUM)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
             .enableInliningAnnotations()
-            .addOptionsModification(this::enableEnumOptions)
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .setMinApi(parameters.getApiLevel())
             .compile()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingAnalysisTest.java b/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingAnalysisTest.java
index 53cddc6..a40dec0 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/SwitchEnumUnboxingAnalysisTest.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -16,19 +16,24 @@
 @RunWith(Parameterized.class)
 public class SwitchEnumUnboxingAnalysisTest extends EnumUnboxingTestBase {
 
-  private final TestParameters parameters;
+  private static final Class<?> ENUM_CLASS = MyEnum.class;
 
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final boolean enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
     return enumUnboxingTestParameters();
   }
 
-  public SwitchEnumUnboxingAnalysisTest(TestParameters parameters) {
+  public SwitchEnumUnboxingAnalysisTest(
+      TestParameters parameters, boolean enumValueOptimization, boolean enumKeepRules) {
     this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
   }
 
-  private static final Class<?> ENUM_CLASS = MyEnum.class;
-
   @Test
   public void testEnumUnboxing() throws Exception {
     Class<Switch> classToTest = Switch.class;
@@ -36,9 +41,9 @@
         testForR8(parameters.getBackend())
             .addInnerClasses(SwitchEnumUnboxingAnalysisTest.class)
             .addKeepMainRule(classToTest)
-            .addKeepRules(KEEP_ENUM)
+            .addKeepRules(enumKeepRules ? KEEP_ENUM : "")
             .enableInliningAnnotations()
-            .addOptionsModification(this::enableEnumOptions)
+            .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
             .allowDiagnosticInfoMessages()
             .setMinApi(parameters.getApiLevel())
             .compile()