Add support for chaining ASM visitors for Keep Annotations

The KeepAnno.createClassVisitorForKeepRulesExtraction now has an
overload taking a ClassVisitor to delegate to.

Change-Id: Id432d141b984219f7656afb276d523c2ca512b72
Fixes: b/463772338
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/KeepAnno.java b/src/keepanno/java/com/android/tools/r8/keepanno/KeepAnno.java
index 392abe0..cd7a85e 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/KeepAnno.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/KeepAnno.java
@@ -19,12 +19,28 @@
    * code visited.
    *
    * <p>Each created {@code ClassVisitor} is independent and share no state (except for the {@code
-   * consumer} if the same is used for creating multiple {@code ClassVisitors}) and they can be used
-   * concurrently visiting different classes. If the same {@code consumer} is used for creating
+   * consumer}. If the same is used for creating multiple {@code ClassVisitors}) and they can be
+   * used concurrently visiting different classes. If the same {@code consumer} is used for creating
    * multiple {@code ClassVisitors}, it must be thread safe.
    */
   public static ClassVisitor createClassVisitorForKeepRulesExtraction(Consumer<String> consumer) {
+    return createClassVisitorForKeepRulesExtraction(consumer, null);
+  }
+
+  /**
+   * Experimental API to extract keep rules from keep annotations.
+   *
+   * <p>Create a {@code ClassVisitor} to extract keep rules from keep annotations present in the
+   * code visited.
+   *
+   * <p>Each created {@code ClassVisitor} is independent and share no state (except for the {@code
+   * consumer} and {@code classVisitor}). If the same is used for creating multiple {@code
+   * ClassVisitors}) and they can be used concurrently visiting different classes. If the same
+   * {@code consumer} is used for creating multiple {@code ClassVisitors}, it must be thread safe.
+   */
+  public static ClassVisitor createClassVisitorForKeepRulesExtraction(
+      Consumer<String> consumer, ClassVisitor classVisitor) {
     KeepRuleExtractor extractor = new KeepRuleExtractor(consumer, getR8Options());
-    return KeepEdgeReader.getClassVisitor(extractor::extract);
+    return KeepEdgeReader.getClassVisitor(extractor::extract, classVisitor);
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationPatternParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationPatternParser.java
index c628528..4af9001 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationPatternParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationPatternParser.java
@@ -33,7 +33,8 @@
       AnnotationProperty property,
       String name,
       String descriptor,
-      Consumer<KeepAnnotationPattern> setValue) {
+      Consumer<KeepAnnotationPattern> setValue,
+      AnnotationVisitor annotationVisitor) {
     switch (property) {
       case PATTERN:
         AnnotationParsingContext parsingContext =
@@ -46,9 +47,10 @@
                 setValue.accept(
                     parser.isDeclared()
                         ? parser.getValue()
-                        : KeepAnnotationPattern.anyWithRuntimeRetention()));
+                        : KeepAnnotationPattern.anyWithRuntimeRetention()),
+            annotationVisitor);
       default:
-        return super.tryPropertyAnnotation(property, name, descriptor, setValue);
+        return super.tryPropertyAnnotation(property, name, descriptor, setValue, annotationVisitor);
     }
   }
 
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationVisitorBase.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationVisitorBase.java
index 87e9e42..08f5a00 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationVisitorBase.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/AnnotationVisitorBase.java
@@ -12,8 +12,8 @@
 
   private final ParsingContext parsingContext;
 
-  AnnotationVisitorBase(ParsingContext parsingContext) {
-    super(KeepEdgeReader.ASM_VERSION);
+  AnnotationVisitorBase(ParsingContext parsingContext, AnnotationVisitor annotationVisitor) {
+    super(KeepEdgeReader.ASM_VERSION, annotationVisitor);
     this.parsingContext = parsingContext;
   }
 
@@ -27,11 +27,19 @@
 
   @Override
   public void visit(String name, Object value) {
+    super.visit(name, value);
+  }
+
+  protected void unhandledValue(String name, Object value) {
     throw parsingContext.error("Unexpected value for property " + name + " with value " + value);
   }
 
   @Override
   public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+    return super.visitAnnotation(name, descriptor);
+  }
+
+  protected AnnotationVisitor unhandledAnnotation(String name, String descriptor) {
     throw parsingContext.error(
         "Unexpected annotation for property "
             + name
@@ -41,6 +49,10 @@
 
   @Override
   public void visitEnum(String name, String descriptor, String value) {
+    super.visitEnum(name, descriptor, value);
+  }
+
+  protected void unhandledEnum(String name, String descriptor, String value) {
     throw parsingContext.error(
         "Unexpected enum for property "
             + name
@@ -52,6 +64,10 @@
 
   @Override
   public AnnotationVisitor visitArray(String name) {
+    return super.visitArray(name);
+  }
+
+  protected AnnotationVisitor unhandledArray(String name) {
     throw parsingContext.error("Unexpected array for property " + name);
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ArrayPropertyParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ArrayPropertyParser.java
index 3ae1bd2..55a6c34 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ArrayPropertyParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ArrayPropertyParser.java
@@ -23,12 +23,13 @@
   }
 
   @Override
-  AnnotationVisitor tryPropertyArray(P property, String name, Consumer<List<T>> setValue) {
+  AnnotationVisitor tryPropertyArray(
+      P property, String name, Consumer<List<T>> setValue, AnnotationVisitor annotationVisitor) {
     // The property name and type is forwarded to the element parser.
     values = new ArrayList<>();
     // The context is explicitly *not* extended with the property name here as it is forwarded.
     ParsingContext parsingContext = getParsingContext();
-    return new AnnotationVisitorBase(parsingContext) {
+    return new AnnotationVisitorBase(parsingContext, annotationVisitor) {
 
       private PropertyParser<T, P> getParser() {
         PropertyParser<T, P> parser = elementParser.apply(parsingContext);
@@ -43,34 +44,39 @@
 
       @Override
       public void visit(String unusedName, Object value) {
+        super.visit(unusedName, value);
         if (!getParser().tryParse(name, value, values::add)) {
-          super.visit(name, value);
+          unhandledValue(unusedName, value);
         }
       }
 
       @Override
       public AnnotationVisitor visitAnnotation(String unusedName, String descriptor) {
-        AnnotationVisitor visitor = getParser().tryParseAnnotation(name, descriptor, values::add);
+        AnnotationVisitor annotationVisitor = super.visitAnnotation(unusedName, descriptor);
+        AnnotationVisitor visitor =
+            getParser().tryParseAnnotation(name, descriptor, values::add, annotationVisitor);
         if (visitor != null) {
           return visitor;
         }
-        return super.visitAnnotation(name, descriptor);
+        return annotationVisitor;
       }
 
       @Override
       public void visitEnum(String unusedName, String descriptor, String value) {
+        super.visitEnum(unusedName, descriptor, value);
         if (!getParser().tryParseEnum(name, descriptor, value, values::add)) {
-          super.visitEnum(name, descriptor, value);
+          unhandledEnum(unusedName, descriptor, value);
         }
       }
 
       @Override
       public AnnotationVisitor visitArray(String unusedName) {
-        AnnotationVisitor visitor = getParser().tryParseArray(name, values::add);
+        AnnotationVisitor annotationVisitor = super.visitArray(unusedName);
+        AnnotationVisitor visitor = getParser().tryParseArray(name, values::add, annotationVisitor);
         if (visitor != null) {
           return visitor;
         }
-        return super.visitArray(name);
+        return annotationVisitor;
       }
     };
   }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
index 81d3598..abd1ae6 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
@@ -80,7 +80,8 @@
       ClassNameProperty property,
       String name,
       String descriptor,
-      Consumer<KeepQualifiedClassNamePattern> setValue) {
+      Consumer<KeepQualifiedClassNamePattern> setValue,
+      AnnotationVisitor annotationVisitor) {
     switch (property) {
       case PATTERN:
         {
@@ -121,7 +122,8 @@
                             unqualifiedNameParser.getValueOrDefault(
                                 KeepUnqualfiedClassNamePattern.any()))
                         .build());
-              });
+              },
+              annotationVisitor);
         }
       default:
         return null;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassUnqualifiedNameParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassUnqualifiedNameParser.java
index 896fea9..695c15c 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassUnqualifiedNameParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassUnqualifiedNameParser.java
@@ -50,7 +50,8 @@
       ClassUnqualifiedNameProperty property,
       String name,
       String descriptor,
-      Consumer<KeepUnqualfiedClassNamePattern> setValue) {
+      Consumer<KeepUnqualfiedClassNamePattern> setValue,
+      AnnotationVisitor annotationVisitor) {
     switch (property) {
       case PATTERN:
         return parser.tryPropertyAnnotation(
@@ -58,9 +59,10 @@
             name,
             descriptor,
             stringPattern ->
-                setValue.accept(KeepUnqualfiedClassNamePattern.fromStringPattern(stringPattern)));
+                setValue.accept(KeepUnqualfiedClassNamePattern.fromStringPattern(stringPattern)),
+            annotationVisitor);
       default:
-        return super.tryPropertyAnnotation(property, name, descriptor, setValue);
+        return super.tryPropertyAnnotation(property, name, descriptor, setValue, annotationVisitor);
     }
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintPropertiesParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintPropertiesParser.java
index c652e91..3d9c495 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintPropertiesParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintPropertiesParser.java
@@ -25,15 +25,19 @@
 
   @Override
   AnnotationVisitor tryPropertyArray(
-      ConstraintsProperty property, String name, Consumer<KeepConstraints> setValue) {
+      ConstraintsProperty property,
+      String name,
+      Consumer<KeepConstraints> setValue,
+      AnnotationVisitor annotationVisitor) {
     ParsingContext parsingContext = getParsingContext().property(name);
     switch (property) {
       case ADDITIONS:
         return new KeepConstraintsVisitor(
             parsingContext,
-            constraints -> setValue.accept(KeepConstraints.defaultAdditions(constraints)));
+            constraints -> setValue.accept(KeepConstraints.defaultAdditions(constraints)),
+            annotationVisitor);
       case CONSTRAINTS:
-        return new KeepConstraintsVisitor(parsingContext, setValue::accept);
+        return new KeepConstraintsVisitor(parsingContext, setValue::accept, annotationVisitor);
       default:
         return null;
     }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConvertingPropertyParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConvertingPropertyParser.java
index e449c88..cb6f364 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConvertingPropertyParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConvertingPropertyParser.java
@@ -55,13 +55,14 @@
   }
 
   @Override
-  public AnnotationVisitor tryParseArray(String name, Consumer<T2> setValue) {
-    return parser.tryParseArray(name, wrap(setValue));
+  public AnnotationVisitor tryParseArray(
+      String name, Consumer<T2> setValue, AnnotationVisitor annotationVisitor) {
+    return parser.tryParseArray(name, wrap(setValue), annotationVisitor);
   }
 
   @Override
   public AnnotationVisitor tryParseAnnotation(
-      String name, String descriptor, Consumer<T2> setValue) {
-    return parser.tryParseAnnotation(name, descriptor, wrap(setValue));
+      String name, String descriptor, Consumer<T2> setValue, AnnotationVisitor annotationVisitor) {
+    return parser.tryParseAnnotation(name, descriptor, wrap(setValue), annotationVisitor);
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/DeclarationParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/DeclarationParser.java
index cc9a74d..05e65e1 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/DeclarationParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/DeclarationParser.java
@@ -36,14 +36,15 @@
   }
 
   @Override
-  public AnnotationVisitor tryParseArray(String name, Consumer<T> setValue) {
-    return tryParseArray(name);
+  public AnnotationVisitor tryParseArray(
+      String name, Consumer<T> setValue, AnnotationVisitor annotationVisitor) {
+    return tryParseArray(name, annotationVisitor);
   }
 
   @Override
   public AnnotationVisitor tryParseAnnotation(
-      String name, String descriptor, Consumer<T> setValue) {
-    return tryParseAnnotation(name, descriptor);
+      String name, String descriptor, Consumer<T> setValue, AnnotationVisitor annotationVisitor) {
+    return tryParseAnnotation(name, descriptor, annotationVisitor);
   }
 
   public boolean tryParse(String name, Object value) {
@@ -64,23 +65,25 @@
     return false;
   }
 
-  public AnnotationVisitor tryParseArray(String name) {
+  public AnnotationVisitor tryParseArray(String name, AnnotationVisitor annotationVisitor) {
     for (Parser<?> parser : parsers()) {
-      AnnotationVisitor visitor = parser.tryParseArray(name, this::ignore);
+      AnnotationVisitor visitor = parser.tryParseArray(name, this::ignore, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
     }
-    return null;
+    return annotationVisitor;
   }
 
-  public AnnotationVisitor tryParseAnnotation(String name, String descriptor) {
+  public AnnotationVisitor tryParseAnnotation(
+      String name, String descriptor, AnnotationVisitor annotationVisitor) {
     for (Parser<?> parser : parsers()) {
-      AnnotationVisitor visitor = parser.tryParseAnnotation(name, descriptor, this::ignore);
+      AnnotationVisitor visitor =
+          parser.tryParseAnnotation(name, descriptor, this::ignore, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
     }
-    return null;
+    return annotationVisitor;
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/InstanceOfParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/InstanceOfParser.java
index 73b4905..7f2308b 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/InstanceOfParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/InstanceOfParser.java
@@ -77,7 +77,8 @@
       InstanceOfProperties property,
       String name,
       String descriptor,
-      Consumer<KeepInstanceOfPattern> setValue) {
+      Consumer<KeepInstanceOfPattern> setValue,
+      AnnotationVisitor annotationVisitor) {
     if (property.equals(InstanceOfProperties.PATTERN)) {
       AnnotationParsingContext parsingContext =
           getParsingContext().property(name).annotation(descriptor);
@@ -94,8 +95,9 @@
                       .setInclusive(inclusiveParser.getValueOrDefault(true))
                       .classPattern(
                           classNameParser.getValueOrDefault(KeepQualifiedClassNamePattern.any()))
-                      .build()));
+                      .build()),
+          annotationVisitor);
     }
-    return super.tryPropertyAnnotation(property, name, descriptor, setValue);
+    return super.tryPropertyAnnotation(property, name, descriptor, setValue, annotationVisitor);
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepConstraintsVisitor.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepConstraintsVisitor.java
index 1df490b..79cf8a8 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepConstraintsVisitor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepConstraintsVisitor.java
@@ -10,21 +10,27 @@
 import com.android.tools.r8.keepanno.ast.KeepConstraint;
 import com.android.tools.r8.keepanno.ast.KeepConstraints;
 import com.android.tools.r8.keepanno.ast.ParsingContext;
+import org.objectweb.asm.AnnotationVisitor;
 
 public class KeepConstraintsVisitor extends AnnotationVisitorBase {
 
   private final Parent<KeepConstraints> parent;
   private final KeepConstraints.Builder builder = KeepConstraints.builder();
 
-  public KeepConstraintsVisitor(ParsingContext parsingContext, Parent<KeepConstraints> parent) {
-    super(parsingContext);
+  public KeepConstraintsVisitor(
+      ParsingContext parsingContext,
+      Parent<KeepConstraints> parent,
+      AnnotationVisitor annotationVisitor) {
+    super(parsingContext, annotationVisitor);
     this.parent = parent;
   }
 
   @Override
   public void visitEnum(String ignore, String descriptor, String value) {
+    super.visitEnum(ignore, descriptor, value);
     if (!AnnotationConstants.Constraints.isDescriptor(descriptor)) {
-      super.visitEnum(ignore, descriptor, value);
+      unhandledEnum(ignore, descriptor, value);
+      return;
     }
     switch (value) {
       case Constraints.LOOKUP:
@@ -71,7 +77,7 @@
         builder.add(KeepConstraint.genericSignature());
         break;
       default:
-        super.visitEnum(ignore, descriptor, value);
+        unhandledEnum(ignore, descriptor, value);
     }
   }
 
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
index edb9cb4..6a4d08c 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
@@ -154,8 +154,9 @@
     return internalReadKeepEdges(classFileBytes, true);
   }
 
-  public static ClassVisitor getClassVisitor(Parent<KeepDeclaration> consumer) {
-    return new KeepEdgeClassVisitor(true, consumer);
+  public static ClassVisitor getClassVisitor(
+      Parent<KeepDeclaration> consumer, ClassVisitor classVisitor) {
+    return new KeepEdgeClassVisitor(true, consumer, classVisitor);
   }
 
   private static List<KeepDeclaration> internalReadKeepEdges(
@@ -183,7 +184,8 @@
         builder -> {
           builder.setContextFromClassDescriptor(
               KeepEdgeReaderUtils.getDescriptorFromClassTypeName(className));
-        });
+        },
+        null);
   }
 
   public static AnnotationVisitor createFieldKeepAnnotationVisitor(
@@ -209,7 +211,8 @@
               KeepEdgeReaderUtils.getDescriptorFromClassTypeName(className),
               fieldName,
               fieldTypeDescriptor);
-        });
+        },
+        null);
   }
 
   public static AnnotationVisitor createMethodKeepAnnotationVisitor(
@@ -235,7 +238,8 @@
               KeepEdgeReaderUtils.getDescriptorFromClassTypeName(className),
               methodName,
               methodDescriptor);
-        });
+        },
+        null);
   }
 
   private static KeepClassBindingReference classReferenceFromName(
@@ -331,7 +335,12 @@
     private ClassParsingContext parsingContext;
 
     public KeepEdgeClassVisitor(boolean readEmbedded, Parent<KeepDeclaration> parent) {
-      super(ASM_VERSION);
+      this(readEmbedded, parent, null);
+    }
+
+    public KeepEdgeClassVisitor(
+        boolean readEmbedded, Parent<KeepDeclaration> parent, ClassVisitor classVisitor) {
+      super(ASM_VERSION, classVisitor);
       this.readEmbedded = readEmbedded;
       this.parent = parent;
     }
@@ -359,6 +368,7 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(descriptor, visible);
       return createAnnotationVisitor(
           descriptor,
           visible,
@@ -366,27 +376,29 @@
           parent::accept,
           annotationParsingContext(descriptor),
           className,
-          this::setContext);
+          this::setContext,
+          annotationVisitor);
     }
 
-    private static AnnotationVisitorBase createAnnotationVisitor(
+    private static AnnotationVisitor createAnnotationVisitor(
         String descriptor,
         boolean visible,
         boolean readEmbedded,
         Consumer<KeepDeclaration> parent,
         AnnotationParsingContext parsingContext,
         String className,
-        Consumer<KeepEdgeMetaInfo.Builder> setContext) {
+        Consumer<KeepEdgeMetaInfo.Builder> setContext,
+        AnnotationVisitor annotationVisitor) {
       // Skip any visible annotations as keep annotations are not runtime visible.
       if (visible) {
-        return null;
+        return annotationVisitor;
       }
 
       if (!readEmbedded || !isEmbeddedAnnotation(descriptor)) {
-        return null;
+        return annotationVisitor;
       }
       if (Edge.isDescriptor(descriptor)) {
-        return new KeepEdgeVisitor(parsingContext, parent::accept, setContext);
+        return new KeepEdgeVisitor(parsingContext, parent::accept, setContext, annotationVisitor);
       }
       if (AnnotationConstants.UsesReflection.isDescriptor(descriptor)) {
         return new UsesReflectionVisitor(
@@ -396,7 +408,8 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToConstruct.isDescriptor(descriptor)) {
         return new UsesReflectionToConstructVisitor(
@@ -406,7 +419,8 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToConstruct.isKotlinRepeatableContainerDescriptor(
           descriptor)) {
@@ -417,7 +431,8 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessMethod.isDescriptor(descriptor)) {
         return new UsesReflectionToAccessMethodVisitor(
@@ -427,7 +442,8 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessMethod.isKotlinRepeatableContainerDescriptor(
           descriptor)) {
@@ -438,7 +454,8 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessField.isDescriptor(descriptor)) {
         return new UsesReflectionToAccessFieldVisitor(
@@ -448,7 +465,8 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessField.isKotlinRepeatableContainerDescriptor(
           descriptor)) {
@@ -459,29 +477,41 @@
             bindingsHelper ->
                 KeepClassItemPattern.builder()
                     .setClassNamePattern(KeepQualifiedClassNamePattern.exact(className))
-                    .build());
+                    .build(),
+            annotationVisitor);
       }
       if (AnnotationConstants.UnconditionallyKeep.isDescriptor(descriptor)) {
         return new UnconditionallyKeepClassVisitor(
-            parsingContext, parent::accept, setContext, className);
+            parsingContext, parent::accept, setContext, className, annotationVisitor);
       }
       if (ForApi.isDescriptor(descriptor)) {
-        return new ForApiClassVisitor(parsingContext, parent::accept, setContext, className);
+        return new ForApiClassVisitor(
+            parsingContext, parent::accept, setContext, className, annotationVisitor);
       }
       if (UsedByReflection.isDescriptor(descriptor)
           || AnnotationConstants.UsedByNative.isDescriptor(descriptor)) {
         return new UsedByReflectionClassVisitor(
-            parsingContext, parent::accept, setContext, className);
+            parsingContext, parent::accept, setContext, className, annotationVisitor);
       }
       if (AnnotationConstants.CheckRemoved.isDescriptor(descriptor)) {
         return new CheckRemovedClassVisitor(
-            parsingContext, parent::accept, setContext, className, KeepCheckKind.REMOVED);
+            parsingContext,
+            parent::accept,
+            setContext,
+            className,
+            KeepCheckKind.REMOVED,
+            annotationVisitor);
       }
       if (AnnotationConstants.CheckOptimizedOut.isDescriptor(descriptor)) {
         return new CheckRemovedClassVisitor(
-            parsingContext, parent::accept, setContext, className, KeepCheckKind.OPTIMIZED_OUT);
+            parsingContext,
+            parent::accept,
+            setContext,
+            className,
+            KeepCheckKind.OPTIMIZED_OUT,
+            annotationVisitor);
       }
-      return null;
+      return annotationVisitor;
     }
 
     private void setContext(KeepEdgeMetaInfo.Builder builder) {
@@ -492,21 +522,24 @@
     @Override
     public MethodVisitor visitMethod(
         int access, String name, String descriptor, String signature, String[] exceptions) {
+      MethodVisitor methodVisitor =
+          super.visitMethod(access, name, descriptor, signature, exceptions);
       if (readEmbedded) {
         return new KeepEdgeMethodVisitor(
-            parsingContext, parent::accept, className, name, descriptor);
+            parsingContext, parent::accept, className, name, descriptor, methodVisitor);
       }
-      return null;
+      return methodVisitor;
     }
 
     @Override
     public FieldVisitor visitField(
         int access, String name, String descriptor, String signature, Object value) {
+      FieldVisitor fieldVisitor = super.visitField(access, name, descriptor, signature, value);
       if (readEmbedded) {
         return new KeepEdgeFieldVisitor(
-            parsingContext, parent::accept, className, name, descriptor);
+            parsingContext, parent::accept, className, name, descriptor, fieldVisitor);
       }
-      return null;
+      return fieldVisitor;
     }
   }
 
@@ -522,8 +555,9 @@
         Parent<KeepDeclaration> parent,
         String className,
         String methodName,
-        String methodDescriptor) {
-      super(ASM_VERSION);
+        String methodDescriptor,
+        MethodVisitor methodVisitor) {
+      super(ASM_VERSION, methodVisitor);
       this.parent = parent;
       this.className = className;
       this.methodName = methodName;
@@ -566,6 +600,7 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(descriptor, visible);
       return createAnnotationVisitor(
           descriptor,
           visible,
@@ -575,7 +610,8 @@
           className,
           methodName,
           methodDescriptor,
-          this::setContext);
+          this::setContext,
+          annotationVisitor);
     }
 
     public static AnnotationVisitor createAnnotationVisitor(
@@ -587,17 +623,18 @@
         String className,
         String methodName,
         String methodDescriptor,
-        Consumer<KeepEdgeMetaInfo.Builder> setContext) {
+        Consumer<KeepEdgeMetaInfo.Builder> setContext,
+        AnnotationVisitor annotationVisitor) {
       // Skip any visible annotations as @KeepEdge is not runtime visible.
       if (visible) {
-        return null;
+        return annotationVisitor;
       }
       if (!readEmbedded) {
         // Only the embedded annotations can be on methods.
-        return null;
+        return annotationVisitor;
       }
       if (Edge.isDescriptor(descriptor)) {
-        return new KeepEdgeVisitor(parsingContext, parent::accept, setContext);
+        return new KeepEdgeVisitor(parsingContext, parent::accept, setContext, annotationVisitor);
       }
       if (AnnotationConstants.UsesReflection.isDescriptor(descriptor)) {
         return new UsesReflectionVisitor(
@@ -605,7 +642,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToConstruct.isDescriptor(descriptor)) {
         return new UsesReflectionToConstructVisitor(
@@ -613,7 +651,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToConstruct.isKotlinRepeatableContainerDescriptor(
           descriptor)) {
@@ -622,7 +661,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessMethod.isDescriptor(descriptor)) {
         return new UsesReflectionToAccessMethodVisitor(
@@ -630,7 +670,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessMethod.isKotlinRepeatableContainerDescriptor(
           descriptor)) {
@@ -639,7 +680,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessField.isDescriptor(descriptor)) {
         return new UsesReflectionToAccessFieldVisitor(
@@ -647,7 +689,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsesReflectionToAccessField.isKotlinRepeatableContainerDescriptor(
           descriptor)) {
@@ -656,7 +699,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UnconditionallyKeep.isDescriptor(descriptor)) {
         return new UnconditionallyKeepMemberVisitor(
@@ -664,7 +708,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.ForApi.isDescriptor(descriptor)) {
         return new ForApiMemberVisitor(
@@ -672,7 +717,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UsedByReflection.isDescriptor(descriptor)
           || AnnotationConstants.UsedByNative.isDescriptor(descriptor)) {
@@ -681,7 +727,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper));
+                createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.CheckRemoved.isDescriptor(descriptor)) {
         return new CheckRemovedMemberVisitor(
@@ -690,7 +737,8 @@
             setContext,
             bindingsHelper ->
                 createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
-            KeepCheckKind.REMOVED);
+            KeepCheckKind.REMOVED,
+            annotationVisitor);
       }
       if (AnnotationConstants.CheckOptimizedOut.isDescriptor(descriptor)) {
         return new CheckRemovedMemberVisitor(
@@ -699,9 +747,10 @@
             setContext,
             bindingsHelper ->
                 createMethodItemContext(className, methodName, methodDescriptor, bindingsHelper),
-            KeepCheckKind.OPTIMIZED_OUT);
+            KeepCheckKind.OPTIMIZED_OUT,
+            annotationVisitor);
       }
-      return null;
+      return annotationVisitor;
     }
 
     private void setContext(KeepEdgeMetaInfo.Builder builder) {
@@ -722,8 +771,9 @@
         Parent<KeepEdge> parent,
         String className,
         String fieldName,
-        String fieldTypeDescriptor) {
-      super(ASM_VERSION);
+        String fieldTypeDescriptor,
+        FieldVisitor fieldVisitor) {
+      super(ASM_VERSION, fieldVisitor);
       this.parent = parent;
       this.className = className;
       this.fieldName = fieldName;
@@ -760,6 +810,7 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(descriptor, visible);
       return createAnnotationVisitor(
           descriptor,
           visible,
@@ -769,7 +820,8 @@
           className,
           fieldName,
           fieldTypeDescriptor,
-          this::setContext);
+          this::setContext,
+          annotationVisitor);
     }
 
     public static AnnotationVisitor createAnnotationVisitor(
@@ -781,17 +833,18 @@
         String className,
         String fieldName,
         String fieldTypeDescriptor,
-        Consumer<KeepEdgeMetaInfo.Builder> setContext) {
+        Consumer<KeepEdgeMetaInfo.Builder> setContext,
+        AnnotationVisitor annotationVisitor) {
       // Skip any visible annotations as @KeepEdge is not runtime visible.
       if (visible) {
-        return null;
+        return annotationVisitor;
       }
       if (!readEmbedded) {
         // Only the embedded annotations can be on fields.
-        return null;
+        return annotationVisitor;
       }
       if (Edge.isDescriptor(descriptor)) {
-        return new KeepEdgeVisitor(parsingContext, parent::accept, setContext);
+        return new KeepEdgeVisitor(parsingContext, parent::accept, setContext, annotationVisitor);
       }
       if (AnnotationConstants.UsesReflection.isDescriptor(descriptor)) {
         return new UsesReflectionVisitor(
@@ -799,7 +852,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper));
+                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (AnnotationConstants.UnconditionallyKeep.isDescriptor(descriptor)) {
         return new UnconditionallyKeepMemberVisitor(
@@ -807,7 +861,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper));
+                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (ForApi.isDescriptor(descriptor)) {
         return new ForApiMemberVisitor(
@@ -815,7 +870,8 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper));
+                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper),
+            annotationVisitor);
       }
       if (UsedByReflection.isDescriptor(descriptor)
           || AnnotationConstants.UsedByNative.isDescriptor(descriptor)) {
@@ -824,9 +880,10 @@
             parent::accept,
             setContext,
             bindingsHelper ->
-                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper));
+                createMemberItemContext(className, fieldName, fieldTypeDescriptor, bindingsHelper),
+            annotationVisitor);
       }
-      return null;
+      return annotationVisitor;
     }
   }
 
@@ -926,8 +983,9 @@
     KeepEdgeVisitor(
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
-        Consumer<KeepEdgeMetaInfo.Builder> addContext) {
-      super(parsingContext);
+        Consumer<KeepEdgeMetaInfo.Builder> addContext,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       addContext.accept(metaInfoBuilder);
@@ -935,28 +993,28 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       PropertyParsingContext propertyParsingContext = parsingContext.property(name);
       if (name.equals(Edge.bindings)) {
-        return new KeepBindingsVisitor(propertyParsingContext, bindingsHelper);
+        return new KeepBindingsVisitor(propertyParsingContext, bindingsHelper, annotationVisitor);
       }
       if (name.equals(Edge.preconditions)) {
         return new KeepPreconditionsVisitor(
-            propertyParsingContext, builder::setPreconditions, bindingsHelper);
+            propertyParsingContext, builder::setPreconditions, bindingsHelper, annotationVisitor);
       }
       if (name.equals(Edge.consequences)) {
         return new KeepConsequencesVisitor(
-            propertyParsingContext, builder::setConsequences, bindingsHelper);
+            propertyParsingContext, builder::setConsequences, bindingsHelper, annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -987,8 +1045,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        String className) {
-      super(parsingContext);
+        String className,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.className = className;
       this.parent = parent;
@@ -1006,24 +1065,25 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       if (name.equals(ForApi.additionalTargets)) {
         return new KeepConsequencesVisitor(
             parsingContext.property(name),
             additionalConsequences -> {
               additionalConsequences.forEachTarget(consequences::addTarget);
             },
-            bindingsHelper);
+            bindingsHelper,
+            annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1117,8 +1177,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       addContext.accept(metaInfoBuilder);
@@ -1133,24 +1194,29 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
+      } else {
+        unhandledValue(name, value);
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       if (name.equals(ForApi.additionalTargets)) {
         return new KeepConsequencesVisitor(
             parsingContext.property(name),
             additionalConsequences -> {
               additionalConsequences.forEachTarget(consequences::addTarget);
             },
-            bindingsHelper);
+            bindingsHelper,
+            annotationVisitor);
+      } else {
+        unhandledArray(name);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1161,6 +1227,7 @@
               .setBindings(bindingsHelper.build())
               .setConsequences(consequences.build())
               .build());
+      super.visitEnd();
     }
   }
 
@@ -1244,8 +1311,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        String className) {
-      super(parsingContext);
+        String className,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.className = className;
       this.parent = parent;
@@ -1262,19 +1330,19 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       PropertyParsingContext propertyParsingContext = parsingContext.property(name);
       if (name.equals(Edge.preconditions)) {
         return new KeepPreconditionsVisitor(
-            propertyParsingContext, builder::setPreconditions, bindingsHelper);
+            propertyParsingContext, builder::setPreconditions, bindingsHelper, annotationVisitor);
       }
       if (name.equals(UsedByReflection.additionalTargets)) {
         return new KeepConsequencesVisitor(
@@ -1282,13 +1350,15 @@
             additionalConsequences -> {
               additionalConsequences.forEachTarget(consequences::addTarget);
             },
-            bindingsHelper);
+            bindingsHelper,
+            annotationVisitor);
       }
-      AnnotationVisitor visitor = constraintsParser.tryParseArray(name, unused -> {});
+      AnnotationVisitor visitor =
+          constraintsParser.tryParseArray(name, unused -> {}, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1361,8 +1431,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.context = contextBuilder.apply(bindingsHelper);
@@ -1372,32 +1443,34 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public void visitEnum(String name, String descriptor, String value) {
+      super.visitEnum(name, descriptor, value);
       if (!Kind.isDescriptor(descriptor)) {
-        super.visitEnum(name, descriptor, value);
+        unhandledEnum(name, descriptor, value);
+        return;
       }
       KeepEdgeReader.ItemKind kind = KeepEdgeReader.ItemKind.fromString(value);
       if (kind != null) {
         this.kind = kind;
       } else {
-        super.visitEnum(name, descriptor, value);
+        unhandledEnum(name, descriptor, value);
       }
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       PropertyParsingContext propertyParsingContext = parsingContext.property(name);
       if (name.equals(Edge.preconditions)) {
         return new KeepPreconditionsVisitor(
-            propertyParsingContext, builder::setPreconditions, bindingsHelper);
+            propertyParsingContext, builder::setPreconditions, bindingsHelper, annotationVisitor);
       }
       if (name.equals(UsedByReflection.additionalTargets)) {
         return new KeepConsequencesVisitor(
@@ -1405,13 +1478,15 @@
             additionalConsequences -> {
               additionalConsequences.forEachTarget(consequences::addTarget);
             },
-            bindingsHelper);
+            bindingsHelper,
+            annotationVisitor);
       }
-      AnnotationVisitor visitor = constraintsParser.tryParseArray(name, unused -> {});
+      AnnotationVisitor visitor =
+          constraintsParser.tryParseArray(name, unused -> {}, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1439,6 +1514,7 @@
               .setBindings(bindingsHelper.build())
               .setConsequences(consequences.build())
               .build());
+      super.visitEnd();
     }
 
     private void validateConsistentKind(KeepMemberPattern memberPattern) {
@@ -1467,8 +1543,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       KeepItemPattern context = contextBuilder.apply(bindingsHelper);
@@ -1482,17 +1559,17 @@
     public void visit(String name, Object value) {
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
       super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       PropertyParsingContext propertyParsingContext = parsingContext.property(name);
       if (name.equals(AnnotationConstants.UsesReflection.value)) {
         return new KeepConsequencesVisitor(
-            propertyParsingContext, builder::setConsequences, bindingsHelper);
+            propertyParsingContext, builder::setConsequences, bindingsHelper, annotationVisitor);
       }
       if (name.equals(AnnotationConstants.UsesReflection.additionalPreconditions)) {
         return new KeepPreconditionsVisitor(
@@ -1500,9 +1577,10 @@
             additionalPreconditions -> {
               additionalPreconditions.forEach(preconditions::addCondition);
             },
-            bindingsHelper);
+            bindingsHelper,
+            annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1513,6 +1591,7 @@
               .setBindings(bindingsHelper.build())
               .setPreconditions(preconditions.build())
               .build());
+      super.visitEnd();
     }
   }
 
@@ -1523,8 +1602,10 @@
         KeepMethodParametersPattern.builder();
 
     public ParametersClassVisitor(
-        PropertyParsingContext parsingContext, Consumer<KeepMethodParametersPattern> consumer) {
-      super(parsingContext);
+        PropertyParsingContext parsingContext,
+        Consumer<KeepMethodParametersPattern> consumer,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.consumer = consumer;
     }
@@ -1537,14 +1618,14 @@
       } else if (value instanceof Type) {
         builder.addParameterTypePattern(
             KeepTypePattern.fromDescriptor(((Type) value).getDescriptor()));
-      } else {
-        super.visit(name, value);
       }
+      super.visit(name, value);
     }
 
     @Override
     public void visitEnd() {
       consumer.accept(builder.build());
+      super.visitEnd();
     }
   }
 
@@ -1555,8 +1636,10 @@
         KeepMethodParametersPattern.builder();
 
     public ParametersClassNamesVisitor(
-        PropertyParsingContext parsingContext, Consumer<KeepMethodParametersPattern> consumer) {
-      super(parsingContext);
+        PropertyParsingContext parsingContext,
+        Consumer<KeepMethodParametersPattern> consumer,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.consumer = consumer;
     }
@@ -1568,14 +1651,14 @@
         builder.addParameterTypePattern(
             KeepTypePattern.fromDescriptor(
                 DescriptorUtils.javaTypeToDescriptor(kotlinTypeToJavaType((String) value))));
-      } else {
-        super.visit(name, value);
       }
+      super.visit(name, value);
     }
 
     @Override
     public void visitEnd() {
       consumer.accept(builder.build());
+      super.visitEnd();
     }
   }
 
@@ -1590,8 +1673,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.addContext = addContext;
@@ -1600,11 +1684,12 @@
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       if (name.equals("value")) {
         return new UsesReflectionForInstantiationsVisitor(
-            parsingContext, parent, addContext, contextBuilder);
+            parsingContext, parent, addContext, contextBuilder, annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1623,8 +1708,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.addContext = addContext;
@@ -1633,12 +1719,13 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
       assert name == null;
       if (AnnotationConstants.UsesReflectionToConstruct.isDescriptor(descriptor)) {
         return new UsesReflectionToConstructVisitor(
-            parsingContext, parent, addContext, contextBuilder);
+            parsingContext, parent, addContext, contextBuilder, annotationVisitor);
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
   }
 
@@ -1653,8 +1740,9 @@
     protected KeepQualifiedClassNamePattern qualifiedName;
     protected boolean includeSubclasses = false;
 
-    UsesReflectionToXXXVisitor(AnnotationParsingContext parsingContext) {
-      super(parsingContext);
+    UsesReflectionToXXXVisitor(
+        AnnotationParsingContext parsingContext, AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       assert UsesReflectionToXXXClassConstant.equals(UsesReflectionToConstruct.classConstant);
       assert UsesReflectionToXXXClassConstant.equals(UsesReflectionToAccessMethod.classConstant);
@@ -1720,8 +1808,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       KeepItemPattern context = contextBuilder.apply(bindingsHelper);
       KeepBindingReference contextBinding =
@@ -1732,27 +1821,28 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (maybeVisitQualifiedName(name, value)) {
         return;
       }
       if (maybeVisitIncludeSubclasses(name, value)) {
         return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       PropertyParsingContext propertyParsingContext = parsingContext.property(name);
       if (name.equals(UsesReflectionToConstruct.parameterTypes)) {
         return new ParametersClassVisitor(
-            propertyParsingContext, parameters -> this.parameters = parameters);
+            propertyParsingContext, parameters -> this.parameters = parameters, annotationVisitor);
       }
       if (name.equals(UsesReflectionToConstruct.parameterTypeNames)) {
         return new ParametersClassNamesVisitor(
-            propertyParsingContext, parameters -> this.parameters = parameters);
+            propertyParsingContext, parameters -> this.parameters = parameters, annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1783,6 +1873,8 @@
               .setPreconditions(preconditions.build())
               .setConsequences(consequencesBuilder.build())
               .build());
+
+      super.visitEnd();
     }
   }
 
@@ -1797,8 +1889,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.addContext = addContext;
@@ -1807,11 +1900,12 @@
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       if (name.equals("value")) {
         return new UsesReflectionToAccessMethodContainerElementVisitor(
-            parsingContext, parent, addContext, contextBuilder);
+            parsingContext, parent, addContext, contextBuilder, annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1836,8 +1930,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.addContext = addContext;
@@ -1846,12 +1941,13 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
       assert name == null;
       if (AnnotationConstants.UsesReflectionToAccessMethod.isDescriptor(descriptor)) {
         return new UsesReflectionToAccessMethodVisitor(
-            parsingContext, parent, addContext, contextBuilder);
+            parsingContext, parent, addContext, contextBuilder, annotationVisitor);
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
 
     @Override
@@ -1879,8 +1975,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       KeepItemPattern context = contextBuilder.apply(bindingsHelper);
       KeepBindingReference contextBinding =
@@ -1891,6 +1988,7 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (maybeVisitQualifiedName(name, value)) {
         return;
       }
@@ -1922,21 +2020,21 @@
         }
         return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       PropertyParsingContext propertyParsingContext = parsingContext.property(name);
       if (name.equals(UsesReflectionToAccessMethod.parameterTypes)) {
         return new ParametersClassVisitor(
-            propertyParsingContext, parameters -> this.parameters = parameters);
+            propertyParsingContext, parameters -> this.parameters = parameters, annotationVisitor);
       }
       if (name.equals(UsesReflectionToAccessMethod.parameterTypeNames)) {
         return new ParametersClassNamesVisitor(
-            propertyParsingContext, parameters -> this.parameters = parameters);
+            propertyParsingContext, parameters -> this.parameters = parameters, annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -1987,6 +2085,8 @@
               .setPreconditions(preconditions.build())
               .setConsequences(consequencesBuilder.build())
               .build());
+
+      super.visitEnd();
     }
   }
 
@@ -2001,8 +2101,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.addContext = addContext;
@@ -2011,11 +2112,12 @@
 
     @Override
     public AnnotationVisitor visitArray(String name) {
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
       if (name.equals("value")) {
         return new UsesReflectionToAccessFieldContainerElementVisitor(
-            parsingContext, parent, addContext, contextBuilder);
+            parsingContext, parent, addContext, contextBuilder, annotationVisitor);
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -2040,8 +2142,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.addContext = addContext;
@@ -2050,12 +2153,13 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
       assert name == null;
       if (AnnotationConstants.UsesReflectionToAccessField.isDescriptor(descriptor)) {
         return new UsesReflectionToAccessFieldVisitor(
-            parsingContext, parent, addContext, contextBuilder);
+            parsingContext, parent, addContext, contextBuilder, annotationVisitor);
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
 
     @Override
@@ -2082,8 +2186,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       KeepItemPattern context = contextBuilder.apply(bindingsHelper);
       KeepBindingReference contextBinding =
@@ -2094,6 +2199,7 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (maybeVisitQualifiedName(name, value)) {
         return;
       }
@@ -2118,7 +2224,6 @@
                         KeepQualifiedClassNamePattern.exact((String) value))));
         return;
       }
-      super.visit(name, value);
     }
 
     @Override
@@ -2149,6 +2254,8 @@
               .setPreconditions(preconditions.build())
               .setConsequences(consequencesBuilder.build())
               .build());
+
+      super.visitEnd();
     }
   }
 
@@ -2164,8 +2271,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        String className) {
-      super(parsingContext);
+        String className,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       addContext.accept(metaInfoBuilder);
       KeepClassBindingReference kotlinMetadataBinding =
@@ -2184,6 +2292,7 @@
               .setBindings(bindingsHelper.build())
               .setConsequences(consequences.build())
               .build());
+      super.visitEnd();
     }
   }
 
@@ -2199,8 +2308,9 @@
         AnnotationParsingContext parsingContext,
         Parent<KeepEdge> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
-        Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder) {
-      super(parsingContext);
+        Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       addContext.accept(metaInfoBuilder);
       KeepMemberItemPattern context = contextBuilder.apply(bindingsHelper);
@@ -2220,6 +2330,8 @@
               .setBindings(bindingsHelper.build())
               .setConsequences(consequences.build())
               .build());
+
+      super.visitEnd();
     }
   }
 
@@ -2227,19 +2339,24 @@
     private final ParsingContext parsingContext;
     private final UserBindingsHelper helper;
 
-    public KeepBindingsVisitor(PropertyParsingContext parsingContext, UserBindingsHelper helper) {
-      super(parsingContext);
+    public KeepBindingsVisitor(
+        PropertyParsingContext parsingContext,
+        UserBindingsHelper helper,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.helper = helper;
     }
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
       assert name == null;
       if (AnnotationConstants.Binding.isDescriptor(descriptor)) {
-        return new KeepBindingVisitor(parsingContext.annotation(descriptor), helper);
+        return new KeepBindingVisitor(
+            parsingContext.annotation(descriptor), helper, annotationVisitor);
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
   }
 
@@ -2252,8 +2369,9 @@
     public KeepPreconditionsVisitor(
         PropertyParsingContext parsingContext,
         Parent<KeepPreconditions> parent,
-        UserBindingsHelper bindingsHelper) {
-      super(parsingContext);
+        UserBindingsHelper bindingsHelper,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.bindingsHelper = bindingsHelper;
@@ -2261,17 +2379,22 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
       assert name == null;
       if (Condition.isDescriptor(descriptor)) {
         return new KeepConditionVisitor(
-            parsingContext.annotation(descriptor), builder::addCondition, bindingsHelper);
+            parsingContext.annotation(descriptor),
+            builder::addCondition,
+            bindingsHelper,
+            annotationVisitor);
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
 
     @Override
     public void visitEnd() {
       parent.accept(builder.build());
+      super.visitEnd();
     }
   }
 
@@ -2284,8 +2407,9 @@
     public KeepConsequencesVisitor(
         PropertyParsingContext parsingContext,
         Parent<KeepConsequences> parent,
-        UserBindingsHelper bindingsHelper) {
-      super(parsingContext);
+        UserBindingsHelper bindingsHelper,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.bindingsHelper = bindingsHelper;
@@ -2293,17 +2417,22 @@
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
       assert name == null;
       if (Target.isDescriptor(descriptor)) {
         return KeepTargetVisitor.create(
-            parsingContext.annotation(descriptor), builder::addTarget, bindingsHelper);
+            parsingContext.annotation(descriptor),
+            builder::addTarget,
+            bindingsHelper,
+            annotationVisitor);
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
 
     @Override
     public void visitEnd() {
       parent.accept(builder.build());
+      super.visitEnd();
     }
   }
 
@@ -2321,8 +2450,9 @@
         Parent<KeepCheck> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
         String className,
-        KeepCheckKind kind) {
-      super(parsingContext);
+        KeepCheckKind kind,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.parent = parent;
       this.className = className;
@@ -2334,7 +2464,6 @@
     public void visit(String name, Object value) {
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
       super.visit(name, value);
     }
@@ -2343,7 +2472,7 @@
     public void visitEnd() {
       UserBindingsHelper bindingsHelper = new UserBindingsHelper();
       KeepItemVisitorBase itemVisitor =
-          new KeepItemVisitorBase(parsingContext) {
+          new KeepItemVisitorBase(parsingContext, null) {
             @Override
             public UserBindingsHelper getBindingsHelper() {
               return bindingsHelper;
@@ -2358,6 +2487,7 @@
               .setBindings(itemVisitor.getBindingsHelper().build())
               .setItemReference(itemVisitor.getItemReference())
               .build());
+      super.visitEnd();
     }
   }
 
@@ -2375,8 +2505,9 @@
         Parent<KeepDeclaration> parent,
         Consumer<KeepEdgeMetaInfo.Builder> addContext,
         Function<UserBindingsHelper, KeepMemberItemPattern> contextBuilder,
-        KeepCheckKind kind) {
-      super(parsingContext);
+        KeepCheckKind kind,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       this.context = bindingsHelper.defineFreshMemberBinding(contextBuilder.apply(bindingsHelper));
       this.kind = kind;
@@ -2387,15 +2518,14 @@
     public void visit(String name, Object value) {
       if (name.equals(Edge.description) && value instanceof String) {
         metaInfoBuilder.setDescription((String) value);
-        return;
       }
       super.visit(name, value);
     }
 
     @Override
     public void visitEnd() {
-      super.visitEnd();
       parent.accept(buildKeepCheckFromItem(metaInfoBuilder.build(), kind, context, bindingsHelper));
+      super.visitEnd();
     }
 
     private static KeepCheck buildKeepCheckFromItem(
@@ -2594,12 +2724,12 @@
     }
 
     @Override
-    public AnnotationVisitor tryParseArray(String name) {
+    public AnnotationVisitor tryParseArray(String name, AnnotationVisitor annotationVisitor) {
       if (name.equals(Item.methodAccess)) {
         accessBuilder = KeepMethodAccessPattern.builder();
-        return new MethodAccessVisitor(parsingContext, accessBuilder);
+        return new MethodAccessVisitor(parsingContext, accessBuilder, annotationVisitor);
       }
-      return super.tryParseArray(name);
+      return super.tryParseArray(name, annotationVisitor);
     }
   }
 
@@ -2667,12 +2797,12 @@
     }
 
     @Override
-    public AnnotationVisitor tryParseArray(String name) {
+    public AnnotationVisitor tryParseArray(String name, AnnotationVisitor annotationVisitor) {
       if (name.equals(Item.fieldAccess)) {
         accessBuilder = KeepFieldAccessPattern.builder();
-        return new FieldAccessVisitor(parsingContext, accessBuilder);
+        return new FieldAccessVisitor(parsingContext, accessBuilder, annotationVisitor);
       }
-      return super.tryParseArray(name);
+      return super.tryParseArray(name, annotationVisitor);
     }
   }
 
@@ -2739,12 +2869,12 @@
     }
 
     @Override
-    public AnnotationVisitor tryParseArray(String name) {
+    public AnnotationVisitor tryParseArray(String name, AnnotationVisitor annotationVisitor) {
       if (name.equals(Item.memberAccess)) {
         accessBuilder = KeepMemberAccessPattern.memberBuilder();
-        return new MemberAccessVisitor(parsingContext, accessBuilder);
+        return new MemberAccessVisitor(parsingContext, accessBuilder, annotationVisitor);
       }
-      return super.tryParseArray(name);
+      return super.tryParseArray(name, annotationVisitor);
     }
   }
 
@@ -2764,8 +2894,8 @@
     // Constructed bindings available once visitEnd has been called.
     private List<KeepBindingReference> itemReferences = null;
 
-    KeepItemVisitorBase(ParsingContext parsingContext) {
-      super(parsingContext);
+    KeepItemVisitorBase(ParsingContext parsingContext, AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       classDeclaration = new ClassDeclarationParser(parsingContext, this::getBindingsHelper);
       memberDeclaration = new MemberDeclarationParser(parsingContext);
@@ -2803,8 +2933,9 @@
 
     @Override
     public void visitEnum(String name, String descriptor, String value) {
+      super.visitEnum(name, descriptor, value);
       if (!AnnotationConstants.Kind.isDescriptor(descriptor)) {
-        super.visitEnum(name, descriptor, value);
+        return;
       }
       ItemKind kind = ItemKind.fromString(value);
       if (kind != null) {
@@ -2814,6 +2945,7 @@
 
     @Override
     public void visit(String name, Object value) {
+      super.visit(name, value);
       if (name.equals(Item.memberFromBinding) && value instanceof String) {
         memberBindingReference = (String) value;
         return;
@@ -2822,29 +2954,31 @@
           || memberDeclaration.tryParse(name, value)) {
         return;
       }
-      super.visit(name, value);
     }
 
     @Override
     public AnnotationVisitor visitAnnotation(String name, String descriptor) {
-      AnnotationVisitor visitor = classDeclaration.tryParseAnnotation(name, descriptor);
+      AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
+      AnnotationVisitor visitor =
+          classDeclaration.tryParseAnnotation(name, descriptor, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
-      visitor = memberDeclaration.tryParseAnnotation(name, descriptor);
+      visitor = memberDeclaration.tryParseAnnotation(name, descriptor, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
-      return super.visitAnnotation(name, descriptor);
+      return annotationVisitor;
     }
 
     @Override
     public AnnotationVisitor visitArray(String name) {
-      AnnotationVisitor visitor = memberDeclaration.tryParseArray(name);
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
+      AnnotationVisitor visitor = memberDeclaration.tryParseArray(name, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     private void visitEndWithMemberBindingReference() {
@@ -2881,6 +3015,8 @@
 
     @Override
     public void visitEnd() {
+      super.visitEnd();
+
       // Item defined by binding reference.
       if (memberBindingReference != null) {
         visitEndWithMemberBindingReference();
@@ -2960,8 +3096,11 @@
     private final UserBindingsHelper helper;
     private String bindingName;
 
-    public KeepBindingVisitor(AnnotationParsingContext parsingContext, UserBindingsHelper helper) {
-      super(parsingContext);
+    public KeepBindingVisitor(
+        AnnotationParsingContext parsingContext,
+        UserBindingsHelper helper,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parsingContext = parsingContext;
       this.helper = helper;
     }
@@ -2975,7 +3114,6 @@
     public void visit(String name, Object value) {
       if (name.equals(Binding.bindingName) && value instanceof String) {
         bindingName = (String) value;
-        return;
       }
       super.visit(name, value);
     }
@@ -2998,15 +3136,17 @@
     static KeepTargetVisitor create(
         AnnotationParsingContext parsingContext,
         Parent<KeepTarget> parent,
-        UserBindingsHelper bindingsHelper) {
-      return new KeepTargetVisitor(parsingContext, parent, bindingsHelper);
+        UserBindingsHelper bindingsHelper,
+        AnnotationVisitor annotationVisitor) {
+      return new KeepTargetVisitor(parsingContext, parent, bindingsHelper, annotationVisitor);
     }
 
     private KeepTargetVisitor(
         AnnotationParsingContext parsingContext,
         Parent<KeepTarget> parent,
-        UserBindingsHelper bindingsHelper) {
-      super(parsingContext);
+        UserBindingsHelper bindingsHelper,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       this.bindingsHelper = bindingsHelper;
       constraintsParser = new ConstraintDeclarationParser(parsingContext);
@@ -3019,11 +3159,13 @@
 
     @Override
     public AnnotationVisitor visitArray(String name) {
-      AnnotationVisitor visitor = constraintsParser.tryParseArray(name, unused -> {});
+      AnnotationVisitor annotationVisitor = super.visitArray(name);
+      AnnotationVisitor visitor =
+          constraintsParser.tryParseArray(name, unused -> {}, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
-      return super.visitArray(name);
+      return annotationVisitor;
     }
 
     @Override
@@ -3045,8 +3187,9 @@
     public KeepConditionVisitor(
         AnnotationParsingContext parsingContext,
         Parent<KeepCondition> parent,
-        UserBindingsHelper bindingsHelper) {
-      super(parsingContext);
+        UserBindingsHelper bindingsHelper,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.parent = parent;
       this.bindingsHelper = bindingsHelper;
     }
@@ -3066,8 +3209,11 @@
   private static class MemberAccessVisitor extends AnnotationVisitorBase {
     private KeepMemberAccessPattern.BuilderBase<?, ?> builder;
 
-    public MemberAccessVisitor(ParsingContext parsingContext, BuilderBase<?, ?> builder) {
-      super(parsingContext);
+    public MemberAccessVisitor(
+        ParsingContext parsingContext,
+        BuilderBase<?, ?> builder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, annotationVisitor);
       this.builder = builder;
     }
 
@@ -3079,36 +3225,39 @@
     }
 
     @Override
-    public void visitEnum(String ignore, String descriptor, String value) {
-      if (!AnnotationConstants.MemberAccess.isDescriptor(descriptor)) {
-        super.visitEnum(ignore, descriptor, value);
+    public void visitEnum(String name, String descriptor, String value) {
+      if (AnnotationConstants.MemberAccess.isDescriptor(descriptor)) {
+        boolean handled = handleCommonAccessFlags(value);
+        if (!handled) {
+          unhandledEnum(name, descriptor, value);
+        }
       }
-      boolean handled =
-          withNormalizedAccessFlag(
-              value,
-              (flag, allow) -> {
-                AccessVisibility visibility = getAccessVisibilityFromString(flag);
-                if (visibility != null) {
-                  builder.setAccessVisibility(visibility, allow);
-                  return true;
-                }
-                switch (flag) {
-                  case MemberAccess.STATIC:
-                    builder.setStatic(allow);
-                    return true;
-                  case MemberAccess.FINAL:
-                    builder.setFinal(allow);
-                    return true;
-                  case MemberAccess.SYNTHETIC:
-                    builder.setSynthetic(allow);
-                    return true;
-                  default:
-                    return false;
-                }
-              });
-      if (!handled) {
-        super.visitEnum(ignore, descriptor, value);
-      }
+      super.visitEnum(name, descriptor, value);
+    }
+
+    public boolean handleCommonAccessFlags(String value) {
+      return withNormalizedAccessFlag(
+          value,
+          (flag, allow) -> {
+            AccessVisibility visibility = getAccessVisibilityFromString(flag);
+            if (visibility != null) {
+              builder.setAccessVisibility(visibility, allow);
+              return true;
+            }
+            switch (flag) {
+              case MemberAccess.STATIC:
+                builder.setStatic(allow);
+                return true;
+              case MemberAccess.FINAL:
+                builder.setFinal(allow);
+                return true;
+              case MemberAccess.SYNTHETIC:
+                builder.setSynthetic(allow);
+                return true;
+              default:
+                return false;
+            }
+          });
     }
 
     private AccessVisibility getAccessVisibilityFromString(String value) {
@@ -3132,44 +3281,48 @@
     private KeepMethodAccessPattern.Builder methodAccessBuilder;
 
     public MethodAccessVisitor(
-        ParsingContext parsingContext, KeepMethodAccessPattern.Builder builder) {
-      super(parsingContext, builder);
+        ParsingContext parsingContext,
+        KeepMethodAccessPattern.Builder builder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, builder, annotationVisitor);
       this.methodAccessBuilder = builder;
     }
 
     @Override
-    public void visitEnum(String ignore, String descriptor, String value) {
-      if (!AnnotationConstants.MethodAccess.isDescriptor(descriptor)) {
-        super.visitEnum(ignore, descriptor, value);
+    public void visitEnum(String name, String descriptor, String value) {
+      if (AnnotationConstants.MethodAccess.isDescriptor(descriptor)) {
+        boolean handled =
+            withNormalizedAccessFlag(
+                value,
+                (flag, allow) -> {
+                  switch (flag) {
+                    case MethodAccess.SYNCHRONIZED:
+                      methodAccessBuilder.setSynchronized(allow);
+                      return true;
+                    case MethodAccess.BRIDGE:
+                      methodAccessBuilder.setBridge(allow);
+                      return true;
+                    case MethodAccess.NATIVE:
+                      methodAccessBuilder.setNative(allow);
+                      return true;
+                    case MethodAccess.ABSTRACT:
+                      methodAccessBuilder.setAbstract(allow);
+                      return true;
+                    case MethodAccess.STRICT_FP:
+                      methodAccessBuilder.setStrictFp(allow);
+                      return true;
+                    default:
+                      return false;
+                  }
+                });
+        if (!handled) {
+          handled = handleCommonAccessFlags(value);
+          if (!handled) {
+            unhandledEnum(name, descriptor, value);
+          }
+        }
       }
-      boolean handled =
-          withNormalizedAccessFlag(
-              value,
-              (flag, allow) -> {
-                switch (flag) {
-                  case MethodAccess.SYNCHRONIZED:
-                    methodAccessBuilder.setSynchronized(allow);
-                    return true;
-                  case MethodAccess.BRIDGE:
-                    methodAccessBuilder.setBridge(allow);
-                    return true;
-                  case MethodAccess.NATIVE:
-                    methodAccessBuilder.setNative(allow);
-                    return true;
-                  case MethodAccess.ABSTRACT:
-                    methodAccessBuilder.setAbstract(allow);
-                    return true;
-                  case MethodAccess.STRICT_FP:
-                    methodAccessBuilder.setStrictFp(allow);
-                    return true;
-                  default:
-                    return false;
-                }
-              });
-      if (!handled) {
-        // Continue visitation with the "member" descriptor to allow matching the common values.
-        super.visitEnum(ignore, MemberAccess.getDescriptor(), value);
-      }
+      super.visitEnum(name, descriptor, value);
     }
   }
 
@@ -3178,36 +3331,39 @@
     private KeepFieldAccessPattern.Builder fieldAccessBuilder;
 
     public FieldAccessVisitor(
-        ParsingContext parsingContext, KeepFieldAccessPattern.Builder builder) {
-      super(parsingContext, builder);
+        ParsingContext parsingContext,
+        KeepFieldAccessPattern.Builder builder,
+        AnnotationVisitor annotationVisitor) {
+      super(parsingContext, builder, annotationVisitor);
       this.fieldAccessBuilder = builder;
     }
 
     @Override
-    public void visitEnum(String ignore, String descriptor, String value) {
-      if (!AnnotationConstants.FieldAccess.isDescriptor(descriptor)) {
-        super.visitEnum(ignore, descriptor, value);
+    public void visitEnum(String name, String descriptor, String value) {
+      if (AnnotationConstants.FieldAccess.isDescriptor(descriptor)) {
+        boolean handled =
+            withNormalizedAccessFlag(
+                value,
+                (flag, allow) -> {
+                  switch (flag) {
+                    case FieldAccess.VOLATILE:
+                      fieldAccessBuilder.setVolatile(allow);
+                      return true;
+                    case FieldAccess.TRANSIENT:
+                      fieldAccessBuilder.setTransient(allow);
+                      return true;
+                    default:
+                      return false;
+                  }
+                });
+        if (!handled) {
+          handled = handleCommonAccessFlags(value);
+          if (!handled) {
+            unhandledEnum(name, descriptor, value);
+          }
+        }
       }
-      boolean handled =
-          withNormalizedAccessFlag(
-              value,
-              (flag, allow) -> {
-                switch (flag) {
-                  case FieldAccess.VOLATILE:
-                    fieldAccessBuilder.setVolatile(allow);
-                    return true;
-                  case FieldAccess.TRANSIENT:
-                    fieldAccessBuilder.setTransient(allow);
-                    return true;
-                  default:
-                    return false;
-                }
-              });
-      if (!handled) {
-        // Continue visitation with the "member" descriptor to allow matching the common values.
-        super.visitEnum(ignore, MemberAccess.getDescriptor(), value);
-      }
+      super.visitEnum(name, descriptor, value);
     }
   }
-
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/MethodReturnTypeParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/MethodReturnTypeParser.java
index ccf5183..d5a1b6c 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/MethodReturnTypeParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/MethodReturnTypeParser.java
@@ -66,8 +66,11 @@
 
   @Override
   AnnotationVisitor tryPropertyArray(
-      TypeProperty property, String name, Consumer<KeepMethodReturnTypePattern> setValue) {
-    return typeParser.tryPropertyArray(property, name, wrap(setValue));
+      TypeProperty property,
+      String name,
+      Consumer<KeepMethodReturnTypePattern> setValue,
+      AnnotationVisitor annotationVisitor) {
+    return typeParser.tryPropertyArray(property, name, wrap(setValue), annotationVisitor);
   }
 
   @Override
@@ -75,7 +78,9 @@
       TypeProperty property,
       String name,
       String descriptor,
-      Consumer<KeepMethodReturnTypePattern> setValue) {
-    return typeParser.tryPropertyAnnotation(property, name, descriptor, wrap(setValue));
+      Consumer<KeepMethodReturnTypePattern> setValue,
+      AnnotationVisitor annotationVisitor) {
+    return typeParser.tryPropertyAnnotation(
+        property, name, descriptor, wrap(setValue), annotationVisitor);
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/Parser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/Parser.java
index 3ca879b..58925e1 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/Parser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/Parser.java
@@ -19,7 +19,9 @@
 
   boolean tryParseEnum(String name, String descriptor, String value, Consumer<T> setValue);
 
-  AnnotationVisitor tryParseArray(String name, Consumer<T> setValue);
+  AnnotationVisitor tryParseArray(
+      String name, Consumer<T> setValue, AnnotationVisitor annotationVisitor);
 
-  AnnotationVisitor tryParseAnnotation(String name, String descriptor, Consumer<T> setValue);
+  AnnotationVisitor tryParseAnnotation(
+      String name, String descriptor, Consumer<T> setValue, AnnotationVisitor annotationVisitor);
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ParserVisitor.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ParserVisitor.java
index 5acb59f..92aab67 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ParserVisitor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ParserVisitor.java
@@ -16,64 +16,75 @@
   private final Runnable onVisitEnd;
 
   public ParserVisitor(
-      AnnotationParsingContext parsingContext, List<Parser<?>> parsers, Runnable onVisitEnd) {
-    super(parsingContext);
+      AnnotationParsingContext parsingContext,
+      List<Parser<?>> parsers,
+      Runnable onVisitEnd,
+      AnnotationVisitor annotationVisitor) {
+    super(parsingContext, annotationVisitor);
     this.parsers = parsers;
     this.onVisitEnd = onVisitEnd;
   }
 
   public ParserVisitor(
-      AnnotationParsingContext parsingContext, Parser<?> parser, Runnable onVisitEnd) {
-    this(parsingContext, Collections.singletonList(parser), onVisitEnd);
+      AnnotationParsingContext parsingContext,
+      Parser<?> parser,
+      Runnable onVisitEnd,
+      AnnotationVisitor annotationVisitor) {
+    this(parsingContext, Collections.singletonList(parser), onVisitEnd, annotationVisitor);
   }
 
   private <T> void ignore(T unused) {}
 
   @Override
   public void visit(String name, Object value) {
+    super.visit(name, value);
     for (Parser<?> parser : parsers) {
       if (parser.tryParse(name, value, this::ignore)) {
         return;
       }
     }
-    super.visit(name, value);
+    unhandledValue(name, value);
   }
 
   @Override
   public AnnotationVisitor visitArray(String name) {
+    AnnotationVisitor annotationVisitor = super.visitArray(name);
     for (Parser<?> parser : parsers) {
-      AnnotationVisitor visitor = parser.tryParseArray(name, this::ignore);
+      AnnotationVisitor visitor = parser.tryParseArray(name, this::ignore, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
     }
-    return super.visitArray(name);
+    return unhandledArray(name);
   }
 
   @Override
   public void visitEnum(String name, String descriptor, String value) {
+    super.visitEnum(name, descriptor, value);
     for (Parser<?> parser : parsers) {
       if (parser.tryParseEnum(name, descriptor, value, this::ignore)) {
         return;
       }
     }
-    super.visitEnum(name, descriptor, value);
+    unhandledEnum(name, descriptor, value);
   }
 
   @Override
   public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+    AnnotationVisitor annotationVisitor = super.visitAnnotation(name, descriptor);
     for (Parser<?> parser : parsers) {
-      AnnotationVisitor visitor = parser.tryParseAnnotation(name, descriptor, this::ignore);
+      AnnotationVisitor visitor =
+          parser.tryParseAnnotation(name, descriptor, this::ignore, annotationVisitor);
       if (visitor != null) {
         return visitor;
       }
     }
-    return super.visitAnnotation(name, descriptor);
+    return unhandledAnnotation(name, descriptor);
   }
 
   @Override
   public void visitEnd() {
-    onVisitEnd.run();
     super.visitEnd();
+    onVisitEnd.run();
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/PropertyParserBase.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/PropertyParserBase.java
index f5b40c3..5360348 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/PropertyParserBase.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/PropertyParserBase.java
@@ -42,13 +42,18 @@
     return false;
   }
 
-  AnnotationVisitor tryPropertyArray(P property, String name, Consumer<T> setValue) {
-    return null;
+  AnnotationVisitor tryPropertyArray(
+      P property, String name, Consumer<T> setValue, AnnotationVisitor annotationVisitor) {
+    return annotationVisitor;
   }
 
   AnnotationVisitor tryPropertyAnnotation(
-      P property, String name, String descriptor, Consumer<T> setValue) {
-    return null;
+      P property,
+      String name,
+      String descriptor,
+      Consumer<T> setValue,
+      AnnotationVisitor annotationVisitor) {
+    return annotationVisitor;
   }
 
   private Consumer<T> wrap(String propertyName, Consumer<T> setValue) {
@@ -124,30 +129,32 @@
   }
 
   @Override
-  public final AnnotationVisitor tryParseArray(String name, Consumer<T> setValue) {
+  public final AnnotationVisitor tryParseArray(
+      String name, Consumer<T> setValue, AnnotationVisitor annotationVisitor) {
     P prop = mapping.get(name);
     if (prop != null) {
       try {
-        return tryPropertyArray(prop, name, wrap(name, setValue));
+        return tryPropertyArray(prop, name, wrap(name, setValue), annotationVisitor);
       } catch (RuntimeException e) {
         throw parsingContext.rethrow(e);
       }
     }
-    return null;
+    return annotationVisitor;
   }
 
   @Override
   public final AnnotationVisitor tryParseAnnotation(
-      String name, String descriptor, Consumer<T> setValue) {
+      String name, String descriptor, Consumer<T> setValue, AnnotationVisitor annotationVisitor) {
     P prop = mapping.get(name);
     if (prop != null) {
       try {
-        return tryPropertyAnnotation(prop, name, descriptor, wrap(name, setValue));
+        return tryPropertyAnnotation(
+            prop, name, descriptor, wrap(name, setValue), annotationVisitor);
       } catch (RuntimeException e) {
         throw parsingContext.rethrow(e);
       }
     }
-    return null;
+    return annotationVisitor;
   }
 
   public void setValueCheck(BiConsumer<T, ParsingContext> check) {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/StringPatternParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/StringPatternParser.java
index 2bb95df..486f586 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/StringPatternParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/StringPatternParser.java
@@ -43,7 +43,8 @@
       StringProperty property,
       String name,
       String descriptor,
-      Consumer<KeepStringPattern> setValue) {
+      Consumer<KeepStringPattern> setValue,
+      AnnotationVisitor annotationVisitor) {
     switch (property) {
       case PATTERN:
         {
@@ -74,7 +75,8 @@
                           .setSuffix(suffixParser.getValueOrDefault(null))
                           .build());
                 }
-              });
+              },
+              annotationVisitor);
         }
       default:
         return null;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
index 85962be..1e2198c 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
@@ -49,7 +49,11 @@
 
   @Override
   public AnnotationVisitor tryPropertyAnnotation(
-      TypeProperty property, String name, String descriptor, Consumer<KeepTypePattern> setValue) {
+      TypeProperty property,
+      String name,
+      String descriptor,
+      Consumer<KeepTypePattern> setValue,
+      AnnotationVisitor annotationVisitor) {
     switch (property) {
       case TYPE_PATTERN:
         {
@@ -63,7 +67,8 @@
           return new ParserVisitor(
               context,
               typeParser,
-              () -> setValue.accept(typeParser.getValueOrDefault(KeepTypePattern.any())));
+              () -> setValue.accept(typeParser.getValueOrDefault(KeepTypePattern.any())),
+              annotationVisitor);
         }
       case CLASS_NAME_PATTERN:
         {
@@ -72,8 +77,8 @@
               ClassNameProperty.PATTERN,
               name,
               descriptor,
-              value ->
-                  setValue.accept(KeepTypePattern.fromClass(KeepClassPattern.fromName(value))));
+              value -> setValue.accept(KeepTypePattern.fromClass(KeepClassPattern.fromName(value))),
+              annotationVisitor);
         }
       case INSTANCE_OF_PATTERN:
         {
@@ -85,7 +90,8 @@
               value ->
                   setValue.accept(
                       KeepTypePattern.fromClass(
-                          KeepClassPattern.builder().setInstanceOfPattern(value).build())));
+                          KeepClassPattern.builder().setInstanceOfPattern(value).build())),
+              annotationVisitor);
         }
       default:
         return null;
diff --git a/src/test/java8/keepanno/com/android/tools/r8/keepanno/KeepAnnoChainingTest.java b/src/test/java8/keepanno/com/android/tools/r8/keepanno/KeepAnnoChainingTest.java
new file mode 100644
index 0000000..fca830b
--- /dev/null
+++ b/src/test/java8/keepanno/com/android/tools/r8/keepanno/KeepAnnoChainingTest.java
@@ -0,0 +1,150 @@
+// Copyright (c) 2026, 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.keepanno;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.UsedByReflection;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class KeepAnnoChainingTest extends TestBase {
+
+  @UsedByReflection(kind = KeepItemKind.CLASS_AND_MEMBERS)
+  static class AnnotatedClass {
+    @UsedByReflection(kind = KeepItemKind.CLASS_AND_MEMBERS)
+    public int field;
+
+    @UsedByReflection(kind = KeepItemKind.CLASS_AND_MEMBERS)
+    public void method() {}
+  }
+
+  private static class RecordingVisitor extends ClassVisitor {
+    int visitCount = 0;
+    int visitAnnotationCount = 0;
+    int visitFieldCount = 0;
+    int visitMethodCount = 0;
+    List<String> visitedAnnotations = new ArrayList<>();
+    List<String> visitedFields = new ArrayList<>();
+    List<String> visitedMethods = new ArrayList<>();
+    List<String> visitedFieldAnnotations = new ArrayList<>();
+    List<String> visitedMethodAnnotations = new ArrayList<>();
+
+    RecordingVisitor() {
+      super(Opcodes.ASM9);
+    }
+
+    @Override
+    public void visit(
+        int version,
+        int access,
+        String name,
+        String signature,
+        String superName,
+        String[] interfaces) {
+      visitCount++;
+      super.visit(version, access, name, signature, superName, interfaces);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+      visitAnnotationCount++;
+      visitedAnnotations.add(descriptor);
+      return super.visitAnnotation(descriptor, visible);
+    }
+
+    @Override
+    public FieldVisitor visitField(
+        int access, String name, String descriptor, String signature, Object value) {
+      visitFieldCount++;
+      visitedFields.add(name);
+      FieldVisitor fieldVisitor = super.visitField(access, name, descriptor, signature, value);
+      return new FieldVisitor(Opcodes.ASM9, fieldVisitor) {
+        @Override
+        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+          visitedFieldAnnotations.add(descriptor);
+          return super.visitAnnotation(descriptor, visible);
+        }
+      };
+    }
+
+    @Override
+    public MethodVisitor visitMethod(
+        int access, String name, String descriptor, String signature, String[] exceptions) {
+      visitMethodCount++;
+      visitedMethods.add(name);
+      MethodVisitor methodVisitor =
+          super.visitMethod(access, name, descriptor, signature, exceptions);
+      return new MethodVisitor(Opcodes.ASM9, methodVisitor) {
+        @Override
+        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+          visitedMethodAnnotations.add(descriptor);
+          return super.visitAnnotation(descriptor, visible);
+        }
+      };
+    }
+  }
+
+  @Test
+  public void testChainingRulesExtractor() throws Exception {
+    byte[] bytes = Files.readAllBytes(ToolHelper.getClassFileForTestClass(AnnotatedClass.class));
+    ClassReader reader = new ClassReader(bytes);
+
+    List<String> rules = new ArrayList<>();
+    RecordingVisitor recorder = new RecordingVisitor();
+    ClassVisitor extractor =
+        KeepAnno.createClassVisitorForKeepRulesExtraction(rules::add, recorder);
+
+    reader.accept(extractor, ClassReader.SKIP_CODE);
+
+    // Verify rules were extracted
+    assertTrue(rules.size() > 0);
+
+    // Verify recorder saw everything
+    assertEquals(1, recorder.visitCount);
+    // AnnotatedClass has @UsedByReflection on class
+    assertTrue(recorder.visitedAnnotations.stream().anyMatch(d -> d.contains("UsedByReflection")));
+    // And it has field and method
+    assertTrue(recorder.visitedFields.contains("field"));
+    assertTrue(recorder.visitedMethods.contains("method"));
+
+    // Verify field and method annotations were delegated
+    assertTrue(
+        recorder.visitedFieldAnnotations.stream().anyMatch(d -> d.contains("UsedByReflection")));
+    assertTrue(
+        recorder.visitedMethodAnnotations.stream().anyMatch(d -> d.contains("UsedByReflection")));
+  }
+
+  @Test
+  public void testChainingRulesExtractorWithItself() throws Exception {
+    byte[] bytes = Files.readAllBytes(ToolHelper.getClassFileForTestClass(AnnotatedClass.class));
+    ClassReader reader = new ClassReader(bytes);
+
+    List<String> rules = new ArrayList<>();
+    ClassVisitor extractor = KeepAnno.createClassVisitorForKeepRulesExtraction(rules::add);
+
+    List<String> rules2 = new ArrayList<>();
+    ClassVisitor extractor2 =
+        KeepAnno.createClassVisitorForKeepRulesExtraction(rules2::add, extractor);
+
+    reader.accept(extractor2, ClassReader.SKIP_CODE);
+
+    // As the visitor is not making any changes but only reading the annotations chaining it with
+    // itself should extract the same rules twice.
+    assertTrue(rules.size() > 0);
+    assertEquals(rules2, rules);
+  }
+}