Version 2.1.38

Cherry pick: Support for multiple class, inheritance and member annotations
CL: https://r8-review.googlesource.com/c/r8/+/52010

Cherry pick: Remove ImmutableList.builderWithExpectedSize() use
CL: https://r8-review.googlesource.com/c/r8/+/52040

Bug: 158454684
Change-Id: I961eb124a597b733fe94cacb877bbb2b84725569
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index f4cd7bf..bb3e17f 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "2.1.37";
+  public static final String LABEL = "2.1.38";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java b/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java
index f5a3bbf..5b97077 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.shaking;
 
 import com.android.tools.r8.graph.DexAnnotation;
+import java.util.List;
 
 public abstract class AnnotationMatchResult {
 
@@ -30,14 +31,14 @@
 
   static class ConcreteAnnotationMatchResult extends AnnotationMatchResult {
 
-    private final DexAnnotation matchedAnnotation;
+    private final List<DexAnnotation> matchedAnnotations;
 
-    public ConcreteAnnotationMatchResult(DexAnnotation matchedAnnotation) {
-      this.matchedAnnotation = matchedAnnotation;
+    public ConcreteAnnotationMatchResult(List<DexAnnotation> matchedAnnotations) {
+      this.matchedAnnotations = matchedAnnotations;
     }
 
-    public DexAnnotation getMatchedAnnotation() {
-      return matchedAnnotation;
+    public List<DexAnnotation> getMatchedAnnotations() {
+      return matchedAnnotations;
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
index 4e69cd2..ccda8e3 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
@@ -39,13 +39,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules,
@@ -59,13 +59,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
@@ -74,13 +74,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java b/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
index 43bfe4b..ee57043 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
@@ -34,9 +34,21 @@
 
     @Override
     public ClassMergingRule build() {
-      return new ClassMergingRule(origin, getPosition(), source, classAnnotation, classAccessFlags,
-          negatedClassAccessFlags, classTypeNegated, classType, classNames, inheritanceAnnotation,
-          inheritanceClassName, inheritanceIsExtends, memberRules, type);
+      return new ClassMergingRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules,
+          type);
     }
   }
 
@@ -46,20 +58,31 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
       Type type) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
     this.type = type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java
index 8288bde..540db63 100644
--- a/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java
@@ -24,7 +24,7 @@
     if (enqueuer.getMode().isInitialTreeShaking()
         && annotationMatchResult.isConcreteAnnotationMatchResult()) {
       enqueuer.retainAnnotationForFinalTreeShaking(
-          annotationMatchResult.asConcreteAnnotationMatchResult().getMatchedAnnotation());
+          annotationMatchResult.asConcreteAnnotationMatchResult().getMatchedAnnotations());
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
index 6d6f424..bc33778 100644
--- a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
@@ -27,13 +27,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules);
@@ -44,13 +44,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
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 1cc091d..6878c05 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3334,10 +3334,10 @@
     desugaredLambdaImplementationMethods.clear();
   }
 
-  void retainAnnotationForFinalTreeShaking(DexAnnotation annotation) {
+  void retainAnnotationForFinalTreeShaking(List<DexAnnotation> annotations) {
     assert mode.isInitialTreeShaking();
     if (annotationRemoverBuilder != null) {
-      annotationRemoverBuilder.retainAnnotation(annotation);
+      annotations.forEach(annotationRemoverBuilder::retainAnnotation);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java b/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java
index aa37771..527565f 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java
@@ -12,7 +12,7 @@
 
   @Override
   protected boolean doEquivalent(ProguardIfRule p1, ProguardIfRule p2) {
-    if (!Objects.equals(p1.getClassAnnotation(), p2.getClassAnnotation())) {
+    if (!p1.getClassAnnotations().equals(p2.getClassAnnotations())) {
       return false;
     }
     if (!p1.getClassAccessFlags().equals(p2.getClassAccessFlags())
@@ -26,7 +26,7 @@
     if (p1.getInheritanceIsExtends() != p2.getInheritanceIsExtends()) {
       return false;
     }
-    if (!Objects.equals(p1.getInheritanceAnnotation(), p2.getInheritanceAnnotation())) {
+    if (!p1.getInheritanceAnnotations().equals(p2.getInheritanceAnnotations())) {
       return false;
     }
     if (!Objects.equals(p1.getInheritanceClassName(), p2.getInheritanceClassName())) {
@@ -40,17 +40,13 @@
 
   @Override
   protected int doHash(ProguardIfRule rule) {
-    int result = (rule.getClassAnnotation() != null ? rule.getClassAnnotation().hashCode() : 0);
+    int result = rule.getClassAnnotations().hashCode();
     result = 3 * result + rule.getClassAccessFlags().hashCode();
     result = 3 * result + rule.getNegatedClassAccessFlags().hashCode();
     result = 3 * result + (rule.getClassTypeNegated() ? 1 : 0);
     result = 3 * result + (rule.getClassType() != null ? rule.getClassType().hashCode() : 0);
     result = 3 * result + rule.getClassNames().hashCode();
-    result =
-        3 * result
-            + (rule.getInheritanceAnnotation() != null
-                ? rule.getInheritanceAnnotation().hashCode()
-                : 0);
+    result = 3 * result + rule.getInheritanceAnnotations().hashCode();
     result =
         3 * result
             + (rule.getInheritanceClassName() != null
diff --git a/src/main/java/com/android/tools/r8/shaking/InlineRule.java b/src/main/java/com/android/tools/r8/shaking/InlineRule.java
index ca746a1..41b6b33 100644
--- a/src/main/java/com/android/tools/r8/shaking/InlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/InlineRule.java
@@ -41,9 +41,21 @@
 
     @Override
     public InlineRule build() {
-      return new InlineRule(origin, getPosition(), source, classAnnotation, classAccessFlags,
-          negatedClassAccessFlags, classTypeNegated, classType, classNames, inheritanceAnnotation,
-          inheritanceClassName, inheritanceIsExtends, memberRules, type);
+      return new InlineRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules,
+          type);
     }
   }
 
@@ -53,20 +65,31 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
       Type type) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
     this.type = type;
   }
 
@@ -83,13 +106,13 @@
     ProguardCheckDiscardRule.Builder builder = ProguardCheckDiscardRule.builder();
     builder.setOrigin(checkDiscardOrigin);
     builder.setSource(null);
-    builder.setClassAnnotation(getClassAnnotation());
+    builder.addClassAnnotations(getClassAnnotations());
     builder.setClassAccessFlags(getClassAccessFlags());
     builder.setNegatedClassAccessFlags(getNegatedClassAccessFlags());
     builder.setClassTypeNegated(getClassTypeNegated());
     builder.setClassType(getClassType());
     builder.setClassNames(getClassNames());
-    builder.setInheritanceAnnotation(getInheritanceAnnotation());
+    builder.addInheritanceAnnotations(getInheritanceAnnotations());
     builder.setInheritanceIsExtends(getInheritanceIsExtends());
     builder.setMemberRules(getMemberRules());
     return builder.build();
diff --git a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java b/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
index dde4631..c26832b 100644
--- a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
@@ -35,9 +35,21 @@
 
     @Override
     public MemberValuePropagationRule build() {
-      return new MemberValuePropagationRule(origin, getPosition(), source, classAnnotation,
-          classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
-          inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules, type);
+      return new MemberValuePropagationRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules,
+          type);
     }
   }
 
@@ -47,20 +59,31 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
       Type type) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
     this.type = type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java
index 01b7a5e..654bc3e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java
@@ -27,13 +27,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules);
@@ -44,13 +44,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
index 5f8e860..ed151aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
@@ -23,9 +23,20 @@
 
     @Override
     public ProguardAssumeNoSideEffectRule build() {
-      return new ProguardAssumeNoSideEffectRule(origin, getPosition(), source, classAnnotation,
-          classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
-          inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+      return new ProguardAssumeNoSideEffectRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
     }
   }
 
@@ -33,19 +44,30 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
index 8b8f4dd..97d901e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
@@ -23,9 +23,20 @@
 
     @Override
     public ProguardAssumeValuesRule build() {
-      return new ProguardAssumeValuesRule(origin, getPosition(), source, classAnnotation,
-          classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
-          inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+      return new ProguardAssumeValuesRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
     }
   }
 
@@ -33,19 +44,30 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
index 664cb25..82b81a4 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
@@ -23,9 +23,20 @@
 
     @Override
     public ProguardCheckDiscardRule build() {
-      return new ProguardCheckDiscardRule(origin, getPosition(), source, classAnnotation,
-          classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
-          inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+      return new ProguardCheckDiscardRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
     }
   }
 
@@ -33,19 +44,30 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
   }
 
   public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
index 9ae4986..2bf270a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.position.TextRange;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
@@ -22,13 +23,15 @@
     protected Position start;
     protected Position end;
     protected String source;
-    protected ProguardTypeMatcher classAnnotation;
+    private final ImmutableList.Builder<ProguardTypeMatcher> classAnnotations =
+        ImmutableList.builder();
     protected ProguardAccessFlags classAccessFlags = new ProguardAccessFlags();
     protected ProguardAccessFlags negatedClassAccessFlags = new ProguardAccessFlags();
     protected boolean classTypeNegated = false;
     protected ProguardClassType classType = ProguardClassType.UNSPECIFIED;
     protected ProguardClassNameList classNames;
-    protected ProguardTypeMatcher inheritanceAnnotation;
+    private final ImmutableList.Builder<ProguardTypeMatcher> inheritanceAnnotations =
+        ImmutableList.builder();
     protected ProguardTypeMatcher inheritanceClassName;
     protected boolean inheritanceIsExtends = false;
     protected List<ProguardMemberRule> memberRules = new LinkedList<>();
@@ -105,12 +108,13 @@
       this.inheritanceClassName = inheritanceClassName;
     }
 
-    public ProguardTypeMatcher getInheritanceAnnotation() {
-      return inheritanceAnnotation;
+    public void addInheritanceAnnotations(List<ProguardTypeMatcher> inheritanceAnnotations) {
+      assert inheritanceAnnotations != null;
+      this.inheritanceAnnotations.addAll(inheritanceAnnotations);
     }
 
-    public void setInheritanceAnnotation(ProguardTypeMatcher inheritanceAnnotation) {
-      this.inheritanceAnnotation = inheritanceAnnotation;
+    public List<ProguardTypeMatcher> buildInheritanceAnnotations() {
+      return inheritanceAnnotations.build();
     }
 
     public ProguardClassNameList getClassNames() {
@@ -155,12 +159,17 @@
       negatedClassAccessFlags = flags;
     }
 
-    public ProguardTypeMatcher getClassAnnotation() {
-      return classAnnotation;
+    public void addClassAnnotation(ProguardTypeMatcher classAnnotation) {
+      classAnnotations.add(classAnnotation);
     }
 
-    public void setClassAnnotation(ProguardTypeMatcher classAnnotation) {
-      this.classAnnotation = classAnnotation;
+    public void addClassAnnotations(List<ProguardTypeMatcher> classAnnotations) {
+      assert classAnnotations != null;
+      this.classAnnotations.addAll(classAnnotations);
+    }
+
+    public List<ProguardTypeMatcher> buildClassAnnotations() {
+      return classAnnotations.build();
     }
 
     protected void matchAllSpecification() {
@@ -172,13 +181,13 @@
   private final Origin origin;
   private final Position position;
   private final String source;
-  private final ProguardTypeMatcher classAnnotation;
+  private final List<ProguardTypeMatcher> classAnnotations;
   private final ProguardAccessFlags classAccessFlags;
   private final ProguardAccessFlags negatedClassAccessFlags;
   private final boolean classTypeNegated;
   private final ProguardClassType classType;
   private final ProguardClassNameList classNames;
-  private final ProguardTypeMatcher inheritanceAnnotation;
+  private final List<ProguardTypeMatcher> inheritanceAnnotations;
   private final ProguardTypeMatcher inheritanceClassName;
   private final boolean inheritanceIsExtends;
   private final List<ProguardMemberRule> memberRules;
@@ -187,13 +196,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
@@ -202,15 +211,15 @@
     assert source != null || origin != Origin.unknown();
     this.origin = origin;
     this.position = position;
-    this.source =source;
-    this.classAnnotation = classAnnotation;
+    this.source = source;
+    this.classAnnotations = classAnnotations;
     this.classAccessFlags = classAccessFlags;
     this.negatedClassAccessFlags = negatedClassAccessFlags;
     this.classTypeNegated = classTypeNegated;
     this.classType = classType;
     assert classType != null;
     this.classNames = classNames;
-    this.inheritanceAnnotation = inheritanceAnnotation;
+    this.inheritanceAnnotations = inheritanceAnnotations;
     this.inheritanceClassName = inheritanceClassName;
     this.inheritanceIsExtends = inheritanceIsExtends;
     this.memberRules = memberRules;
@@ -248,8 +257,8 @@
     return inheritanceClassName;
   }
 
-  public ProguardTypeMatcher getInheritanceAnnotation() {
-    return inheritanceAnnotation;
+  public List<ProguardTypeMatcher> getInheritanceAnnotations() {
+    return inheritanceAnnotations;
   }
 
   public ProguardClassNameList getClassNames() {
@@ -272,8 +281,8 @@
     return negatedClassAccessFlags;
   }
 
-  public ProguardTypeMatcher getClassAnnotation() {
-    return classAnnotation;
+  public List<ProguardTypeMatcher> getClassAnnotations() {
+    return classAnnotations;
   }
 
   @Override
@@ -289,7 +298,7 @@
     if (inheritanceIsExtends != that.inheritanceIsExtends) {
       return false;
     }
-    if (!Objects.equals(classAnnotation, that.classAnnotation)) {
+    if (!Objects.equals(classAnnotations, that.classAnnotations)) {
       return false;
     }
     if (!classAccessFlags.equals(that.classAccessFlags)) {
@@ -304,7 +313,7 @@
     if (!classNames.equals(that.classNames)) {
       return false;
     }
-    if (!Objects.equals(inheritanceAnnotation, that.inheritanceAnnotation)) {
+    if (!Objects.equals(inheritanceAnnotations, that.inheritanceAnnotations)) {
       return false;
     }
     if (!Objects.equals(inheritanceClassName, that.inheritanceClassName)) {
@@ -316,13 +325,13 @@
   @Override
   public int hashCode() {
     // Used multiplier 3 to avoid too much overflow when computing hashCode.
-    int result = (classAnnotation != null ? classAnnotation.hashCode() : 0);
+    int result = classAnnotations.hashCode();
     result = 3 * result + classAccessFlags.hashCode();
     result = 3 * result + negatedClassAccessFlags.hashCode();
     result = 3 * result + (classTypeNegated ? 1 : 0);
     result = 3 * result + (classType != null ? classType.hashCode() : 0);
     result = 3 * result + classNames.hashCode();
-    result = 3 * result + (inheritanceAnnotation != null ? inheritanceAnnotation.hashCode() : 0);
+    result = 3 * result + inheritanceAnnotations.hashCode();
     result = 3 * result + (inheritanceClassName != null ? inheritanceClassName.hashCode() : 0);
     result = 3 * result + (inheritanceIsExtends ? 1 : 0);
     result = 3 * result + memberRules.hashCode();
@@ -330,9 +339,9 @@
   }
 
   protected StringBuilder append(StringBuilder builder, boolean includeMemberRules) {
+    appendAnnotations(classAnnotations, builder);
     boolean needsSpaceBeforeClassType =
-        StringUtils.appendNonEmpty(builder, "@", classAnnotation, null)
-            | StringUtils.appendNonEmpty(builder, "", classAccessFlags, null)
+        StringUtils.appendNonEmpty(builder, null, classAccessFlags, null)
             | StringUtils.appendNonEmpty(
                 builder, "!", negatedClassAccessFlags.toString().replace(" ", " !"), null);
     if (needsSpaceBeforeClassType) {
@@ -345,9 +354,8 @@
     builder.append(' ');
     classNames.writeTo(builder);
     if (hasInheritanceClassName()) {
-      builder.append(' ').append(inheritanceIsExtends ? "extends" : "implements");
-      StringUtils.appendNonEmpty(builder, "@", inheritanceAnnotation, null);
-      builder.append(' ');
+      builder.append(' ').append(inheritanceIsExtends ? "extends" : "implements").append(' ');
+      appendAnnotations(inheritanceAnnotations, builder);
       builder.append(inheritanceClassName);
     }
     if (includeMemberRules && !memberRules.isEmpty()) {
@@ -362,6 +370,18 @@
     return builder;
   }
 
+  private static void appendAnnotations(
+      List<ProguardTypeMatcher> annotations, StringBuilder builder) {
+    if (!annotations.isEmpty()) {
+      Iterator<ProguardTypeMatcher> annotationIterator = annotations.iterator();
+      builder.append('@').append(annotationIterator.next());
+      while (annotationIterator.hasNext()) {
+        builder.append(" @").append(annotationIterator.next());
+      }
+      builder.append(' ');
+    }
+  }
+
   /**
    * Short String representation without member rules.
    */
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index aee4a83..58bbdae 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -897,7 +897,7 @@
         ProguardClassSpecification.Builder<C, B> builder,
         boolean allowValueSpecification)
         throws ProguardRuleParserException {
-      parseClassFlagsAndAnnotations(builder);
+      parseClassAnnotationsAndFlags(builder);
       parseClassType(builder);
       builder.setClassNames(parseClassNames());
       parseInheritance(builder);
@@ -965,6 +965,18 @@
       }
     }
 
+    private List<ProguardTypeMatcher> parseAnnotationList() throws ProguardRuleParserException {
+      List<ProguardTypeMatcher> annotations = null;
+      ProguardTypeMatcher current;
+      while ((current = parseAnnotation()) != null) {
+        if (annotations == null) {
+          annotations = new ArrayList<>(2);
+        }
+        annotations.add(current);
+      }
+      return annotations != null ? annotations : Collections.emptyList();
+    }
+
     private ProguardTypeMatcher parseAnnotation() throws ProguardRuleParserException {
       skipWhitespace();
       int startPosition = position;
@@ -988,16 +1000,14 @@
       return acceptChar('!');
     }
 
-    private void parseClassFlagsAndAnnotations(ProguardClassSpecification.Builder builder)
+    private void parseClassAnnotationsAndFlags(ProguardClassSpecification.Builder<?, ?> builder)
         throws ProguardRuleParserException {
+      // We allow interleaving the class annotations and class flags for compatibility with
+      // Proguard, although this should not be possible according to the grammar.
       while (true) {
-        skipWhitespace();
         ProguardTypeMatcher annotation = parseAnnotation();
         if (annotation != null) {
-          // TODO(ager): Should we only allow one annotation? It looks that way from the
-          // proguard keep rule description, but that seems like a strange restriction?
-          assert builder.getClassAnnotation() == null;
-          builder.setClassAnnotation(annotation);
+          builder.addClassAnnotation(annotation);
         } else {
           int start = position;
           ProguardAccessFlags flags =
@@ -1025,7 +1035,7 @@
           "Expected [!]interface|@interface|class|enum", origin, getPosition(start));
     }
 
-    private void parseClassType(ProguardClassSpecification.Builder builder) {
+    private void parseClassType(ProguardClassSpecification.Builder<?, ?> builder) {
       skipWhitespace();
       TextPosition start = getPosition();
       if (acceptChar('!')) {
@@ -1049,7 +1059,8 @@
       }
     }
 
-    private void parseInheritance(ProguardClassSpecification.Builder classSpecificationBuilder)
+    private void parseInheritance(
+        ProguardClassSpecification.Builder<?, ?> classSpecificationBuilder)
         throws ProguardRuleParserException {
       skipWhitespace();
       if (acceptString("implements")) {
@@ -1059,7 +1070,7 @@
       } else {
         return;
       }
-      classSpecificationBuilder.setInheritanceAnnotation(parseAnnotation());
+      classSpecificationBuilder.addInheritanceAnnotations(parseAnnotationList());
       classSpecificationBuilder.setInheritanceClassName(ProguardTypeMatcher.create(parseClassName(),
           ClassOrType.CLASS, dexItemFactory));
     }
@@ -1084,8 +1095,7 @@
     private ProguardMemberRule parseMemberRule(boolean allowValueSpecification)
         throws ProguardRuleParserException {
       ProguardMemberRule.Builder ruleBuilder = ProguardMemberRule.builder();
-      skipWhitespace();
-      ruleBuilder.setAnnotation(parseAnnotation());
+      ruleBuilder.setAnnotations(parseAnnotationList());
       parseMemberAccessFlags(ruleBuilder);
       parseMemberPattern(ruleBuilder, allowValueSpecification);
       return ruleBuilder.isValid() ? ruleBuilder.build() : null;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index 0e21e66..4a19c6f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -27,19 +27,30 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
   }
 
   public boolean isUsed() {
@@ -124,17 +135,16 @@
   protected Iterable<ProguardWildcard> getWildcards() {
     List<ProguardMemberRule> memberRules = getMemberRules();
     return Iterables.concat(
-        ProguardTypeMatcher.getWildcardsOrEmpty(getClassAnnotation()),
+        ProguardTypeMatcher.getWildcardsOrEmpty(getClassAnnotations()),
         ProguardClassNameList.getWildcardsOrEmpty(getClassNames()),
-        ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceAnnotation()),
+        ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceAnnotations()),
         ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceClassName()),
         memberRules != null
             ? memberRules.stream()
-                .map(ProguardMemberRule::getWildcards)
-                .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+                    .map(ProguardMemberRule::getWildcards)
+                    .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
                 ::iterator
-            : Collections::emptyIterator
-    );
+            : Collections::emptyIterator);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
index 8ff7670..37c75a1 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
@@ -22,9 +22,20 @@
 
     @Override
     public ProguardIdentifierNameStringRule build() {
-      return new ProguardIdentifierNameStringRule(origin, getPosition(), source, classAnnotation,
-          classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
-          inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+      return new ProguardIdentifierNameStringRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
     }
   }
 
@@ -32,19 +43,30 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
   }
 
   public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
index ba9ec8a..c8e185f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
@@ -58,13 +58,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules,
@@ -77,22 +77,34 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
       ProguardKeepRule subsequentRule,
       Set<DexReference> preconditions) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules,
-        ProguardKeepRuleType.CONDITIONAL, ProguardKeepRuleModifiers.builder().build());
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules,
+        ProguardKeepRuleType.CONDITIONAL,
+        ProguardKeepRuleModifiers.builder().build());
     this.subsequentRule = subsequentRule;
     this.preconditions = preconditions;
   }
@@ -122,15 +134,13 @@
         getOrigin(),
         getPosition(),
         getSource(),
-        getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
         getClassAccessFlags(),
         getNegatedClassAccessFlags(),
         getClassTypeNegated(),
         getClassType(),
         getClassNames().materialize(dexItemFactory),
-        getInheritanceAnnotation() == null
-            ? null
-            : getInheritanceAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
         getInheritanceClassName() == null
             ? null
             : getInheritanceClassName().materialize(dexItemFactory),
@@ -149,15 +159,13 @@
         neverInlineOrigin,
         Position.UNKNOWN,
         null,
-        getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
         getClassAccessFlags(),
         getNegatedClassAccessFlags(),
         getClassTypeNegated(),
         getClassType(),
         getClassNames().materialize(dexItemFactory),
-        getInheritanceAnnotation() == null
-            ? null
-            : getInheritanceAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
         getInheritanceClassName() == null
             ? null
             : getInheritanceClassName().materialize(dexItemFactory),
@@ -196,15 +204,13 @@
         neverInlineOrigin,
         Position.UNKNOWN,
         null,
-        getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
         getClassAccessFlags(),
         getNegatedClassAccessFlags(),
         getClassTypeNegated(),
         getClassType(),
         getClassNames().materialize(dexItemFactory),
-        getInheritanceAnnotation() == null
-            ? null
-            : getInheritanceAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
         getInheritanceClassName() == null
             ? null
             : getInheritanceClassName().materialize(dexItemFactory),
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
index 4633882..305c108 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
@@ -25,9 +25,22 @@
 
     @Override
     public ProguardKeepRule build() {
-      return new ProguardKeepRule(origin, getPosition(), source, classAnnotation, classAccessFlags,
-          negatedClassAccessFlags, classTypeNegated, classType, classNames, inheritanceAnnotation,
-          inheritanceClassName, inheritanceIsExtends, memberRules, type, modifiersBuilder.build());
+      return new ProguardKeepRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules,
+          type,
+          modifiersBuilder.build());
     }
   }
 
@@ -35,21 +48,34 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
       ProguardKeepRuleType type,
       ProguardKeepRuleModifiers modifiers) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules, type, modifiers);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules,
+        type,
+        modifiers);
   }
 
   /**
@@ -64,15 +90,13 @@
         getOrigin(),
         getPosition(),
         getSource(),
-        getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
         getClassAccessFlags(),
         getNegatedClassAccessFlags(),
         getClassTypeNegated(),
         getClassType(),
         getClassNames() == null ? null : getClassNames().materialize(dexItemFactory),
-        getInheritanceAnnotation() == null
-            ? null
-            : getInheritanceAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
         getInheritanceClassName() == null
             ? null
             : getInheritanceClassName().materialize(dexItemFactory),
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
index 7455469..b87e5a6 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
@@ -43,21 +43,32 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
       ProguardKeepRuleType type,
       ProguardKeepRuleModifiers modifiers) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
     this.type = type;
     this.modifiers = modifiers;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
index 1a894d3..3034f6d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
@@ -24,7 +24,7 @@
 
   public static class Builder {
 
-    private ProguardTypeMatcher annotation;
+    private List<ProguardTypeMatcher> annotations = Collections.emptyList();
     private ProguardAccessFlags accessFlags = new ProguardAccessFlags();
     private ProguardAccessFlags negatedAccessFlags = new ProguardAccessFlags();
     private ProguardMemberType ruleType;
@@ -35,8 +35,9 @@
 
     private Builder() {}
 
-    public void setAnnotation(ProguardTypeMatcher annotation) {
-      this.annotation = annotation;
+    public void setAnnotations(List<ProguardTypeMatcher> annotations) {
+      assert annotations != null;
+      this.annotations = annotations;
     }
 
     public ProguardAccessFlags getAccessFlags() {
@@ -91,12 +92,19 @@
 
     public ProguardMemberRule build() {
       assert isValid();
-      return new ProguardMemberRule(annotation, accessFlags, negatedAccessFlags, ruleType, type,
-          name, arguments, returnValue);
+      return new ProguardMemberRule(
+          annotations,
+          accessFlags,
+          negatedAccessFlags,
+          ruleType,
+          type,
+          name,
+          arguments,
+          returnValue);
     }
   }
 
-  private final ProguardTypeMatcher annotation;
+  private final List<ProguardTypeMatcher> annotations;
   private final ProguardAccessFlags accessFlags;
   private final ProguardAccessFlags negatedAccessFlags;
   private final ProguardMemberType ruleType;
@@ -106,7 +114,7 @@
   private final ProguardMemberRuleReturnValue returnValue;
 
   private ProguardMemberRule(
-      ProguardTypeMatcher annotation,
+      List<ProguardTypeMatcher> annotations,
       ProguardAccessFlags accessFlags,
       ProguardAccessFlags negatedAccessFlags,
       ProguardMemberType ruleType,
@@ -114,7 +122,7 @@
       ProguardNameMatcher name,
       List<ProguardTypeMatcher> arguments,
       ProguardMemberRuleReturnValue returnValue) {
-    this.annotation = annotation;
+    this.annotations = annotations;
     this.accessFlags = accessFlags;
     this.negatedAccessFlags = negatedAccessFlags;
     this.ruleType = ruleType;
@@ -131,8 +139,8 @@
     return new Builder();
   }
 
-  public ProguardTypeMatcher getAnnotation() {
-    return annotation;
+  public List<ProguardTypeMatcher> getAnnotations() {
+    return annotations;
   }
 
   public ProguardAccessFlags getAccessFlags() {
@@ -187,7 +195,8 @@
             break;
           }
           // Annotations check.
-          return RootSetBuilder.containsAnnotation(annotation, field, matchedAnnotationsConsumer);
+          return RootSetBuilder.containsAllAnnotations(
+              annotations, field, matchedAnnotationsConsumer);
         }
 
       case FIELD:
@@ -207,7 +216,8 @@
             break;
           }
           // Annotations check
-          return RootSetBuilder.containsAnnotation(annotation, field, matchedAnnotationsConsumer);
+          return RootSetBuilder.containsAllAnnotations(
+              annotations, field, matchedAnnotationsConsumer);
         }
 
       case ALL_METHODS:
@@ -241,7 +251,8 @@
             break;
           }
           // Annotations check.
-          return RootSetBuilder.containsAnnotation(annotation, method, matchedAnnotationsConsumer);
+          return RootSetBuilder.containsAllAnnotations(
+              annotations, method, matchedAnnotationsConsumer);
         }
 
       case METHOD:
@@ -266,7 +277,8 @@
             break;
           }
           // Annotations check.
-          if (!RootSetBuilder.containsAnnotation(annotation, method, matchedAnnotationsConsumer)) {
+          if (!RootSetBuilder.containsAllAnnotations(
+              annotations, method, matchedAnnotationsConsumer)) {
             return false;
           }
           // Parameter types check.
@@ -309,21 +321,20 @@
 
   Iterable<ProguardWildcard> getWildcards() {
     return Iterables.concat(
-        ProguardTypeMatcher.getWildcardsOrEmpty(annotation),
+        ProguardTypeMatcher.getWildcardsOrEmpty(annotations),
         ProguardTypeMatcher.getWildcardsOrEmpty(type),
         ProguardNameMatcher.getWildcardsOrEmpty(name),
         arguments != null
             ? arguments.stream()
-                .map(ProguardTypeMatcher::getWildcards)
-                .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+                    .map(ProguardTypeMatcher::getWildcards)
+                    .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
                 ::iterator
-            : Collections::emptyIterator
-    );
+            : Collections::emptyIterator);
   }
 
   ProguardMemberRule materialize(DexItemFactory dexItemFactory) {
     return new ProguardMemberRule(
-        getAnnotation() == null ? null : getAnnotation().materialize(dexItemFactory),
+        ProguardTypeMatcher.materializeList(getAnnotations(), dexItemFactory),
         getAccessFlags(),
         getNegatedAccessFlags(),
         getRuleType(),
@@ -345,7 +356,7 @@
 
     ProguardMemberRule that = (ProguardMemberRule) o;
 
-    if (annotation != null ? !annotation.equals(that.annotation) : that.annotation != null) {
+    if (!annotations.equals(that.annotations)) {
       return false;
     }
     if (!accessFlags.equals(that.accessFlags)) {
@@ -368,7 +379,7 @@
 
   @Override
   public int hashCode() {
-    int result = annotation != null ? annotation.hashCode() : 0;
+    int result = annotations.hashCode();
     result = 31 * result + accessFlags.hashCode();
     result = 31 * result + negatedAccessFlags.hashCode();
     result = 31 * result + (ruleType != null ? ruleType.hashCode() : 0);
@@ -381,7 +392,9 @@
   @Override
   public String toString() {
     StringBuilder result = new StringBuilder();
-    ProguardKeepRule.appendNonEmpty(result, "@", annotation, " ");
+    for (ProguardTypeMatcher annotation : annotations) {
+      ProguardKeepRule.appendNonEmpty(result, "@", annotation, " ");
+    }
     ProguardKeepRule.appendNonEmpty(result, null, accessFlags, " ");
     ProguardKeepRule
         .appendNonEmpty(result, null, negatedAccessFlags.toString().replace(" ", " !"), " ");
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
index a4db6a2..19bd876 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
@@ -36,6 +36,10 @@
     TYPE
   }
 
+  public MatchSpecificType asSpecificTypeMatcher() {
+    return null;
+  }
+
   // Evaluates this matcher on the given type.
   public abstract boolean matches(DexType type);
 
@@ -59,10 +63,30 @@
     return typeMatcher == null ? Collections::emptyIterator : typeMatcher.getWildcards();
   }
 
+  static Iterable<ProguardWildcard> getWildcardsOrEmpty(List<ProguardTypeMatcher> typeMatchers) {
+    List<ProguardWildcard> result = new ArrayList<>();
+    for (ProguardTypeMatcher typeMatcher : typeMatchers) {
+      typeMatcher.getWildcards().forEach(result::add);
+    }
+    return result;
+  }
+
   protected ProguardTypeMatcher materialize(DexItemFactory dexItemFactory) {
     return this;
   }
 
+  public static List<ProguardTypeMatcher> materializeList(
+      List<ProguardTypeMatcher> matchers, DexItemFactory dexItemFactory) {
+    if (matchers.isEmpty()) {
+      return Collections.emptyList();
+    }
+    ImmutableList.Builder<ProguardTypeMatcher> builder = ImmutableList.builder();
+    for (ProguardTypeMatcher matcher : matchers) {
+      builder.add(matcher.materialize(dexItemFactory));
+    }
+    return builder.build();
+  }
+
   @Override
   public abstract String toString();
 
@@ -312,6 +336,11 @@
     }
 
     @Override
+    public MatchSpecificType asSpecificTypeMatcher() {
+      return this;
+    }
+
+    @Override
     public boolean matches(DexType type) {
       return this.type == type;
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
index 87200fb..4083ff5 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
@@ -23,9 +23,20 @@
 
     @Override
     public ProguardWhyAreYouKeepingRule build() {
-      return new ProguardWhyAreYouKeepingRule(origin, getPosition(), source, classAnnotation,
-          classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
-          inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+      return new ProguardWhyAreYouKeepingRule(
+          origin,
+          getPosition(),
+          source,
+          buildClassAnnotations(),
+          classAccessFlags,
+          negatedClassAccessFlags,
+          classTypeNegated,
+          classType,
+          classNames,
+          buildInheritanceAnnotations(),
+          inheritanceClassName,
+          inheritanceIsExtends,
+          memberRules);
     }
   }
 
@@ -33,19 +44,30 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
-    super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
-        classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
-        inheritanceIsExtends, memberRules);
+    super(
+        origin,
+        position,
+        source,
+        classAnnotations,
+        classAccessFlags,
+        negatedClassAccessFlags,
+        classTypeNegated,
+        classType,
+        classNames,
+        inheritanceAnnotations,
+        inheritanceClassName,
+        inheritanceIsExtends,
+        memberRules);
   }
 
   public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java b/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java
index 58e03d9..cfcd1fc 100644
--- a/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java
@@ -40,13 +40,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules,
@@ -60,13 +60,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
@@ -75,13 +75,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java b/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java
index 8e8e288..2c7d19a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java
@@ -40,13 +40,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules,
@@ -60,13 +60,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules,
@@ -75,13 +75,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 73171b4..8419104 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -754,7 +754,7 @@
   }
 
   static AnnotationMatchResult satisfyAnnotation(ProguardConfigurationRule rule, DexClass clazz) {
-    return containsAnnotation(rule.getClassAnnotation(), clazz);
+    return containsAllAnnotations(rule.getClassAnnotations(), clazz);
   }
 
   boolean satisfyInheritanceRule(DexClass clazz, ProguardConfigurationRule rule) {
@@ -786,7 +786,7 @@
       // annotations of `class`.
       if (rule.getInheritanceClassName().matches(clazz.type, appView)) {
         AnnotationMatchResult annotationMatchResult =
-            containsAnnotation(rule.getInheritanceAnnotation(), clazz);
+            containsAllAnnotations(rule.getInheritanceAnnotations(), clazz);
         if (annotationMatchResult != null) {
           handleMatchedAnnotation(annotationMatchResult);
           return true;
@@ -823,7 +823,7 @@
       // annotations of `ifaceClass`.
       if (rule.getInheritanceClassName().matches(iface, appView)) {
         AnnotationMatchResult annotationMatchResult =
-            containsAnnotation(rule.getInheritanceAnnotation(), ifaceClass);
+            containsAllAnnotations(rule.getInheritanceAnnotations(), ifaceClass);
         if (annotationMatchResult != null) {
           handleMatchedAnnotation(annotationMatchResult);
           return true;
@@ -899,17 +899,18 @@
     return false;
   }
 
-  static AnnotationMatchResult containsAnnotation(
-      ProguardTypeMatcher classAnnotation, DexClass clazz) {
-    return containsAnnotation(classAnnotation, clazz.annotations());
+  static AnnotationMatchResult containsAllAnnotations(
+      List<ProguardTypeMatcher> annotationMatchers, DexClass clazz) {
+    return containsAllAnnotations(annotationMatchers, clazz.annotations());
   }
 
-  static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> boolean containsAnnotation(
-      ProguardTypeMatcher classAnnotation,
-      DexEncodedMember<D, R> member,
-      Consumer<AnnotationMatchResult> matchedAnnotationsConsumer) {
+  static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
+      boolean containsAllAnnotations(
+          List<ProguardTypeMatcher> annotationMatchers,
+          DexEncodedMember<D, R> member,
+          Consumer<AnnotationMatchResult> matchedAnnotationsConsumer) {
     AnnotationMatchResult annotationMatchResult =
-        containsAnnotation(classAnnotation, member.annotations());
+        containsAllAnnotations(annotationMatchers, member.annotations());
     if (annotationMatchResult != null) {
       matchedAnnotationsConsumer.accept(annotationMatchResult);
       return true;
@@ -918,7 +919,7 @@
       DexEncodedMethod method = member.asDexEncodedMethod();
       for (int i = 0; i < method.parameterAnnotationsList.size(); i++) {
         annotationMatchResult =
-            containsAnnotation(classAnnotation, method.parameterAnnotationsList.get(i));
+            containsAllAnnotations(annotationMatchers, method.parameterAnnotationsList.get(i));
         if (annotationMatchResult != null) {
           matchedAnnotationsConsumer.accept(annotationMatchResult);
           return true;
@@ -928,14 +929,28 @@
     return false;
   }
 
-  private static AnnotationMatchResult containsAnnotation(
-      ProguardTypeMatcher classAnnotation, DexAnnotationSet annotations) {
-    if (classAnnotation == null) {
+  private static AnnotationMatchResult containsAllAnnotations(
+      List<ProguardTypeMatcher> annotationMatchers, DexAnnotationSet annotations) {
+    if (annotationMatchers.isEmpty()) {
       return AnnotationsIgnoredMatchResult.getInstance();
     }
+    List<DexAnnotation> matchedAnnotations = new ArrayList<>();
+    for (ProguardTypeMatcher annotationMatcher : annotationMatchers) {
+      DexAnnotation matchedAnnotation =
+          getFirstAnnotationThatMatches(annotationMatcher, annotations);
+      if (matchedAnnotation == null) {
+        return null;
+      }
+      matchedAnnotations.add(matchedAnnotation);
+    }
+    return new ConcreteAnnotationMatchResult(matchedAnnotations);
+  }
+
+  private static DexAnnotation getFirstAnnotationThatMatches(
+      ProguardTypeMatcher annotationMatcher, DexAnnotationSet annotations) {
     for (DexAnnotation annotation : annotations.annotations) {
-      if (classAnnotation.matches(annotation.annotation.type)) {
-        return new ConcreteAnnotationMatchResult(annotation);
+      if (annotationMatcher.matches(annotation.getAnnotationType())) {
+        return annotation;
       }
     }
     return null;
diff --git a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
index 1098bcd..dd537bc 100644
--- a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
@@ -27,13 +27,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules);
@@ -44,13 +44,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java b/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
index aa52ca3..0f2f684 100644
--- a/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
@@ -27,13 +27,13 @@
           origin,
           getPosition(),
           source,
-          classAnnotation,
+          buildClassAnnotations(),
           classAccessFlags,
           negatedClassAccessFlags,
           classTypeNegated,
           classType,
           classNames,
-          inheritanceAnnotation,
+          buildInheritanceAnnotations(),
           inheritanceClassName,
           inheritanceIsExtends,
           memberRules);
@@ -44,13 +44,13 @@
       Origin origin,
       Position position,
       String source,
-      ProguardTypeMatcher classAnnotation,
+      List<ProguardTypeMatcher> classAnnotations,
       ProguardAccessFlags classAccessFlags,
       ProguardAccessFlags negatedClassAccessFlags,
       boolean classTypeNegated,
       ProguardClassType classType,
       ProguardClassNameList classNames,
-      ProguardTypeMatcher inheritanceAnnotation,
+      List<ProguardTypeMatcher> inheritanceAnnotations,
       ProguardTypeMatcher inheritanceClassName,
       boolean inheritanceIsExtends,
       List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
         origin,
         position,
         source,
-        classAnnotation,
+        classAnnotations,
         classAccessFlags,
         negatedClassAccessFlags,
         classTypeNegated,
         classType,
         classNames,
-        inheritanceAnnotation,
+        inheritanceAnnotations,
         inheritanceClassName,
         inheritanceIsExtends,
         memberRules);
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 4cada28..222c6a8 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -5,6 +5,7 @@
 
 import static com.android.tools.r8.DiagnosticsChecker.checkDiagnostics;
 import static com.android.tools.r8.shaking.ProguardConfigurationSourceStrings.createConfigurationForTesting;
+import static com.android.tools.r8.utils.BooleanUtils.intValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
@@ -17,6 +18,8 @@
 import static org.junit.Assert.fail;
 
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.graph.ClassAccessFlags;
@@ -34,10 +37,12 @@
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
 import com.android.tools.r8.utils.KeepingDiagnosticHandler;
+import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
@@ -47,6 +52,8 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -55,6 +62,8 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 class EmptyMainClassForProguardTests {
 
@@ -62,6 +71,7 @@
   }
 }
 
+@RunWith(Parameterized.class)
 public class ProguardConfigurationParserTest extends TestBase {
 
   private static final String VALID_PROGUARD_DIR = "src/test/proguard/valid/";
@@ -151,6 +161,13 @@
   private List<String> lineSeparators = ImmutableList.of("\n", "\r\n");
   private List<Character> quotes = ImmutableList.of('"', '\'');
 
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ProguardConfigurationParserTest(TestParameters parameters) {}
+
   @Before
   public void reset() {
     handler = new KeepingDiagnosticHandler();
@@ -187,7 +204,7 @@
   }
 
   @Test
-  public void parseMultipleNamePatterns() throws Exception {
+  public void parseMultipleNamePatterns() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(MULTIPLE_NAME_PATTERNS_FILE));
@@ -210,7 +227,7 @@
   }
 
   @Test
-  public void parseNonJavaIdentifiers() throws Exception {
+  public void parseNonJavaIdentifiers() {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, new Reporter());
@@ -250,8 +267,8 @@
     assertEquals(0x03, matches);
   }
 
-  private void testDontXXX(String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern)
-      throws Exception {
+  private void testDontXXX(
+      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -265,13 +282,13 @@
   }
 
   @Test
-  public void testDontXXX() throws Exception {
+  public void testDontXXX() {
     testDontXXX("warn", ProguardConfiguration::getDontWarnPatterns);
     testDontXXX("note", ProguardConfiguration::getDontNotePatterns);
   }
 
   private void testDontXXXMultiple(
-      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) throws Exception {
+      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -288,13 +305,13 @@
   }
 
   @Test
-  public void testDontWarnMultiple() throws Exception {
+  public void testDontWarnMultiple() {
     testDontXXXMultiple("warn", ProguardConfiguration::getDontWarnPatterns);
     testDontXXXMultiple("note", ProguardConfiguration::getDontNotePatterns);
   }
 
   private void testDontXXXAllExplicitly(
-      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) throws Exception {
+      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -308,13 +325,13 @@
   }
 
   @Test
-  public void testDontWarnAllExplicitly() throws Exception {
+  public void testDontWarnAllExplicitly() {
     testDontXXXAllExplicitly("warn", ProguardConfiguration::getDontWarnPatterns);
     testDontXXXAllExplicitly("note", ProguardConfiguration::getDontNotePatterns);
   }
 
   private void testDontXXXAllImplicitly(
-      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) throws Exception {
+      String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -328,13 +345,13 @@
   }
 
   @Test
-  public void testDontWarnAllImplicitly() throws Exception {
+  public void testDontWarnAllImplicitly() {
     testDontXXXAllImplicitly("warn", ProguardConfiguration::getDontWarnPatterns);
     testDontXXXAllImplicitly("note", ProguardConfiguration::getDontNotePatterns);
   }
 
   @Test
-  public void parseAccessFlags() throws Exception {
+  public void parseAccessFlags() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ACCESS_FLAGS_FILE));
@@ -380,7 +397,7 @@
   }
 
   @Test
-  public void parseWhyAreYouKeeping() throws Exception {
+  public void parseWhyAreYouKeeping() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(WHY_ARE_YOU_KEEPING_FILE));
@@ -395,7 +412,7 @@
   }
 
   @Test
-  public void parseAssumeNoSideEffects() throws Exception {
+  public void parseAssumeNoSideEffects() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS));
@@ -408,7 +425,7 @@
   }
 
   @Test
-  public void parseAssumeNoSideEffectsWithReturnValue() throws Exception {
+  public void parseAssumeNoSideEffectsWithReturnValue() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS_WITH_RETURN_VALUE));
@@ -477,7 +494,7 @@
   }
 
   @Test
-  public void parseAssumeValuesWithReturnValue() throws Exception {
+  public void parseAssumeValuesWithReturnValue() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(ASSUME_VALUES_WITH_RETURN_VALUE));
@@ -546,7 +563,7 @@
   }
 
   @Test
-  public void testAdaptClassStrings() throws Exception {
+  public void testAdaptClassStrings() {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -563,7 +580,7 @@
   }
 
   @Test
-  public void testAdaptClassStringsMultiple() throws Exception {
+  public void testAdaptClassStringsMultiple() {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -584,7 +601,7 @@
   }
 
   @Test
-  public void testAdaptClassStringsAllExplicitly() throws Exception {
+  public void testAdaptClassStringsAllExplicitly() {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -601,7 +618,7 @@
   }
 
   @Test
-  public void testAdaptClassStringsAllImplicitly() throws Exception {
+  public void testAdaptClassStringsAllImplicitly() {
     DexItemFactory dexItemFactory = new DexItemFactory();
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -618,7 +635,7 @@
   }
 
   @Test
-  public void testIdentifierNameString() throws Exception {
+  public void testIdentifierNameString() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     String config1 =
@@ -656,14 +673,22 @@
     });
     assertEquals(1, identifierNameStrings.get(2).getClassNames().size());
     assertEquals("*", identifierNameStrings.get(2).getClassNames().toString());
-    identifierNameStrings.get(2).getMemberRules().forEach(memberRule -> {
-      assertEquals(ProguardMemberType.ALL, memberRule.getRuleType());
-      assertTrue(memberRule.getAnnotation().toString().endsWith("IdentifierNameString"));
-    });
+    identifierNameStrings
+        .get(2)
+        .getMemberRules()
+        .forEach(
+            memberRule -> {
+              assertEquals(ProguardMemberType.ALL, memberRule.getRuleType());
+              assertEquals(1, memberRule.getAnnotations().size());
+              assertTrue(
+                  ListUtils.first(memberRule.getAnnotations())
+                      .toString()
+                      .endsWith("IdentifierNameString"));
+            });
   }
 
   @Test
-  public void parseDontobfuscate() throws Exception {
+  public void parseDontobfuscate() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(DONT_OBFUSCATE));
@@ -673,7 +698,7 @@
   }
 
   @Test
-  public void parseRepackageClassesEmpty() throws Exception {
+  public void parseRepackageClassesEmpty() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_1));
@@ -685,7 +710,7 @@
   }
 
   @Test
-  public void parseRepackageClassesNonEmpty() throws Exception {
+  public void parseRepackageClassesNonEmpty() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_2));
@@ -697,7 +722,7 @@
   }
 
   @Test
-  public void parseFlattenPackageHierarchyEmpty() throws Exception {
+  public void parseFlattenPackageHierarchyEmpty() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_3));
@@ -709,7 +734,7 @@
   }
 
   @Test
-  public void parseFlattenPackageHierarchyNonEmpty() throws Exception {
+  public void parseFlattenPackageHierarchyNonEmpty() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(PACKAGE_OBFUSCATION_4));
@@ -721,7 +746,7 @@
   }
 
   @Test
-  public void flattenPackageHierarchyCannotOverrideRepackageClasses() throws Exception {
+  public void flattenPackageHierarchyCannotOverrideRepackageClasses() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     Path path = Paths.get(PACKAGE_OBFUSCATION_5);
@@ -735,7 +760,7 @@
   }
 
   @Test
-  public void repackageClassesOverridesFlattenPackageHierarchy() throws Exception {
+  public void repackageClassesOverridesFlattenPackageHierarchy() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     Path path = Paths.get(PACKAGE_OBFUSCATION_6);
@@ -749,7 +774,7 @@
   }
 
   @Test
-  public void parseApplyMapping() throws Exception {
+  public void parseApplyMapping() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(APPLY_MAPPING));
@@ -759,7 +784,7 @@
   }
 
   @Test
-  public void parseApplyMappingWithoutFile() throws Exception {
+  public void parseApplyMappingWithoutFile() {
     Path path = Paths.get(APPLY_MAPPING_WITHOUT_FILE);
     try {
       ProguardConfigurationParser parser =
@@ -781,7 +806,7 @@
   }
 
   @Test
-  public void parseIncluding() throws Exception {
+  public void parseIncluding() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(Paths.get(INCLUDING));
@@ -789,7 +814,7 @@
   }
 
   @Test
-  public void parseInvalidIncluding1() throws IOException {
+  public void parseInvalidIncluding1() {
     Path path = Paths.get(INVALID_INCLUDING_1);
     try {
       new ProguardConfigurationParser(new DexItemFactory(), reporter)
@@ -1442,7 +1467,7 @@
   }
 
   @Test
-  public void parseKeepParameterNames() throws Exception {
+  public void parseKeepParameterNames() {
     try {
       ProguardConfigurationParser parser =
           new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -1458,7 +1483,7 @@
   }
 
   @Test
-  public void parseKeepParameterNamesWithoutMinification() throws Exception {
+  public void parseKeepParameterNamesWithoutMinification() {
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     parser.parse(createConfigurationForTesting(ImmutableList.of(
@@ -1483,7 +1508,7 @@
   }
 
   @Test
-  public void parseShortLine() throws IOException {
+  public void parseShortLine() {
     try {
       ProguardConfigurationParser parser =
           new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -1496,7 +1521,7 @@
   }
 
   @Test
-  public void parseNoLocals() throws IOException {
+  public void parseNoLocals() {
     try {
       ProguardConfigurationParser parser =
           new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -2915,4 +2940,239 @@
     parser.parse(proguardConfig);
     verifyParserEndsCleanly();
   }
+
+  @Test
+  public void parseClassAnnotationsAndFlags() {
+    List<String> configurationContents =
+        ImmutableList.of(
+            // 1 annotation without flags.
+            "-keep @Foo class *",
+            // 1 annotation with public flag.
+            "-keep public @Foo class *",
+            "-keep @Foo public class *",
+            // 1 annotation with public final flags.
+            "-keep public final @Foo class *",
+            "-keep public @Foo final class *",
+            "-keep @Foo public final class *",
+            // 2 annotations without flags.
+            "-keep @Foo @Bar class *",
+            // 2 annotations with public flag.
+            "-keep public @Foo @Bar class *",
+            "-keep @Foo public @Bar class *",
+            "-keep @Foo @Bar public class *",
+            // 2 annotations with public final flags.
+            "-keep public final @Foo @Bar class *",
+            "-keep public @Foo final @Bar class *",
+            "-keep public @Foo @Bar final class *",
+            "-keep @Foo public final @Bar class *",
+            "-keep @Foo public @Bar final class *",
+            "-keep @Foo @Bar public final class *");
+    for (String configurationContent : configurationContents) {
+      DexItemFactory dexItemFactory = new DexItemFactory();
+      ProguardConfigurationParser parser =
+          new ProguardConfigurationParser(dexItemFactory, reporter);
+      parser.parse(createConfigurationForTesting(ImmutableList.of(configurationContent)));
+      verifyParserEndsCleanly();
+
+      ProguardConfiguration configuration = parser.getConfig();
+      assertEquals(1, configuration.getRules().size());
+
+      ProguardKeepRule rule = ListUtils.first(configuration.getRules()).asProguardKeepRule();
+      assertEquals(configurationContent.contains("final"), rule.getClassAccessFlags().isFinal());
+      assertEquals(configurationContent.contains("public"), rule.getClassAccessFlags().isPublic());
+      assertEquals(
+          1 + intValue(configurationContent.contains("@Bar")), rule.getClassAnnotations().size());
+
+      ProguardTypeMatcher.MatchSpecificType fooAnnotation =
+          rule.getClassAnnotations().get(0).asSpecificTypeMatcher();
+      assertEquals("Foo", fooAnnotation.getSpecificType().toSourceString());
+
+      if (configurationContent.contains("@Bar")) {
+        ProguardTypeMatcher.MatchSpecificType barAnnotation =
+            rule.getClassAnnotations().get(1).asSpecificTypeMatcher();
+        assertEquals("Bar", barAnnotation.getSpecificType().toSourceString());
+      }
+    }
+  }
+
+  @Test
+  public void parseFieldAnnotationsAndFlags() {
+    Map<String, Optional<Class<? extends Exception>>> configurationContents =
+        ImmutableMap.<String, Optional<Class<? extends Exception>>>builder()
+            // 1 annotation without flags.
+            .put("-keep class * { @Foo Type FIELD; }", Optional.empty())
+            // 1 annotation with public flag.
+            .put("-keep class * { public @Foo Type FIELD; }", Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo public Type FIELD; }", Optional.empty())
+            // 1 annotation with public final flags.
+            .put(
+                "-keep class * { public final @Foo Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { public @Foo final Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo public final Type FIELD; }", Optional.empty())
+            //// 2 annotations without flags.
+            .put("-keep class * { @Foo @Bar Type FIELD; }", Optional.empty())
+            //// 2 annotations with public flag.
+            .put(
+                "-keep class * { public @Foo @Bar Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { @Foo public @Bar Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo @Bar public Type FIELD; }", Optional.empty())
+            //// 2 annotations with public final flags.
+            .put(
+                "-keep class * { public final @Foo @Bar Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { public @Foo final @Bar Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { public @Foo @Bar final Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { @Foo public final @Bar Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { @Foo public @Bar final Type FIELD; }",
+                Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo @Bar public final Type FIELD; }", Optional.empty())
+            .build();
+    configurationContents.forEach(
+        (configurationContent, expectedExceptionClass) -> {
+          DexItemFactory dexItemFactory = new DexItemFactory();
+          ProguardConfigurationParser parser =
+              new ProguardConfigurationParser(dexItemFactory, reporter);
+          try {
+            parser.parse(createConfigurationForTesting(ImmutableList.of(configurationContent)));
+            assertFalse(expectedExceptionClass.isPresent());
+          } catch (Throwable e) {
+            assertTrue(expectedExceptionClass.isPresent());
+            assertEquals(expectedExceptionClass.get(), e.getClass());
+            reset();
+            return;
+          }
+
+          verifyParserEndsCleanly();
+
+          ProguardConfiguration configuration = parser.getConfig();
+          assertEquals(1, configuration.getRules().size());
+
+          ProguardKeepRule rule = ListUtils.first(configuration.getRules()).asProguardKeepRule();
+          assertEquals(1, rule.getMemberRules().size());
+
+          ProguardMemberRule memberRule = ListUtils.first(rule.getMemberRules());
+
+          assertEquals(
+              configurationContent.contains("final"), memberRule.getAccessFlags().isFinal());
+          assertEquals(
+              configurationContent.contains("public"), memberRule.getAccessFlags().isPublic());
+          assertEquals(
+              1 + intValue(configurationContent.contains("@Bar")),
+              memberRule.getAnnotations().size());
+
+          ProguardTypeMatcher.MatchSpecificType fooAnnotation =
+              memberRule.getAnnotations().get(0).asSpecificTypeMatcher();
+          assertEquals("Foo", fooAnnotation.getSpecificType().toSourceString());
+
+          if (configurationContent.contains("@Bar")) {
+            ProguardTypeMatcher.MatchSpecificType barAnnotation =
+                memberRule.getAnnotations().get(1).asSpecificTypeMatcher();
+            assertEquals("Bar", barAnnotation.getSpecificType().toSourceString());
+          }
+        });
+  }
+
+  @Test
+  public void parseMethodAnnotationsAndFlags() {
+    Map<String, Optional<Class<? extends Exception>>> configurationContents =
+        ImmutableMap.<String, Optional<Class<? extends Exception>>>builder()
+            // 1 annotation without flags.
+            .put("-keep class * { @Foo Type method(); }", Optional.empty())
+            // 1 annotation with public flag.
+            .put(
+                "-keep class * { public @Foo Type method(); }", Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo public Type method(); }", Optional.empty())
+            // 1 annotation with public final flags.
+            .put(
+                "-keep class * { public final @Foo Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { public @Foo final Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo public final Type method(); }", Optional.empty())
+            //// 2 annotations without flags.
+            .put("-keep class * { @Foo @Bar Type method(); }", Optional.empty())
+            //// 2 annotations with public flag.
+            .put(
+                "-keep class * { public @Foo @Bar Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { @Foo public @Bar Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo @Bar public Type method(); }", Optional.empty())
+            //// 2 annotations with public final flags.
+            .put(
+                "-keep class * { public final @Foo @Bar Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { public @Foo final @Bar Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { public @Foo @Bar final Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { @Foo public final @Bar Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put(
+                "-keep class * { @Foo public @Bar final Type method(); }",
+                Optional.of(RuntimeException.class))
+            .put("-keep class * { @Foo @Bar public final Type method(); }", Optional.empty())
+            .build();
+    configurationContents.forEach(
+        (configurationContent, expectedExceptionClass) -> {
+          DexItemFactory dexItemFactory = new DexItemFactory();
+          ProguardConfigurationParser parser =
+              new ProguardConfigurationParser(dexItemFactory, reporter);
+          try {
+            parser.parse(createConfigurationForTesting(ImmutableList.of(configurationContent)));
+            assertFalse(expectedExceptionClass.isPresent());
+          } catch (Throwable e) {
+            assertTrue(expectedExceptionClass.isPresent());
+            assertEquals(expectedExceptionClass.get(), e.getClass());
+            reset();
+            return;
+          }
+
+          verifyParserEndsCleanly();
+
+          ProguardConfiguration configuration = parser.getConfig();
+          assertEquals(1, configuration.getRules().size());
+
+          ProguardKeepRule rule = ListUtils.first(configuration.getRules()).asProguardKeepRule();
+          assertEquals(1, rule.getMemberRules().size());
+
+          ProguardMemberRule memberRule = ListUtils.first(rule.getMemberRules());
+
+          assertEquals(
+              configurationContent.contains("final"), memberRule.getAccessFlags().isFinal());
+          assertEquals(
+              configurationContent.contains("public"), memberRule.getAccessFlags().isPublic());
+          assertEquals(
+              1 + intValue(configurationContent.contains("@Bar")),
+              memberRule.getAnnotations().size());
+
+          ProguardTypeMatcher.MatchSpecificType fooAnnotation =
+              memberRule.getAnnotations().get(0).asSpecificTypeMatcher();
+          assertEquals("Foo", fooAnnotation.getSpecificType().toSourceString());
+
+          if (configurationContent.contains("@Bar")) {
+            ProguardTypeMatcher.MatchSpecificType barAnnotation =
+                memberRule.getAnnotations().get(1).asSpecificTypeMatcher();
+            assertEquals("Bar", barAnnotation.getSpecificType().toSourceString());
+          }
+        });
+  }
 }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleClassAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleClassAnnotationsTest.java
new file mode 100644
index 0000000..80dab7c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleClassAnnotationsTest.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, 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.shaking.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleClassAnnotationsTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public KeepWithMultipleClassAnnotationsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testA() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleClassAnnotationsTest.class)
+        .addKeepRules(
+            "-keep @" + A.class.getTypeName() + " class * {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testAB() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleClassAnnotationsTest.class)
+        .addKeepRules(
+            "-keep @" + A.class.getTypeName() + " @" + B.class.getTypeName() + " class * {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testABC() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleClassAnnotationsTest.class)
+        .addKeepRules(
+            "-keep @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " @"
+                + C.class.getTypeName()
+                + " class * {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .allowUnusedProguardConfigurationRules()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+  }
+
+  @A
+  @B
+  static class TestClass {
+
+    public static void main(String[] args) {
+      System.out.println("Hello world!");
+    }
+  }
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.TYPE})
+  @interface A {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.TYPE})
+  @interface B {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.TYPE})
+  @interface C {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleInheritanceAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleInheritanceAnnotationsTest.java
new file mode 100644
index 0000000..25e610b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleInheritanceAnnotationsTest.java
@@ -0,0 +1,108 @@
+// Copyright (c) 2020, 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.shaking.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleInheritanceAnnotationsTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public KeepWithMultipleInheritanceAnnotationsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testA() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleInheritanceAnnotationsTest.class)
+        .addKeepRules(
+            "-keep class * extends @" + A.class.getTypeName() + " * {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testAB() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleInheritanceAnnotationsTest.class)
+        .addKeepRules(
+            "-keep class * extends @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " * {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testABC() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleInheritanceAnnotationsTest.class)
+        .addKeepRules(
+            "-keep class * extends @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " @"
+                + C.class.getTypeName()
+                + " * {",
+            "  public static void main(java.lang.String[]);",
+            "}")
+        .allowUnusedProguardConfigurationRules()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+  }
+
+  @A
+  @B
+  static class TestClassBase {}
+
+  static class TestClass extends TestClassBase {
+
+    public static void main(String[] args) {
+      System.out.println("Hello world!");
+    }
+  }
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.TYPE})
+  @interface A {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.TYPE})
+  @interface B {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.TYPE})
+  @interface C {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleMemberAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleMemberAnnotationsTest.java
new file mode 100644
index 0000000..cafe2a4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleMemberAnnotationsTest.java
@@ -0,0 +1,106 @@
+// Copyright (c) 2020, 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.shaking.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleMemberAnnotationsTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public KeepWithMultipleMemberAnnotationsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testA() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleMemberAnnotationsTest.class)
+        .addKeepRules(
+            "-keepclasseswithmembers class * {",
+            "  @" + A.class.getTypeName() + " public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testAB() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleMemberAnnotationsTest.class)
+        .addKeepRules(
+            "-keepclasseswithmembers class * {",
+            "  @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testABC() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleMemberAnnotationsTest.class)
+        .addKeepRules(
+            "-keepclasseswithmembers class * {",
+            "  @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " @"
+                + C.class.getTypeName()
+                + " public static void main(java.lang.String[]);",
+            "}")
+        .allowUnusedProguardConfigurationRules()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+  }
+
+  static class TestClass {
+
+    @A
+    @B
+    public static void main(String[] args) {
+      System.out.println("Hello world!");
+    }
+  }
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.METHOD})
+  @interface A {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.METHOD})
+  @interface B {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.METHOD})
+  @interface C {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleParameterAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleParameterAnnotationsTest.java
new file mode 100644
index 0000000..795574a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleParameterAnnotationsTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) 2020, 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.shaking.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleParameterAnnotationsTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public KeepWithMultipleParameterAnnotationsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testA() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleParameterAnnotationsTest.class)
+        .addKeepRules(
+            "-keepclasseswithmembers class * {",
+            "  @" + A.class.getTypeName() + " public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testAB() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleParameterAnnotationsTest.class)
+        .addKeepRules(
+            "-keepclasseswithmembers class * {",
+            "  @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " public static void main(java.lang.String[]);",
+            "}")
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  @Test
+  public void testABC() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(KeepWithMultipleParameterAnnotationsTest.class)
+        .addKeepRules(
+            "-keepclasseswithmembers class * {",
+            "  @"
+                + A.class.getTypeName()
+                + " @"
+                + B.class.getTypeName()
+                + " @"
+                + C.class.getTypeName()
+                + " public static void main(java.lang.String[]);",
+            "}")
+        .allowUnusedProguardConfigurationRules()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+  }
+
+  static class TestClass {
+
+    public static void main(@A @B String[] args) {
+      System.out.println("Hello world!");
+    }
+  }
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.PARAMETER})
+  @interface A {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.PARAMETER})
+  @interface B {}
+
+  @Retention(RetentionPolicy.CLASS)
+  @Target({ElementType.PARAMETER})
+  @interface C {}
+}