Reapply "Refactor AnnotationRemover to always use the same filtering"

This reverts commit 9a3c378cb7e50fde819232ec04b624dc82f31ce0.

Change-Id: I9fffcfea13507d0386e38383cfd8e446d9c79c9d
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index bf7c4f8..1cfa7f2 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -59,10 +59,13 @@
 
   /** Used to filter annotations on classes, methods and fields. */
   private boolean filterAnnotations(
-      ProgramDefinition holder, DexAnnotation annotation, AnnotatedKind kind) {
+      ProgramDefinition holder,
+      DexAnnotation annotation,
+      AnnotatedKind kind,
+      KeepInfo<?, ?> keepInfo) {
     return annotationsToRetain.contains(annotation)
         || shouldKeepAnnotation(
-            appView, holder, annotation, isAnnotationTypeLive(annotation), kind, mode);
+            appView, holder, annotation, isAnnotationTypeLive(annotation), kind, mode, keepInfo);
   }
 
   public static boolean shouldKeepAnnotation(
@@ -71,13 +74,17 @@
       DexAnnotation annotation,
       boolean isAnnotationTypeLive,
       AnnotatedKind kind,
-      Mode mode) {
+      Mode mode,
+      KeepInfo<?, ?> keepInfo) {
     // If we cannot run the AnnotationRemover we are keeping the annotation.
     InternalOptions options = appView.options();
     if (!options.isShrinking()) {
       return true;
     }
 
+    boolean isAnnotationOnAnnotationClass =
+        holder.isProgramClass() && holder.asProgramClass().isAnnotation();
+
     ProguardKeepAttributes config =
         options.getProguardConfiguration() != null
             ? options.getProguardConfiguration().getKeepAttributes()
@@ -109,20 +116,17 @@
             && DexAnnotation.isParameterNameAnnotation(annotation, dexItemFactory)) {
           return true;
         }
-        if (DexAnnotation.isAnnotationDefaultAnnotation(annotation, dexItemFactory)) {
-          // These have to be kept if the corresponding annotation class is kept to retain default
-          // values.
+        if (isAnnotationOnAnnotationClass
+            && DexAnnotation.isAnnotationDefaultAnnotation(annotation, dexItemFactory)
+            && shouldRetainAnnotationDefaultAnnotationOnAnnotationClass(annotation)) {
           return true;
         }
         return false;
 
       case DexAnnotation.VISIBILITY_RUNTIME:
-        // We always keep the @java.lang.Retention annotation on annotation classes, since the
-        // removal of this annotation may change the annotation from being runtime visible to
-        // runtime invisible.
-        if (holder.isProgramClass()
-            && holder.asProgramClass().isAnnotation()
-            && DexAnnotation.isJavaLangRetentionAnnotation(annotation, dexItemFactory)) {
+        if (isAnnotationOnAnnotationClass
+            && DexAnnotation.isJavaLangRetentionAnnotation(annotation, dexItemFactory)
+            && shouldRetainRetentionAnnotationOnAnnotationClass(annotation, dexItemFactory)) {
           return true;
         }
 
@@ -137,7 +141,7 @@
             && !options.isKeepRuntimeVisibleTypeAnnotationsEnabled()) {
           return false;
         }
-        return isAnnotationTypeLive;
+        return !keepInfo.isAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
 
       case DexAnnotation.VISIBILITY_BUILD:
         if (annotation
@@ -160,7 +164,7 @@
             && !options.isKeepRuntimeInvisibleTypeAnnotationsEnabled()) {
           return false;
         }
-        return isAnnotationTypeLive;
+        return !keepInfo.isAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
       default:
         throw new Unreachable("Unexpected annotation visibility.");
     }
@@ -243,9 +247,12 @@
   }
 
   private DexAnnotation rewriteAnnotation(
-      ProgramDefinition holder, DexAnnotation original, AnnotatedKind kind) {
+      ProgramDefinition holder,
+      DexAnnotation original,
+      AnnotatedKind kind,
+      KeepInfo<?, ?> keepInfo) {
     // Check if we should keep this annotation first.
-    if (filterAnnotations(holder, original, kind)) {
+    if (filterAnnotations(holder, original, kind, keepInfo)) {
       // Then, filter out values that refer to dead definitions.
       return original.rewrite(this::rewriteEncodedAnnotation);
     }
@@ -296,36 +303,8 @@
 
   private void removeAnnotations(ProgramDefinition definition, KeepInfo<?, ?> keepInfo) {
     assert mode.isInitialTreeShaking() || annotationsToRetain.isEmpty();
-    boolean isAnnotation =
-        definition.isProgramClass() && definition.asProgramClass().isAnnotation();
-    if (keepInfo.isAnnotationRemovalAllowed(options)) {
-      if (isAnnotation || mode.isInitialTreeShaking()) {
-        definition.rewriteAllAnnotations(
-            (annotation, kind) ->
-                shouldRetainAnnotation(definition, annotation, kind) ? annotation : null);
-      } else {
-        definition.clearAllAnnotations();
-      }
-    } else {
-      definition.rewriteAllAnnotations(
-          (annotation, kind) -> rewriteAnnotation(definition, annotation, kind));
-    }
-  }
-
-  private boolean shouldRetainAnnotation(
-      ProgramDefinition definition, DexAnnotation annotation, AnnotatedKind kind) {
-    boolean isAnnotationOnAnnotationClass =
-        definition.isProgramClass() && definition.asProgramClass().isAnnotation();
-    if (isAnnotationOnAnnotationClass) {
-      if (DexAnnotation.isAnnotationDefaultAnnotation(annotation, appView.dexItemFactory())) {
-        return shouldRetainAnnotationDefaultAnnotationOnAnnotationClass(annotation);
-      }
-      if (DexAnnotation.isJavaLangRetentionAnnotation(annotation, appView.dexItemFactory())) {
-        return shouldRetainRetentionAnnotationOnAnnotationClass(annotation);
-      }
-    }
-    return annotationsToRetain.contains(annotation)
-        || isComposableAnnotationToRetain(appView, annotation, kind, mode, options);
+    definition.rewriteAllAnnotations(
+        (annotation, kind) -> rewriteAnnotation(definition, annotation, kind, keepInfo));
   }
 
   private static boolean isComposableAnnotationToRetain(
@@ -342,29 +321,30 @@
             .isIdenticalTo(appView.getComposeReferences().composableType);
   }
 
-  @SuppressWarnings("UnusedVariable")
-  private boolean shouldRetainAnnotationDefaultAnnotationOnAnnotationClass(
-      DexAnnotation annotation) {
+  private static boolean shouldRetainAnnotationDefaultAnnotationOnAnnotationClass(
+      DexAnnotation unusedAnnotation) {
     // We currently always retain the @AnnotationDefault annotations for annotation classes. In full
     // mode we could consider only retaining @AnnotationDefault annotations for pinned annotations,
     // as this is consistent with removing all annotations for non-kept items.
     return true;
   }
 
-  @SuppressWarnings("ReferenceEquality")
-  private boolean shouldRetainRetentionAnnotationOnAnnotationClass(DexAnnotation annotation) {
+  private static boolean shouldRetainRetentionAnnotationOnAnnotationClass(
+      DexAnnotation annotation, DexItemFactory dexItemFactory) {
     // Retain @Retention annotations that are different from @Retention(RetentionPolicy.CLASS).
     if (annotation.annotation.getNumberOfElements() != 1) {
       return true;
     }
     DexAnnotationElement element = annotation.annotation.getElement(0);
-    if (element.name != appView.dexItemFactory().valueString) {
+    if (element.name.isNotIdenticalTo(dexItemFactory.valueString)) {
       return true;
     }
     DexValue value = element.getValue();
     if (!value.isDexValueEnum()
-        || value.asDexValueEnum().getValue()
-            != appView.dexItemFactory().javaLangAnnotationRetentionPolicyMembers.CLASS) {
+        || value
+            .asDexValueEnum()
+            .getValue()
+            .isNotIdenticalTo(dexItemFactory.javaLangAnnotationRetentionPolicyMembers.CLASS)) {
       return true;
     }
     return false;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 6041570..c1978ca 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2473,18 +2473,20 @@
       ProgramDefinition annotatedItem, DexAnnotation annotation, AnnotatedKind kind) {
     DexType type = annotation.getAnnotationType();
     DexClass clazz = definitionFor(type, annotatedItem);
-    boolean annotationTypeIsLibraryClass = clazz == null || clazz.isNotProgramClass();
-    boolean isLive = annotationTypeIsLibraryClass || liveTypes.contains(clazz.asProgramClass());
+    boolean annotationTypeIsNotProgramClass = clazz == null || clazz.isNotProgramClass();
+    boolean isLive = annotationTypeIsNotProgramClass || liveTypes.contains(clazz.asProgramClass());
     if (!shouldKeepAnnotation(annotatedItem, annotation, kind, isLive)) {
       // Remember this annotation for later.
-      if (!annotationTypeIsLibraryClass) {
-        Map<DexType, Map<DexAnnotation, List<ProgramDefinition>>> deferredAnnotations =
-            kind.isParameter() ? deferredParameterAnnotations : this.deferredAnnotations;
-        Map<DexAnnotation, List<ProgramDefinition>> deferredAnnotationsForAnnotationType =
-            deferredAnnotations.computeIfAbsent(type, ignore -> new IdentityHashMap<>());
-        deferredAnnotationsForAnnotationType
-            .computeIfAbsent(annotation, ignore -> new ArrayList<>())
-            .add(annotatedItem);
+      Map<DexType, Map<DexAnnotation, List<ProgramDefinition>>> deferredAnnotations =
+          kind.isParameter() ? deferredParameterAnnotations : this.deferredAnnotations;
+      Map<DexAnnotation, List<ProgramDefinition>> deferredAnnotationsForAnnotationType =
+          deferredAnnotations.computeIfAbsent(type, ignore -> new IdentityHashMap<>());
+      deferredAnnotationsForAnnotationType
+          .computeIfAbsent(annotation, ignore -> new ArrayList<>())
+          .add(annotatedItem);
+      // Also, non-program annotations should be considered live w.r.t the deferred processing.
+      if (annotationTypeIsNotProgramClass) {
+        liveAnnotations.add(type);
       }
       return;
     }
@@ -2510,7 +2512,13 @@
       return true;
     }
     return AnnotationRemover.shouldKeepAnnotation(
-        appView, annotatedItem, annotation, isLive, annotatedKind, mode);
+        appView,
+        annotatedItem,
+        annotation,
+        isLive,
+        annotatedKind,
+        mode,
+        keepInfo.getInfo(annotatedItem));
   }
 
   private DexClass resolveBaseType(DexType type, ProgramDefinition context) {
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index d13b3d0..5055090 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.PermittedSubclassAttribute;
+import com.android.tools.r8.graph.ProgramMember;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.graph.RecordComponentInfo;
@@ -112,12 +113,17 @@
     InternalOptions options = appView.options();
     List<DexProgramClass> newClasses = new ArrayList<>();
     for (DexProgramClass clazz : classes) {
+      boolean isLiveClass = appInfo.isLiveProgramClass(clazz);
       if (options.configurationDebugging) {
         newClasses.add(clazz);
         pruneMembersAndAttributes(clazz);
+        if (!isLiveClass) {
+          clazz.clearAllAnnotations();
+          clazz.forEachProgramMember(ProgramMember::clearAllAnnotations);
+        }
         continue;
       }
-      if (appInfo.isLiveProgramClass(clazz)) {
+      if (isLiveClass) {
         newClasses.add(clazz);
         if (!appInfo.getObjectAllocationInfoCollection().isInstantiatedDirectly(clazz)
             && !options.forceProguardCompatibility) {