Rewrite enums and DexItemBasedValueStrings in annotations

Bug: 174742877
Change-Id: Id79511ff76d6e456a01b1b154b1a52202a890bba
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 97d304b..f355030 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -307,6 +307,10 @@
     return null;
   }
 
+  public boolean isNestedDexValue() {
+    return false;
+  }
+
   public abstract AbstractValue toAbstractValue(AbstractValueFactory factory);
 
   static DexValue fromAsmBootstrapArgument(
@@ -1133,6 +1137,11 @@
     }
 
     @Override
+    public boolean isNestedDexValue() {
+      return true;
+    }
+
+    @Override
     public DexType getType(DexItemFactory factory) {
       throw new Unreachable();
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java b/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
index a67af38..4fdad6a 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationFixer.java
@@ -4,15 +4,21 @@
 
 package com.android.tools.r8.shaking;
 
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationElement;
 import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexItemBasedValueString;
+import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
+import com.android.tools.r8.graph.DexValue.DexValueEnum;
 import com.android.tools.r8.graph.DexValue.DexValueType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.utils.ArrayUtils;
@@ -56,27 +62,65 @@
   }
 
   private DexAnnotationElement rewriteAnnotationElement(DexAnnotationElement original) {
-    DexValue rewrittenValue = rewriteValue(original.value);
+    DexValue rewrittenValue = rewriteComplexValue(original.value);
     if (rewrittenValue != original.value) {
       return new DexAnnotationElement(original.name, rewrittenValue);
     }
     return original;
   }
 
-  private DexValue rewriteValue(DexValue value) {
-    if (value.isDexValueType()) {
+  private DexValue rewriteComplexValue(DexValue value) {
+    if (value.isDexValueArray()) {
+      DexValue[] originalValues = value.asDexValueArray().getValues();
+      DexValue[] rewrittenValues =
+          ArrayUtils.map(DexValue[].class, originalValues, this::rewriteComplexValue);
+      if (rewrittenValues != originalValues) {
+        return new DexValueArray(rewrittenValues);
+      }
+    } else if (value.isDexValueAnnotation()) {
+      DexValueAnnotation original = value.asDexValueAnnotation();
+      DexEncodedAnnotation rewritten = rewriteEncodedAnnotation(original.getValue());
+      if (original.value == rewritten) {
+        return value;
+      }
+      return new DexValueAnnotation(rewritten);
+    }
+    return rewriteNestedValue(value);
+  }
+
+  private DexValue rewriteNestedValue(DexValue value) {
+    if (value.isDexItemBasedValueString()) {
+      DexItemBasedValueString valueString = value.asDexItemBasedValueString();
+      DexReference original = valueString.value;
+      DexReference rewritten = lens.lookupReference(original);
+      if (original != rewritten) {
+        return new DexItemBasedValueString(rewritten, valueString.getNameComputationInfo());
+      }
+    } else if (value.isDexValueEnum()) {
+      DexField original = value.asDexValueEnum().value;
+      DexField rewritten = lens.lookupField(original);
+      if (original != rewritten) {
+        return new DexValueEnum(rewritten);
+      }
+    } else if (value.isDexValueField()) {
+      throw new Unreachable("Unexpected field in annotation");
+    } else if (value.isDexValueMethod()) {
+      throw new Unreachable("Unexpected method in annotation");
+    } else if (value.isDexValueMethodHandle()) {
+      throw new Unreachable("Unexpected method handle in annotation");
+    } else if (value.isDexValueMethodType()) {
+      throw new Unreachable("Unexpected method type in annotation");
+    } else if (value.isDexValueString()) {
+      // If we identified references in the string it would be a DexItemBasedValueString.
+    } else if (value.isDexValueType()) {
       DexType originalType = value.asDexValueType().value;
       DexType rewrittenType = lens.lookupType(originalType);
       if (rewrittenType != originalType) {
         return new DexValueType(rewrittenType);
       }
-    } else if (value.isDexValueArray()) {
-      DexValue[] originalValues = value.asDexValueArray().getValues();
-      DexValue[] rewrittenValues =
-          ArrayUtils.map(DexValue[].class, originalValues, this::rewriteValue);
-      if (rewrittenValues != originalValues) {
-        return new DexValueArray(rewrittenValues);
-      }
+    } else {
+      // Assert that we have not forgotten a value.
+      assert !value.isNestedDexValue();
     }
     return value;
   }
diff --git a/src/test/java/com/android/tools/r8/repackage/EnumAndIdentifierBasedStringInAnnotationTest.java b/src/test/java/com/android/tools/r8/repackage/EnumAndIdentifierBasedStringInAnnotationTest.java
index 4f22f5c..f542e6e 100644
--- a/src/test/java/com/android/tools/r8/repackage/EnumAndIdentifierBasedStringInAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/EnumAndIdentifierBasedStringInAnnotationTest.java
@@ -8,7 +8,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -47,14 +46,7 @@
         .compile()
         .inspect(inspector -> assertThat(inspector.clazz(Enum.class), isPresentAndRenamed()))
         .run(parameters.getRuntime(), Main.class)
-        // It is truly amazing that these two ART VMs can find the value with incorrect names :)
-        .forDexRuntimeSatisfying(
-            version ->
-                version.isNewerThanOrEqual(Version.V5_1_1)
-                    && version.isOlderThanOrEqual(Version.V6_0_1),
-            result -> result.assertSuccessWithOutputLines("TEST_ONE"))
-        // TODO(b/174742877): We should not throw an error.
-        .otherwise(result -> result.assertFailureWithErrorThatThrows(ClassNotFoundException.class));
+        .assertSuccessWithOutputLines("TEST_ONE");
   }
 
   public enum Enum {