Update handling of @CovariantReturnType

This performs a minor overhaul of the CovariantReturnTypeAnnotationTransformer.

Changes include:

- Limit @CovariantReturnType processing to Android platform builds
- Limit @CovariantReturnType processing to apps that contain or reference CovariantReturnType
- Parallelize DEX conversion of the synthesized bridge methods
- Avoid decoding DexStrings from inside @CovariantReturnType annotations
- Simplify and prepare CovariantReturnTypeAnnotationTransformer for easy adoption in R8

Change-Id: I2692035be1992130e40135a243f38e76536d19c4
diff --git a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java
index cbd23f5..55f4d78 100644
--- a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeAnnotationTransformer.java
@@ -7,30 +7,30 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationElement;
-import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-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.DexValueAnnotation;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.DexValue.DexValueType;
-import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.conversion.MethodConversionOptions;
 import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
 import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
-import com.google.common.base.Predicates;
-import java.util.HashSet;
-import java.util.LinkedList;
+import com.android.tools.r8.utils.ForEachable;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
 
 // Responsible for processing the annotations dalvik.annotation.codegen.CovariantReturnType and
 // dalvik.annotation.codegen.CovariantReturnType$CovariantReturnTypes.
@@ -54,105 +54,83 @@
 // the contained CovariantReturnType annotations.
 public final class CovariantReturnTypeAnnotationTransformer {
 
+  private final AppView<?> appView;
   private final IRConverter converter;
-  private final MethodProcessorEventConsumer methodProcessorEventConsumer =
-      MethodProcessorEventConsumer.empty();
   private final DexItemFactory factory;
+  private final CovariantReturnTypeReferences references;
 
-  public CovariantReturnTypeAnnotationTransformer(AppView<?> appView, IRConverter converter) {
+  private CovariantReturnTypeAnnotationTransformer(AppView<?> appView, IRConverter converter) {
+    this.appView = appView;
     this.converter = converter;
     this.factory = appView.dexItemFactory();
+    this.references = new CovariantReturnTypeReferences(factory);
   }
 
-  // TODO(b/270398965): Replace LinkedList.
-  @SuppressWarnings("JdkObsolete")
-  public void process(
-      DexApplication.Builder<?> builder,
-      CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer) {
-    // List of methods that should be added to the next class.
-    List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation = new LinkedList<>();
-    List<DexEncodedMethod> covariantReturnTypeMethods = new LinkedList<>();
-    for (DexProgramClass clazz : builder.getProgramClasses()) {
-      // Construct the methods that should be added to clazz.
-      buildCovariantReturnTypeMethodsForClass(
-          clazz,
-          methodsWithCovariantReturnTypeAnnotation,
-          covariantReturnTypeMethods,
-          eventConsumer);
-      if (covariantReturnTypeMethods.isEmpty()) {
-        continue;
-      }
-      updateClass(clazz, methodsWithCovariantReturnTypeAnnotation, covariantReturnTypeMethods);
-      // Reset lists for the next class that will have a CovariantReturnType or
-      // CovariantReturnType$CovariantReturnTypes annotation.
-      methodsWithCovariantReturnTypeAnnotation.clear();
-      covariantReturnTypeMethods.clear();
+  public static void runIfNecessary(
+      AppView<?> appView,
+      IRConverter converter,
+      CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer,
+      ExecutorService executorService)
+      throws ExecutionException {
+    if (!appView.options().processCovariantReturnTypeAnnotations) {
+      return;
     }
+    assert !appView.options().isDesugaredLibraryCompilation();
+    DexItemFactory factory = appView.dexItemFactory();
+    DexString covariantReturnTypeDescriptor =
+        factory.createString(CovariantReturnTypeReferences.COVARIANT_RETURN_TYPE_DESCRIPTOR);
+    if (factory.lookupType(covariantReturnTypeDescriptor) == null) {
+      return;
+    }
+    new CovariantReturnTypeAnnotationTransformer(appView, converter)
+        .run(eventConsumer, executorService);
   }
 
-  private void updateClass(
-      DexClass clazz,
-      List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation,
-      List<DexEncodedMethod> covariantReturnTypeMethods) {
-    // It is a compilation error if the class already has a method with a signature similar to one
-    // of the methods in covariantReturnTypeMethods.
-    for (DexEncodedMethod syntheticMethod : covariantReturnTypeMethods) {
-      if (hasVirtualMethodWithSignature(clazz, syntheticMethod)) {
-        throw new CompilationError(
-            String.format(
-                "Cannot process CovariantReturnType annotation: Class %s already "
-                    + "has a method \"%s\"",
-                clazz.getType(), syntheticMethod.toSourceString()));
-      }
+  private void run(
+      CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer,
+      ExecutorService executorService)
+      throws ExecutionException {
+    List<ProgramMethod> covariantReturnTypeMethods = new ArrayList<>();
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      List<ProgramMethod> newCovariantReturnTypeMethods =
+          processClass(clazz, clazz::forEachProgramVirtualMethod, eventConsumer);
+      covariantReturnTypeMethods.addAll(newCovariantReturnTypeMethods);
     }
-    // Remove the CovariantReturnType annotations.
-    for (DexEncodedMethod method : methodsWithCovariantReturnTypeAnnotation) {
-      method.setAnnotations(
-          method.annotations().keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)));
-    }
-    // Add the newly constructed methods to the class.
-    clazz.addVirtualMethods(covariantReturnTypeMethods);
+    // Convert methods to DEX.
+    converter.optimizeSynthesizedMethods(
+        covariantReturnTypeMethods,
+        MethodProcessorEventConsumer.empty(),
+        MethodConversionOptions.forD8(appView),
+        executorService);
   }
 
   // Processes all the dalvik.annotation.codegen.CovariantReturnType and dalvik.annotation.codegen.
   // CovariantReturnTypes annotations in the given DexClass. Adds the newly constructed, synthetic
   // methods to the list covariantReturnTypeMethods.
-  private void buildCovariantReturnTypeMethodsForClass(
+  private List<ProgramMethod> processClass(
       DexProgramClass clazz,
-      List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation,
-      List<DexEncodedMethod> covariantReturnTypeMethods,
+      ForEachable<ProgramMethod> methodsToProcess,
       CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer) {
-    clazz.forEachProgramVirtualMethod(
-        method -> {
-          if (methodHasCovariantReturnTypeAnnotation(method.getDefinition())) {
-            methodsWithCovariantReturnTypeAnnotation.add(method.getDefinition());
-            buildCovariantReturnTypeMethodsForMethod(
-                method, covariantReturnTypeMethods, eventConsumer);
-          }
-        });
-  }
-
-  private boolean methodHasCovariantReturnTypeAnnotation(DexEncodedMethod method) {
-    for (DexAnnotation annotation : method.annotations().annotations) {
-      if (isCovariantReturnTypeAnnotation(annotation.annotation)) {
-        return true;
-      }
-    }
-    return false;
+    List<ProgramMethod> covariantReturnTypeMethods = new ArrayList<>();
+    methodsToProcess.forEach(
+        method ->
+            processMethod(
+                method,
+                covariantReturnTypeMethod -> {
+                  covariantReturnTypeMethods.add(covariantReturnTypeMethod);
+                  eventConsumer.acceptCovariantReturnTypeBridgeMethod(
+                      covariantReturnTypeMethod, method);
+                }));
+    clazz.getMethodCollection().addVirtualClassMethods(covariantReturnTypeMethods);
+    return covariantReturnTypeMethods;
   }
 
   // Processes all the dalvik.annotation.codegen.CovariantReturnType and dalvik.annotation.Co-
   // variantReturnTypes annotations on the given method. Adds the newly constructed, synthetic
   // methods to the list covariantReturnTypeMethods.
-  private void buildCovariantReturnTypeMethodsForMethod(
-      ProgramMethod method,
-      List<DexEncodedMethod> covariantReturnTypeMethods,
-      CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer) {
-    assert methodHasCovariantReturnTypeAnnotation(method.getDefinition());
-    for (DexType covariantReturnType : getCovariantReturnTypes(method)) {
-      DexEncodedMethod covariantReturnTypeMethod =
-          buildCovariantReturnTypeMethod(method, covariantReturnType, eventConsumer);
-      covariantReturnTypeMethods.add(covariantReturnTypeMethod);
+  private void processMethod(ProgramMethod method, Consumer<ProgramMethod> consumer) {
+    for (DexType covariantReturnType : clearCovariantReturnTypeAnnotations(method)) {
+      consumer.accept(buildCovariantReturnTypeMethod(method, covariantReturnType));
     }
   }
 
@@ -161,48 +139,43 @@
   // type covariantReturnType.
   //
   // Note: any "synchronized" or "strictfp" modifier could be dropped safely.
-  private DexEncodedMethod buildCovariantReturnTypeMethod(
-      ProgramMethod method,
-      DexType covariantReturnType,
-      CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer) {
-    DexProgramClass methodHolder = method.getHolder();
-    DexMethod methodReference = method.getReference();
-    DexEncodedMethod methodDefinition = method.getDefinition();
-    DexProto newProto = factory.createProto(covariantReturnType, methodReference.proto.parameters);
-    MethodAccessFlags newAccessFlags = methodDefinition.accessFlags.copy();
-    newAccessFlags.setBridge();
-    newAccessFlags.setSynthetic();
-    newAccessFlags.unsetAbstract(); // Synthetic bridge has code, so never abstract.
-    DexMethod newMethod =
-        factory.createMethod(methodHolder.getType(), newProto, methodReference.getName());
-    ForwardMethodBuilder forwardMethodBuilder =
-        ForwardMethodBuilder.builder(factory)
-            .setNonStaticSource(newMethod)
-            .setVirtualTarget(methodReference, methodHolder.isInterface())
-            .setCastResult();
-    DexEncodedMethod newVirtualMethod =
+  private ProgramMethod buildCovariantReturnTypeMethod(
+      ProgramMethod method, DexType covariantReturnType) {
+    DexMethod covariantReturnTypeMethodReference =
+        method.getReference().withReturnType(covariantReturnType, factory);
+    failIfPresent(method.getHolder(), covariantReturnTypeMethodReference);
+    DexEncodedMethod definition =
         DexEncodedMethod.syntheticBuilder()
-            .setMethod(newMethod)
-            .setAccessFlags(newAccessFlags)
-            .setGenericSignature(methodDefinition.getGenericSignature())
-            .setAnnotations(
-                methodDefinition
-                    .annotations()
-                    .keepIf(x -> !isCovariantReturnTypeAnnotation(x.annotation)))
-            .setParameterAnnotations(
-                methodDefinition.parameterAnnotationsList.keepIf(Predicates.alwaysTrue()))
-            .setCode(forwardMethodBuilder.buildCf())
-            .setApiLevelForDefinition(methodDefinition.getApiLevelForDefinition())
-            .setApiLevelForCode(methodDefinition.getApiLevelForCode())
+            .setMethod(covariantReturnTypeMethodReference)
+            .setAccessFlags(
+                method.getAccessFlags().copy().setBridge().setSynthetic().unsetAbstract())
+            .setGenericSignature(method.getDefinition().getGenericSignature())
+            .setAnnotations(method.getAnnotations())
+            .setParameterAnnotations(method.getParameterAnnotations())
+            .setCode(
+                ForwardMethodBuilder.builder(factory)
+                    .setNonStaticSource(covariantReturnTypeMethodReference)
+                    .setVirtualTarget(method.getReference(), method.getHolder().isInterface())
+                    .setCastResult()
+                    .buildCf())
+            .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
+            .setApiLevelForCode(method.getDefinition().getApiLevelForCode())
             .build();
-    // Optimize to generate DexCode instead of CfCode.
-    ProgramMethod programMethod = new ProgramMethod(methodHolder, newVirtualMethod);
-    converter.optimizeSynthesizedMethod(
-        programMethod,
-        methodProcessorEventConsumer,
-        MethodConversionOptions.forD8(converter.appView));
-    eventConsumer.acceptCovariantReturnTypeBridgeMethod(programMethod, method);
-    return newVirtualMethod;
+    return new ProgramMethod(method.getHolder(), definition);
+  }
+
+  private void failIfPresent(DexProgramClass clazz, DexMethod covariantReturnTypeMethodReference) {
+    // It is a compilation error if the class already has a method with a signature similar to one
+    // of the methods in covariantReturnTypeMethods.
+    if (clazz.lookupMethod(covariantReturnTypeMethodReference) != null) {
+      throw appView
+          .reporter()
+          .fatalError(
+              String.format(
+                  "Cannot process CovariantReturnType annotation: Class %s already "
+                      + "has a method \"%s\"",
+                  clazz.getTypeName(), covariantReturnTypeMethodReference.toSourceString()));
+    }
   }
 
   // Returns the set of covariant return types for method.
@@ -213,33 +186,36 @@
   //   @Override
   //   public Foo foo() { ... return new SubOfSubOfFoo(); }
   // then this method returns the set { SubOfFoo, SubOfSubOfFoo }.
-  private Set<DexType> getCovariantReturnTypes(ProgramMethod method) {
-    Set<DexType> covariantReturnTypes = new HashSet<>();
-    for (DexAnnotation annotation : method.getDefinition().annotations().annotations) {
-      if (isCovariantReturnTypeAnnotation(annotation.annotation)) {
+  private Set<DexType> clearCovariantReturnTypeAnnotations(ProgramMethod method) {
+    Set<DexType> covariantReturnTypes = new LinkedHashSet<>();
+    for (DexAnnotation annotation : method.getAnnotations().getAnnotations()) {
+      if (references.isOneOfCovariantReturnTypeAnnotations(annotation.getAnnotationType())) {
         getCovariantReturnTypesFromAnnotation(
-            method.getHolder(),
-            method.getDefinition(),
-            annotation.annotation,
-            covariantReturnTypes);
+            method, annotation.getAnnotation(), covariantReturnTypes);
       }
     }
+    if (!covariantReturnTypes.isEmpty()) {
+      method
+          .getDefinition()
+          .setAnnotations(
+              method
+                  .getAnnotations()
+                  .removeIf(
+                      annotation ->
+                          references.isOneOfCovariantReturnTypeAnnotations(
+                              annotation.getAnnotationType())));
+    }
     return covariantReturnTypes;
   }
 
-  @SuppressWarnings("ReferenceEquality")
   private void getCovariantReturnTypesFromAnnotation(
-      DexClass clazz,
-      DexEncodedMethod method,
-      DexEncodedAnnotation annotation,
-      Set<DexType> covariantReturnTypes) {
-    assert isCovariantReturnTypeAnnotation(annotation);
+      ProgramMethod method, DexEncodedAnnotation annotation, Set<DexType> covariantReturnTypes) {
     boolean hasPresentAfterElement = false;
     for (DexAnnotationElement element : annotation.elements) {
-      String name = element.name.toString();
-      if (annotation.type == factory.annotationCovariantReturnType) {
-        if (name.equals("returnType")) {
-          DexValueType dexValueType = element.value.asDexValueType();
+      DexString name = element.getName();
+      if (references.isCovariantReturnTypeAnnotation(annotation.getType())) {
+        if (name.isIdenticalTo(references.returnTypeName)) {
+          DexValueType dexValueType = element.getValue().asDexValueType();
           if (dexValueType == null) {
             throw new CompilationError(
                 String.format(
@@ -247,19 +223,20 @@
                         + "reference a type (method: \"%s\", was: %s)",
                     method.toSourceString(), element.value.getClass().getCanonicalName()));
           }
-          covariantReturnTypes.add(dexValueType.value);
-        } else if (name.equals("presentAfter")) {
+          covariantReturnTypes.add(dexValueType.getValue());
+        } else if (name.isIdenticalTo(references.presentAfterName)) {
           hasPresentAfterElement = true;
         }
       } else {
-        if (name.equals("value")) {
-          DexValueArray array = element.value.asDexValueArray();
+        assert references.isCovariantReturnTypesAnnotation(annotation.getType());
+        if (name.isIdenticalTo(references.valueName)) {
+          DexValueArray array = element.getValue().asDexValueArray();
           if (array == null) {
             throw new CompilationError(
                 String.format(
                     "Expected element \"value\" of CovariantReturnTypes annotation to "
                         + "be an array (method: \"%s\", was: %s)",
-                    method.toSourceString(), element.value.getClass().getCanonicalName()));
+                    method.toSourceString(), element.getValue().getClass().getCanonicalName()));
           }
 
           // Handle the inner dalvik.annotation.codegen.CovariantReturnType annotations recursively.
@@ -267,42 +244,19 @@
             assert value.isDexValueAnnotation();
             DexValueAnnotation innerAnnotation = value.asDexValueAnnotation();
             getCovariantReturnTypesFromAnnotation(
-                clazz, method, innerAnnotation.value, covariantReturnTypes);
+                method, innerAnnotation.getValue(), covariantReturnTypes);
           }
         }
       }
     }
 
-    if (annotation.type == factory.annotationCovariantReturnType && !hasPresentAfterElement) {
+    if (references.isCovariantReturnTypeAnnotation(annotation.getType())
+        && !hasPresentAfterElement) {
       throw new CompilationError(
           String.format(
               "CovariantReturnType annotation for method \"%s\" is missing mandatory element "
                   + "\"presentAfter\" (class %s)",
-              clazz.getType(), method.toSourceString()));
+              method.toSourceString(), method.getHolder().getType()));
     }
   }
-
-  public boolean isCovariantReturnTypeAnnotation(DexEncodedAnnotation annotation) {
-    return isCovariantReturnTypeAnnotation(annotation, factory);
-  }
-
-  public static boolean isCovariantReturnTypeAnnotation(
-      DexEncodedAnnotation annotation, DexItemFactory factory) {
-    return isCovariantReturnTypeAnnotation(annotation.type, factory);
-  }
-
-  @SuppressWarnings("ReferenceEquality")
-  public static boolean isCovariantReturnTypeAnnotation(DexType type, DexItemFactory factory) {
-    return type == factory.annotationCovariantReturnType
-        || type == factory.annotationCovariantReturnTypes;
-  }
-
-  private static boolean hasVirtualMethodWithSignature(DexClass clazz, DexEncodedMethod method) {
-    for (DexEncodedMethod existingMethod : clazz.virtualMethods()) {
-      if (existingMethod.getReference().equals(method.getReference())) {
-        return true;
-      }
-    }
-    return false;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeReferences.java b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeReferences.java
new file mode 100644
index 0000000..fa26148
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/desugar/covariantreturntype/CovariantReturnTypeReferences.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2024, 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.desugar.covariantreturntype;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+
+public class CovariantReturnTypeReferences {
+
+  static String COVARIANT_RETURN_TYPE_DESCRIPTOR =
+      "Ldalvik/annotation/codegen/CovariantReturnType;";
+
+  final DexType annotationCovariantReturnType;
+  final DexType annotationCovariantReturnTypes;
+
+  final DexString presentAfterName;
+  final DexString returnTypeName;
+  final DexString valueName;
+
+  CovariantReturnTypeReferences(DexItemFactory factory) {
+    this.annotationCovariantReturnType = factory.createType(COVARIANT_RETURN_TYPE_DESCRIPTOR);
+    this.annotationCovariantReturnTypes =
+        factory.createType("Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;");
+    this.presentAfterName = factory.createString("presentAfter");
+    this.returnTypeName = factory.createString("returnType");
+    this.valueName = factory.createString("value");
+  }
+
+  boolean isCovariantReturnTypeAnnotation(DexType type) {
+    return type.isIdenticalTo(annotationCovariantReturnType);
+  }
+
+  boolean isCovariantReturnTypesAnnotation(DexType type) {
+    return type.isIdenticalTo(annotationCovariantReturnTypes);
+  }
+
+  boolean isOneOfCovariantReturnTypeAnnotations(DexType type) {
+    return isCovariantReturnTypeAnnotation(type) || isCovariantReturnTypesAnnotation(type);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index 4151107..58011d6 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -226,8 +226,9 @@
     return isSet(Constants.ACC_SYNTHETIC);
   }
 
-  public void setSynthetic() {
+  public T setSynthetic() {
     set(Constants.ACC_SYNTHETIC);
+    return self();
   }
 
   public T unsetSynthetic() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index be7b2b4..cee4f28 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.androidapi.ComputedApiLevel;
-import com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
@@ -79,6 +78,10 @@
     this.annotation = annotation;
   }
 
+  public DexEncodedAnnotation getAnnotation() {
+    return annotation;
+  }
+
   public boolean isTypeAnnotation() {
     return false;
   }
@@ -136,22 +139,21 @@
     mixedItems.add(this);
   }
 
-  @SuppressWarnings("ReferenceEquality")
-  public static boolean retainCompileTimeAnnotation(DexType annotation, InternalOptions options) {
+  public static boolean retainCompileTimeAnnotation(
+      DexType annotationType, InternalOptions options) {
     if (options.retainCompileTimeAnnotations) {
       return true;
     }
-    if (annotation == options.itemFactory.annotationSynthesizedClass
-        || annotation
-            .getDescriptor()
-            .startsWith(options.itemFactory.dalvikAnnotationOptimizationPrefix)) {
+    DexItemFactory factory = options.itemFactory;
+    if (annotationType.isIdenticalTo(factory.annotationSynthesizedClass)) {
       return true;
     }
-    if (options.processCovariantReturnTypeAnnotations) {
-      // @CovariantReturnType annotations are processed by CovariantReturnTypeAnnotationTransformer,
-      // they thus need to be read here and will then be removed as part of the processing.
-      return CovariantReturnTypeAnnotationTransformer.isCovariantReturnTypeAnnotation(
-          annotation, options.itemFactory);
+    DexString descriptor = annotationType.getDescriptor();
+    if (descriptor.startsWith(factory.dalvikAnnotationPrefix)) {
+      if (descriptor.startsWith(factory.dalvikAnnotationCodegenCovariantReturnTypePrefix)) {
+        return options.processCovariantReturnTypeAnnotations;
+      }
+      return descriptor.startsWith(factory.dalvikAnnotationOptimizationPrefix);
     }
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index 6dab6e8..c76fb95 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -156,9 +156,17 @@
     return getFirstMatching(type) != null;
   }
 
+  public boolean hasAnnotation(Predicate<DexAnnotation> predicate) {
+    return getFirstMatching(predicate) != null;
+  }
+
   public DexAnnotation getFirstMatching(DexType type) {
+    return getFirstMatching(annotation -> annotation.getAnnotationType().isIdenticalTo(type));
+  }
+
+  public DexAnnotation getFirstMatching(Predicate<DexAnnotation> predicate) {
     for (DexAnnotation annotation : annotations) {
-      if (annotation.getAnnotationType().isIdenticalTo(type)) {
+      if (predicate.test(annotation)) {
         return annotation;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index 143dbe4..884b892 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -41,6 +41,10 @@
     return DexEncodedAnnotation::specify;
   }
 
+  public DexType getType() {
+    return type;
+  }
+
   public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
     type.collectIndexedItems(appView, indexedItems);
     for (DexAnnotationElement element : elements) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 3c056f8..8f6be1b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -81,8 +81,6 @@
       "Lcom/android/tools/r8/DesugarMethodHandlesLookup;";
   public static final String methodHandlesLookupDescriptorString =
       "Ljava/lang/invoke/MethodHandles$Lookup;";
-  public static final String dalvikAnnotationOptimizationPrefixString =
-      "Ldalvik/annotation/optimization/";
   public static final String androidUtilSparseArrayDescriptorString = "Landroid/util/SparseArray;";
   public static final String androidContentResTypedArrayDescriptorString =
       "Landroid/content/res/TypedArray;";
@@ -380,8 +378,11 @@
   public final DexString apiLevelString = createString("apiLevel");
 
   // Prefix for runtime affecting yet potential class-retained annotations.
+  public final DexString dalvikAnnotationPrefix = createString("Ldalvik/annotation/");
+  public final DexString dalvikAnnotationCodegenCovariantReturnTypePrefix =
+      createString("Ldalvik/annotation/codegen/CovariantReturnType");
   public final DexString dalvikAnnotationOptimizationPrefix =
-      createString(dalvikAnnotationOptimizationPrefixString);
+      createString("Ldalvik/annotation/optimization/");
 
   // Method names used on VarHandle.
   public final DexString getString = createString("get");
@@ -811,11 +812,6 @@
   public final DexType annotationThrows = createStaticallyKnownType("Ldalvik/annotation/Throws;");
   public final DexType annotationSynthesizedClass =
       createStaticallyKnownType("Lcom/android/tools/r8/annotations/SynthesizedClassV2;");
-  public final DexType annotationCovariantReturnType =
-      createStaticallyKnownType("Ldalvik/annotation/codegen/CovariantReturnType;");
-  public final DexType annotationCovariantReturnTypes =
-      createStaticallyKnownType(
-          "Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;");
 
   public final String annotationReachabilitySensitiveDesc =
       "Ldalvik/annotation/optimization/ReachabilitySensitive;";
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index ea4be31..4abdb68 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -360,4 +360,8 @@
   public DexMethod withProto(DexProto proto, DexItemFactory dexItemFactory) {
     return dexItemFactory.createMethod(holder, proto, name);
   }
+
+  public DexMethod withReturnType(DexType returnType, DexItemFactory dexItemFactory) {
+    return withProto(dexItemFactory.createProto(returnType, getParameters()), dexItemFactory);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 5b0aec4..e890a6a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -755,11 +755,6 @@
     methodCollection.addMethod(method);
   }
 
-  public void replaceVirtualMethod(
-      DexMethod virtualMethod, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
-    methodCollection.replaceVirtualMethod(virtualMethod, replacement);
-  }
-
   public void addExtraInterfaces(List<ClassTypeSignature> extraInterfaces, DexItemFactory factory) {
     if (extraInterfaces.isEmpty()) {
       return;
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
index 8ede6f7..742b628 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
@@ -152,8 +152,9 @@
     return isSet(Constants.ACC_BRIDGE);
   }
 
-  public void setBridge() {
+  public MethodAccessFlags setBridge() {
     set(Constants.ACC_BRIDGE);
+    return this;
   }
 
   public void unsetBridge() {
@@ -204,8 +205,9 @@
     promote(Constants.ACC_ABSTRACT);
   }
 
-  public void unsetAbstract() {
+  public MethodAccessFlags unsetAbstract() {
     unset(Constants.ACC_ABSTRACT);
+    return this;
   }
 
   public boolean isStrict() {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index ab17919..7daef60 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -184,12 +184,12 @@
   }
 
   @Override
-  void addVirtualMethods(Collection<DexEncodedMethod> methods) {
+  <T> void addVirtualMethods(Collection<T> methods, Function<? super T, DexEncodedMethod> fn) {
     DexEncodedMethod[] newMethods = new DexEncodedMethod[virtualMethods.length + methods.size()];
     System.arraycopy(virtualMethods, 0, newMethods, 0, virtualMethods.length);
     int i = virtualMethods.length;
-    for (DexEncodedMethod method : methods) {
-      newMethods[i] = method;
+    for (T method : methods) {
+      newMethods[i] = fn.apply(method);
       i++;
     }
     virtualMethods = newMethods;
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index 0f10f5a..17b7e8b 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -5,6 +5,9 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -12,7 +15,6 @@
 import java.util.List;
 import java.util.Set;
 import java.util.function.Consumer;
-import java.util.function.Function;
 import java.util.function.Predicate;
 
 public class MethodCollection {
@@ -354,9 +356,21 @@
   }
 
   public void addVirtualMethods(Collection<DexEncodedMethod> methods) {
-    assert verifyCorrectnessOfMethodHolders(methods);
+    internalAddVirtualMethods(methods, Functions.identity());
+  }
+
+  public void addVirtualClassMethods(Collection<? extends DexClassAndMethod> methods) {
+    internalAddVirtualMethods(methods, DexClassAndMethod::getDefinition);
+  }
+
+  private <T> void internalAddVirtualMethods(
+      Collection<T> methods, Function<? super T, DexEncodedMethod> fn) {
+    if (methods.isEmpty()) {
+      return;
+    }
+    assert verifyCorrectnessOfMethodHolders(Iterables.transform(methods, fn));
     resetVirtualMethodCaches();
-    backing.addVirtualMethods(methods);
+    backing.addVirtualMethods(methods, fn);
   }
 
   public void clearVirtualMethods() {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
index 18a72a3..9de91a2 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
@@ -6,6 +6,7 @@
 import static com.google.common.base.Predicates.alwaysTrue;
 
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.google.common.base.Functions;
 import java.util.Collection;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -99,7 +100,12 @@
 
   abstract void addDirectMethods(Collection<DexEncodedMethod> methods);
 
-  abstract void addVirtualMethods(Collection<DexEncodedMethod> methods);
+  final void addVirtualMethods(Collection<DexEncodedMethod> methods) {
+    addVirtualMethods(methods, Functions.identity());
+  }
+
+  abstract <T> void addVirtualMethods(
+      Collection<T> methods, Function<? super T, DexEncodedMethod> fn);
 
   // Removal methods.
 
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionConcurrencyChecked.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionConcurrencyChecked.java
index 78cfebe8..fa3a0a9 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollectionConcurrencyChecked.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionConcurrencyChecked.java
@@ -4,11 +4,11 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.utils.TraversalContinuation;
+import com.google.common.base.Function;
 import java.util.Collection;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
-import java.util.function.Function;
 import java.util.function.Predicate;
 
 public class MethodCollectionConcurrencyChecked extends MethodCollection {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
index fa553d9..f878e46 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -198,9 +198,9 @@
   }
 
   @Override
-  void addVirtualMethods(Collection<DexEncodedMethod> methods) {
-    for (DexEncodedMethod method : methods) {
-      addVirtualMethod(method);
+  <T> void addVirtualMethods(Collection<T> methods, Function<? super T, DexEncodedMethod> fn) {
+    for (T method : methods) {
+      addVirtualMethod(fn.apply(method));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index acf747a..f5c3538 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.ir.conversion;
 
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
-import com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
@@ -120,7 +119,6 @@
   protected final Inliner inliner;
   protected final IdentifierNameStringMarker identifierNameStringMarker;
   private final Devirtualizer devirtualizer;
-  protected final CovariantReturnTypeAnnotationTransformer covariantReturnTypeAnnotationTransformer;
   private final TypeChecker typeChecker;
   protected EnumUnboxer enumUnboxer;
   protected final NumberUnboxer numberUnboxer;
@@ -190,7 +188,6 @@
       assert options.desugarState.isOn();
       this.instructionDesugaring =
           CfInstructionDesugaringCollection.create(appView, appView.apiLevelCompute());
-      this.covariantReturnTypeAnnotationTransformer = null;
       this.dynamicTypeOptimization = null;
       this.classInliner = null;
       this.fieldAccessAnalysis = null;
@@ -213,10 +210,6 @@
         appView.enableWholeProgramOptimizations()
             ? CfInstructionDesugaringCollection.empty()
             : CfInstructionDesugaringCollection.create(appView, appView.apiLevelCompute());
-    this.covariantReturnTypeAnnotationTransformer =
-        options.processCovariantReturnTypeAnnotations
-            ? new CovariantReturnTypeAnnotationTransformer(appView, this)
-            : null;
     removeVerificationErrorForUnknownReturnedValues =
         (appView.options().apiModelingOptions().enableLibraryApiModeling
                 && appView.options().canHaveVerifyErrorForUnknownUnusedReturnValue())
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
index 9ad2b27..93b681a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryD8L8IRConverter.java
@@ -8,6 +8,7 @@
 import static com.android.tools.r8.ir.desugar.lambda.D8LambdaDesugaring.rewriteEnclosingLambdaMethodAttributes;
 
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeAnnotationTransformerEventConsumer;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfo;
@@ -77,6 +78,8 @@
 
     application = commitPendingSyntheticItems(appView, application);
 
+    processCovariantReturnTypeAnnotations(profileCollectionAdditions, executorService);
+
     // Build a new application with jumbo string info,
     Builder<?> builder = application.builder();
 
@@ -85,8 +88,6 @@
       new L8InnerOuterAttributeEraser(appView).run();
     }
 
-    processCovariantReturnTypeAnnotations(builder, profileCollectionAdditions);
-
     timing.end();
 
     application = builder.build();
@@ -272,6 +273,7 @@
               appView.appInfo().getMainDexInfo()));
       application = appView.appInfo().app();
     }
+    assert application == appView.appInfo().app();
     return application;
   }
 
@@ -338,14 +340,13 @@
     programAdditions.apply(threadingModule, executorService);
   }
 
-  @SuppressWarnings("BadImport")
   private void processCovariantReturnTypeAnnotations(
-      Builder<?> builder, ProfileCollectionAdditions profileCollectionAdditions) {
-    if (covariantReturnTypeAnnotationTransformer != null) {
-      covariantReturnTypeAnnotationTransformer.process(
-          builder,
-          CovariantReturnTypeAnnotationTransformerEventConsumer.create(profileCollectionAdditions));
-    }
+      ProfileCollectionAdditions profileCollectionAdditions, ExecutorService executorService)
+      throws ExecutionException {
+    CovariantReturnTypeAnnotationTransformerEventConsumer eventConsumer =
+        CovariantReturnTypeAnnotationTransformerEventConsumer.create(profileCollectionAdditions);
+    CovariantReturnTypeAnnotationTransformer.runIfNecessary(
+        appView, this, eventConsumer, executorService);
   }
 
   Timing rewriteNonDesugaredCode(
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index dac665d..8abdba1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -372,7 +372,8 @@
     if (isAndroidPlatformBuild) {
       apiModelingOptions().disableApiModeling();
       disableBackportsAndReportIfTriggered = true;
-      addAndroidPlatformBuildToMarker = isAndroidPlatformBuild;
+      addAndroidPlatformBuildToMarker = true;
+      processCovariantReturnTypeAnnotations = true;
     }
   }
 
@@ -778,7 +779,7 @@
   public OffOrAuto tryWithResourcesDesugaring = OffOrAuto.Auto;
   // Flag to turn on/off processing of @dalvik.annotation.codegen.CovariantReturnType and
   // @dalvik.annotation.codegen.CovariantReturnType$CovariantReturnTypes.
-  public boolean processCovariantReturnTypeAnnotations = true;
+  public boolean processCovariantReturnTypeAnnotations = false;
 
   public boolean loadAllClassDefinitions = false;
 
diff --git a/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java b/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java
index 3bcbd20..76c0cde 100644
--- a/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.androidapi;
 
 import static com.android.tools.r8.apimodel.JavaSourceCodePrinter.Type.fromType;
-import static com.android.tools.r8.desugar.covariantreturntype.CovariantReturnTypeAnnotationTransformer.isCovariantReturnTypeAnnotation;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -23,7 +22,6 @@
 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.DexItemFactory;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
 import com.android.tools.r8.graph.DexValue.DexValueArray;
@@ -63,6 +61,11 @@
 @RunWith(Parameterized.class)
 public class GenerateCovariantReturnTypeMethodsTest extends TestBase {
 
+  private static final String COVARIANT_RETURN_TYPE_ANNOTATION_NAME =
+      "dalvik.annotation.codegen.CovariantReturnType";
+  private static final String COVARIANT_RETURN_TYPES_ANNOTATION_NAME =
+      "dalvik.annotation.codegen.CovariantReturnType$CovariantReturnTypes";
+
   private static final String CLASS_NAME = "CovariantReturnTypeMethods";
   private static final String PACKAGE_NAME = "com.android.tools.r8.androidapi";
   // When updating to support a new api level build libcore in aosp and update the cloud dependency.
@@ -200,20 +203,22 @@
     public static CovariantMethodsInJarResult create() throws Exception {
       Map<ClassReference, List<MethodReferenceWithApiLevel>> methodReferenceMap = new HashMap<>();
       CodeInspector inspector = new CodeInspector(PATH_TO_CORE_JAR);
-      DexItemFactory factory = inspector.getFactory();
       for (FoundClassSubject clazz : inspector.allClasses()) {
         clazz.forAllMethods(
             method -> {
               List<DexAnnotation> covariantAnnotations =
                   inspector.findAnnotations(
                       method.getMethod().annotations(),
-                      annotation ->
-                          isCovariantReturnTypeAnnotation(annotation.annotation, factory));
+                      annotation -> {
+                        String typeName = annotation.getAnnotationType().getTypeName();
+                        return typeName.equals(COVARIANT_RETURN_TYPE_ANNOTATION_NAME)
+                            || typeName.equals(COVARIANT_RETURN_TYPES_ANNOTATION_NAME);
+                      });
               if (!covariantAnnotations.isEmpty()) {
                 MethodReference methodReference = method.asMethodReference();
                 for (DexAnnotation covariantAnnotation : covariantAnnotations) {
                   createCovariantMethodReference(
-                      factory, methodReference, covariantAnnotation.annotation, methodReferenceMap);
+                      methodReference, covariantAnnotation.annotation, methodReferenceMap);
                 }
               }
             });
@@ -222,19 +227,21 @@
     }
 
     private static void createCovariantMethodReference(
-        DexItemFactory factory,
         MethodReference methodReference,
         DexEncodedAnnotation covariantAnnotation,
         Map<ClassReference, List<MethodReferenceWithApiLevel>> methodReferenceMap) {
-      if (covariantAnnotation.type == factory.annotationCovariantReturnType) {
+      if (covariantAnnotation
+          .getType()
+          .getTypeName()
+          .equals(COVARIANT_RETURN_TYPE_ANNOTATION_NAME)) {
         DexAnnotationElement returnTypeElement = covariantAnnotation.getElement(0);
-        assert returnTypeElement.name.toString().equals("returnType");
+        assert returnTypeElement.getName().toString().equals("returnType");
         DexValueType newReturnType = returnTypeElement.getValue().asDexValueType();
         DexAnnotationElement presentAfterElement = covariantAnnotation.getElement(1);
-        assert presentAfterElement.name.toString().equals("presentAfter");
+        assert presentAfterElement.getName().toString().equals("presentAfter");
         AndroidApiLevel apiLevel =
             AndroidApiLevel.getAndroidApiLevel(
-                presentAfterElement.getValue().asDexValueInt().value);
+                presentAfterElement.getValue().asDexValueInt().getValue());
         methodReferenceMap
             .computeIfAbsent(methodReference.getHolderClass(), ignoreKey(ArrayList::new))
             .add(
@@ -243,20 +250,23 @@
                         methodReference.getHolderClass(),
                         methodReference.getMethodName(),
                         methodReference.getFormalTypes(),
-                        newReturnType.value.asClassReference()),
+                        newReturnType.getValue().asClassReference()),
                     apiLevel));
       } else {
-        assert covariantAnnotation.type == factory.annotationCovariantReturnTypes;
+        assert covariantAnnotation
+            .getType()
+            .getTypeName()
+            .equals(COVARIANT_RETURN_TYPES_ANNOTATION_NAME);
         DexAnnotationElement valuesElement = covariantAnnotation.getElement(0);
-        assert valuesElement.name.toString().equals("value");
-        DexValueArray array = valuesElement.value.asDexValueArray();
+        assertEquals("value", valuesElement.getName().toString());
+        DexValueArray array = valuesElement.getValue().asDexValueArray();
         if (array == null) {
           fail(
               String.format(
                   "Expected element \"value\" of CovariantReturnTypes annotation to "
                       + "be an array (method: \"%s\", was: %s)",
                   methodReference.toSourceString(),
-                  valuesElement.value.getClass().getCanonicalName()));
+                  valuesElement.getValue().getClass().getCanonicalName()));
         }
 
         // Handle the inner dalvik.annotation.codegen.CovariantReturnType annotations recursively.
@@ -264,7 +274,7 @@
           assert value.isDexValueAnnotation();
           DexValueAnnotation innerAnnotation = value.asDexValueAnnotation();
           createCovariantMethodReference(
-              factory, methodReference, innerAnnotation.value, methodReferenceMap);
+              methodReference, innerAnnotation.value, methodReferenceMap);
         }
       }
     }
diff --git a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
index f14c979..c6c128f 100644
--- a/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/annotations/DalvikAnnotationOptimizationTest.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.transformers.MethodTransformer;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -56,8 +55,7 @@
         BooleanUtils.values());
   }
 
-  private static final String dalvikOptimizationPrefix =
-      DexItemFactory.dalvikAnnotationOptimizationPrefixString;
+  private static final String dalvikOptimizationPrefix = "Ldalvik/annotation/optimization/";
   private static final String dalvikCodegenPrefix = "Ldalvik/annotation/codegen/";
   private static final String ourClassName =
       DescriptorUtils.javaTypeToDescriptor(DalvikAnnotationOptimizationTest.class.getTypeName());