Split annotation keep info in parameters, types and normal annotations

Change-Id: Id43f028fca0afbaa081d9549b020a6d18e83d1aa
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 1cfa7f2..75397e5 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -131,14 +131,21 @@
         }
 
         if (kind.isParameter()) {
-          if (!options.isKeepRuntimeVisibleParameterAnnotationsEnabled()) {
+          KeepMethodInfo methodInfo = keepInfo.asMethodInfo();
+          if (methodInfo == null || !options.isKeepRuntimeVisibleParameterAnnotationsEnabled()) {
             return false;
           }
-        } else if (!annotation.isTypeAnnotation()
-            && !options.isKeepRuntimeVisibleAnnotationsEnabled()) {
-          return false;
-        } else if (annotation.isTypeAnnotation()
-            && !options.isKeepRuntimeVisibleTypeAnnotationsEnabled()) {
+          return !methodInfo.isParameterAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
+        }
+
+        if (annotation.isTypeAnnotation()) {
+          if (!options.isKeepRuntimeVisibleTypeAnnotationsEnabled()) {
+            return false;
+          }
+          return !keepInfo.isTypeAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
+        }
+
+        if (!options.isKeepRuntimeVisibleAnnotationsEnabled()) {
           return false;
         }
         return !keepInfo.isAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
@@ -154,17 +161,25 @@
           return true;
         }
         if (kind.isParameter()) {
-          if (!options.isKeepRuntimeInvisibleParameterAnnotationsEnabled()) {
+          KeepMethodInfo methodInfo = keepInfo.asMethodInfo();
+          if (methodInfo == null || !options.isKeepRuntimeInvisibleParameterAnnotationsEnabled()) {
             return false;
           }
-        } else if (!annotation.isTypeAnnotation()
-            && !options.isKeepRuntimeInvisibleAnnotationsEnabled()) {
-          return false;
-        } else if (annotation.isTypeAnnotation()
-            && !options.isKeepRuntimeInvisibleTypeAnnotationsEnabled()) {
+          return !methodInfo.isParameterAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
+        }
+
+        if (annotation.isTypeAnnotation()) {
+          if (!options.isKeepRuntimeInvisibleTypeAnnotationsEnabled()) {
+            return false;
+          }
+          return !keepInfo.isTypeAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
+        }
+
+        if (!options.isKeepRuntimeInvisibleAnnotationsEnabled()) {
           return false;
         }
         return !keepInfo.isAnnotationRemovalAllowed(options) && isAnnotationTypeLive;
+
       default:
         throw new Unreachable("Unexpected annotation visibility.");
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
index d2e5f1f..1424a52 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -25,6 +25,7 @@
   private final boolean allowSignatureRemoval;
   private final boolean checkDiscarded;
   private final KeepAnnotationCollectionInfo annotationsInfo;
+  private final KeepAnnotationCollectionInfo typeAnnotationsInfo;
 
   private KeepInfo(
       boolean allowAccessModification,
@@ -34,7 +35,8 @@
       boolean allowShrinking,
       boolean allowSignatureRemoval,
       boolean checkDiscarded,
-      KeepAnnotationCollectionInfo annotationsInfo) {
+      KeepAnnotationCollectionInfo annotationsInfo,
+      KeepAnnotationCollectionInfo typeAnnotationsInfo) {
     this.allowAccessModification = allowAccessModification;
     this.allowAccessModificationForTesting = allowAccessModificationForTesting;
     this.allowMinification = allowMinification;
@@ -43,6 +45,7 @@
     this.allowSignatureRemoval = allowSignatureRemoval;
     this.checkDiscarded = checkDiscarded;
     this.annotationsInfo = annotationsInfo;
+    this.typeAnnotationsInfo = typeAnnotationsInfo;
   }
 
   KeepInfo(B builder) {
@@ -54,7 +57,8 @@
         builder.isShrinkingAllowed(),
         builder.isSignatureRemovalAllowed(),
         builder.isCheckDiscardedEnabled(),
-        builder.getAnnotationsInfo().build());
+        builder.getAnnotationsInfo().build(),
+        builder.getTypeAnnotationsInfo().build());
   }
 
   public static Joiner<?, ?, ?> newEmptyJoinerFor(DexReference reference) {
@@ -66,6 +70,10 @@
 
   abstract B builder();
 
+  public KeepMethodInfo asMethodInfo() {
+    return null;
+  }
+
   /**
    * True if an item may have all of its annotations removed.
    *
@@ -73,13 +81,23 @@
    * keep all annotation attributes.
    */
   public boolean isAnnotationRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
+    assert internalAnnotationsInfo().isTop() || internalAnnotationsInfo().isBottom();
     return configuration.isAnnotationRemovalEnabled() && internalAnnotationsInfo().isBottom();
   }
 
+  public boolean isTypeAnnotationRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
+    assert internalTypeAnnotationsInfo().isTop() || internalTypeAnnotationsInfo().isBottom();
+    return configuration.isAnnotationRemovalEnabled() && internalTypeAnnotationsInfo().isBottom();
+  }
+
   KeepAnnotationCollectionInfo internalAnnotationsInfo() {
     return annotationsInfo;
   }
 
+  KeepAnnotationCollectionInfo internalTypeAnnotationsInfo() {
+    return typeAnnotationsInfo;
+  }
+
   public boolean isCheckDiscardedEnabled(GlobalKeepInfoConfiguration configuration) {
     return internalIsCheckDiscardedEnabled();
   }
@@ -230,7 +248,8 @@
         && (allowShrinking || !other.internalIsShrinkingAllowed())
         && (allowSignatureRemoval || !other.internalIsSignatureRemovalAllowed())
         && (!checkDiscarded || other.internalIsCheckDiscardedEnabled())
-        && annotationsInfo.isLessThanOrEquals(other.internalAnnotationsInfo());
+        && annotationsInfo.isLessThanOrEquals(other.internalAnnotationsInfo())
+        && typeAnnotationsInfo.isLessThanOrEquals(other.internalTypeAnnotationsInfo());
   }
 
   /** Builder to construct an arbitrary keep info object. */
@@ -255,6 +274,7 @@
     private boolean allowSignatureRemoval;
     private boolean checkDiscarded;
     private KeepAnnotationCollectionInfo.Builder annotationsInfo;
+    private KeepAnnotationCollectionInfo.Builder typeAnnotationsInfo;
 
     Builder() {
       // Default initialized. Use should be followed by makeTop/makeBottom.
@@ -270,12 +290,14 @@
       allowSignatureRemoval = original.internalIsSignatureRemovalAllowed();
       checkDiscarded = original.internalIsCheckDiscardedEnabled();
       annotationsInfo = original.internalAnnotationsInfo().toBuilder();
+      typeAnnotationsInfo = original.internalTypeAnnotationsInfo().toBuilder();
     }
 
     B makeTop() {
       disallowAccessModification();
       disallowAccessModificationForTesting();
       disallowAnnotationRemoval();
+      disallowTypeAnnotationRemoval();
       disallowMinification();
       disallowOptimization();
       disallowShrinking();
@@ -288,6 +310,7 @@
       allowAccessModification();
       allowAccessModificationForTesting();
       allowAnnotationRemoval();
+      allowTypeAnnotationRemoval();
       allowMinification();
       allowOptimization();
       allowShrinking();
@@ -320,7 +343,8 @@
           && isShrinkingAllowed() == other.internalIsShrinkingAllowed()
           && isSignatureRemovalAllowed() == other.internalIsSignatureRemovalAllowed()
           && isCheckDiscardedEnabled() == other.internalIsCheckDiscardedEnabled()
-          && annotationsInfo.isEqualTo(other.internalAnnotationsInfo());
+          && annotationsInfo.isEqualTo(other.internalAnnotationsInfo())
+          && typeAnnotationsInfo.isEqualTo(other.internalTypeAnnotationsInfo());
     }
 
     public boolean isAccessModificationAllowed() {
@@ -446,6 +470,23 @@
       return setAnnotationsInfo(KeepAnnotationCollectionInfo.Builder.makeTop());
     }
 
+    KeepAnnotationCollectionInfo.Builder getTypeAnnotationsInfo() {
+      return typeAnnotationsInfo;
+    }
+
+    private B setTypeAnnotationsInfo(KeepAnnotationCollectionInfo.Builder typeAnnotationsInfo) {
+      this.typeAnnotationsInfo = typeAnnotationsInfo;
+      return self();
+    }
+
+    public B allowTypeAnnotationRemoval() {
+      return setTypeAnnotationsInfo(KeepAnnotationCollectionInfo.Builder.makeBottom());
+    }
+
+    public B disallowTypeAnnotationRemoval() {
+      return setTypeAnnotationsInfo(KeepAnnotationCollectionInfo.Builder.makeTop());
+    }
+
     private B setAllowSignatureRemoval(boolean allowSignatureRemoval) {
       this.allowSignatureRemoval = allowSignatureRemoval;
       return self();
@@ -577,6 +618,11 @@
       return self();
     }
 
+    public J disallowTypeAnnotationRemoval() {
+      builder.disallowTypeAnnotationRemoval();
+      return self();
+    }
+
     public J disallowMinification() {
       builder.disallowMinification();
       return self();
@@ -614,6 +660,7 @@
       applyIf(!otherBuilder.isSignatureRemovalAllowed(), Joiner::disallowSignatureRemoval);
       applyIf(otherBuilder.isCheckDiscardedEnabled(), Joiner::setCheckDiscarded);
       builder.getAnnotationsInfo().join(otherBuilder.getAnnotationsInfo());
+      builder.getTypeAnnotationsInfo().join(otherBuilder.getTypeAnnotationsInfo());
       reasons.addAll(joiner.reasons);
       rules.addAll(joiner.rules);
       return self();
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index 879369c..ad4ea9f 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -39,6 +39,7 @@
   private final boolean allowSingleCallerInlining;
   private final boolean allowUnusedArgumentOptimization;
   private final boolean allowUnusedReturnValueOptimization;
+  private final KeepAnnotationCollectionInfo parameterAnnotationsInfo;
 
   protected KeepMethodInfo(Builder builder) {
     super(builder);
@@ -55,6 +56,7 @@
     this.allowSingleCallerInlining = builder.isSingleCallerInliningAllowed();
     this.allowUnusedArgumentOptimization = builder.isUnusedArgumentOptimizationAllowed();
     this.allowUnusedReturnValueOptimization = builder.isUnusedReturnValueOptimizationAllowed();
+    this.parameterAnnotationsInfo = builder.getParameterAnnotationsInfo().build();
   }
 
   // This builder is not private as there are known instances where it is safe to modify keep info
@@ -64,6 +66,22 @@
     return new Builder(this);
   }
 
+  @Override
+  public KeepMethodInfo asMethodInfo() {
+    return this;
+  }
+
+  public boolean isParameterAnnotationRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
+    assert internalParameterAnnotationsInfo().isTop()
+        || internalParameterAnnotationsInfo().isBottom();
+    return configuration.isAnnotationRemovalEnabled()
+        && internalParameterAnnotationsInfo().isBottom();
+  }
+
+  KeepAnnotationCollectionInfo internalParameterAnnotationsInfo() {
+    return parameterAnnotationsInfo;
+  }
+
   public boolean isArgumentPropagationAllowed(GlobalKeepInfoConfiguration configuration) {
     return isParameterRemovalAllowed(configuration);
   }
@@ -229,6 +247,7 @@
     private boolean allowSingleCallerInlining;
     private boolean allowUnusedArgumentOptimization;
     private boolean allowUnusedReturnValueOptimization;
+    private KeepAnnotationCollectionInfo.Builder parameterAnnotationsInfo;
 
     public Builder() {
       super();
@@ -250,6 +269,7 @@
       allowUnusedArgumentOptimization = original.internalIsUnusedArgumentOptimizationAllowed();
       allowUnusedReturnValueOptimization =
           original.internalIsUnusedReturnValueOptimizationAllowed();
+      parameterAnnotationsInfo = original.internalParameterAnnotationsInfo().toBuilder();
     }
 
     // Class inlining.
@@ -500,6 +520,22 @@
       return setAllowUnusedReturnValueOptimization(false);
     }
 
+    // Parameter annotations
+
+    KeepAnnotationCollectionInfo.Builder getParameterAnnotationsInfo() {
+      return parameterAnnotationsInfo;
+    }
+
+    public Builder allowParameterAnnotationsRemoval() {
+      parameterAnnotationsInfo = KeepAnnotationCollectionInfo.Builder.makeBottom();
+      return self();
+    }
+
+    public Builder disallowParameterAnnotationsRemoval() {
+      parameterAnnotationsInfo = KeepAnnotationCollectionInfo.Builder.makeTop();
+      return self();
+    }
+
     @Override
     public Builder self() {
       return this;
@@ -539,7 +575,8 @@
           && isUnusedArgumentOptimizationAllowed()
               == other.internalIsUnusedArgumentOptimizationAllowed()
           && isUnusedReturnValueOptimizationAllowed()
-              == other.internalIsUnusedReturnValueOptimizationAllowed();
+              == other.internalIsUnusedReturnValueOptimizationAllowed()
+          && parameterAnnotationsInfo.isEqualTo(other.parameterAnnotationsInfo);
     }
 
     @Override
@@ -562,7 +599,8 @@
           .disallowReturnTypeStrengthening()
           .disallowSingleCallerInlining()
           .disallowUnusedArgumentOptimization()
-          .disallowUnusedReturnValueOptimization();
+          .disallowUnusedReturnValueOptimization()
+          .disallowParameterAnnotationsRemoval();
     }
 
     @Override
@@ -580,7 +618,8 @@
           .allowReturnTypeStrengthening()
           .allowSingleCallerInlining()
           .allowUnusedArgumentOptimization()
-          .allowUnusedReturnValueOptimization();
+          .allowUnusedReturnValueOptimization()
+          .allowParameterAnnotationsRemoval();
     }
   }
 
@@ -659,6 +698,11 @@
       return self();
     }
 
+    public Joiner disallowParameterAnnotationsRemoval() {
+      builder.disallowParameterAnnotationsRemoval();
+      return self();
+    }
+
     @Override
     public Joiner asMethodJoiner() {
       return this;
@@ -667,8 +711,9 @@
     @Override
     public Joiner merge(Joiner joiner) {
       // Should be extended to merge the fields of this class in case any are added.
-      return super.merge(joiner)
-          .applyIf(!joiner.builder.isClassInliningAllowed(), Joiner::disallowClassInlining)
+      super.merge(joiner);
+      builder.getParameterAnnotationsInfo().join(joiner.builder.getParameterAnnotationsInfo());
+      return applyIf(!joiner.builder.isClassInliningAllowed(), Joiner::disallowClassInlining)
           .applyIf(
               !joiner.builder.isClosedWorldReasoningAllowed(), Joiner::disallowClosedWorldReasoning)
           .applyIf(
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 17a3591..d9add46 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -1623,9 +1623,15 @@
       }
 
       if (appView.options().isAnnotationRemovalEnabled() && !modifiers.allowsAnnotationRemoval) {
-        dependentMinimumKeepInfo
-            .getOrCreateMinimumKeepInfoFor(preconditionEvent, item.getReference())
-            .disallowAnnotationRemoval();
+        Joiner<?, ?, ?> joiner =
+            dependentMinimumKeepInfo
+                .getOrCreateMinimumKeepInfoFor(preconditionEvent, item.getReference())
+                .disallowAnnotationRemoval()
+                .disallowTypeAnnotationRemoval();
+        KeepMethodInfo.Joiner methodJoiner = joiner.asMethodJoiner();
+        if (methodJoiner != null) {
+          methodJoiner.disallowParameterAnnotationsRemoval();
+        }
         context.markAsUsed();
       }