[KeepAnno] Add support of adding to the default constraints

Bug: b/248408342
Change-Id: Ibd6b97c537354c06db38893dd9fdc80bd25a8637
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java
index d18f91d..3d055d0 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java
@@ -75,6 +75,7 @@
    * <p>Mutually exclusive with the following other properties defining constraints:
    *
    * <ul>
+   *   <li>constraintAdditions
    *   <li>allow
    *   <li>disallow
    * </ul>
@@ -86,6 +87,28 @@
   KeepConstraint[] constraints() default {};
 
   /**
+   * Add additional usage constraints of the target.
+   *
+   * <p>The specified constraints must remain valid for the target in addition to the default
+   * constraints.
+   *
+   * <p>The default constraints are documented in {@link #constraints}
+   *
+   * <p>Mutually exclusive with the following other properties defining constraints:
+   *
+   * <ul>
+   *   <li>constraints
+   *   <li>allow
+   *   <li>disallow
+   * </ul>
+   *
+   * <p>If nothing is specified for constraints the default is the default for {@link #constraints}.
+   *
+   * @return Additional usage constraints for the target.
+   */
+  KeepConstraint[] constraintAdditions() default {};
+
+  /**
    * Define the constraints that are allowed to be modified.
    *
    * <p>The specified option constraints do not need to be preserved for the target.
@@ -94,6 +117,7 @@
    *
    * <ul>
    *   <li>constraints
+   *   <li>constraintAdditions
    *   <li>disallow
    * </ul>
    *
@@ -114,6 +138,7 @@
    *
    * <ul>
    *   <li>constraints
+   *   <li>constraintAdditions
    *   <li>allow
    * </ul>
    *
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintsParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintsParser.java
index 981c480..05b9fe8 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintsParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ConstraintsParser.java
@@ -16,6 +16,7 @@
 
   public enum ConstraintsProperty {
     CONSTRAINTS,
+    ADDITIONS,
     ALLOW,
     DISALLOW
   }
@@ -27,19 +28,24 @@
   @Override
   AnnotationVisitor tryPropertyArray(
       ConstraintsProperty property, String name, Consumer<KeepConstraints> setValue) {
+    ParsingContext parsingContext = getParsingContext().property(name);
     switch (property) {
+      case ADDITIONS:
+        return new KeepConstraintsVisitor(
+            parsingContext,
+            constraints -> setValue.accept(KeepConstraints.defaultAdditions(constraints)));
       case CONSTRAINTS:
-        return new KeepConstraintsVisitor(getParsingContext(), setValue::accept);
+        return new KeepConstraintsVisitor(parsingContext, setValue::accept);
       case ALLOW:
         return new KeepOptionsVisitor(
-            getParsingContext(),
+            parsingContext,
             options ->
                 setValue.accept(
                     KeepConstraints.fromLegacyOptions(
                         KeepOptions.allowBuilder().addAll(options).build())));
       case DISALLOW:
         return new KeepOptionsVisitor(
-            getParsingContext(),
+            parsingContext,
             options ->
                 setValue.accept(
                     KeepConstraints.fromLegacyOptions(
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 c0d6087..b37f18f 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
@@ -747,6 +747,7 @@
       visit(Item.className, className);
       constraintsParser = new ConstraintsParser(parsingContext);
       constraintsParser.setProperty(Target.constraints, ConstraintsProperty.CONSTRAINTS);
+      constraintsParser.setProperty(Target.constraintAdditions, ConstraintsProperty.ADDITIONS);
       constraintsParser.setProperty(Target.allow, ConstraintsProperty.ALLOW);
       constraintsParser.setProperty(Target.disallow, ConstraintsProperty.DISALLOW);
     }
@@ -857,6 +858,7 @@
       addContext.accept(metaInfoBuilder);
       constraintsParser = new ConstraintsParser(parsingContext);
       constraintsParser.setProperty(Target.constraints, ConstraintsProperty.CONSTRAINTS);
+      constraintsParser.setProperty(Target.constraintAdditions, ConstraintsProperty.ADDITIONS);
       constraintsParser.setProperty(Target.allow, ConstraintsProperty.ALLOW);
       constraintsParser.setProperty(Target.disallow, ConstraintsProperty.DISALLOW);
     }
@@ -1809,6 +1811,7 @@
       this.bindingsHelper = bindingsHelper;
       optionsParser = new ConstraintsParser(parsingContext);
       optionsParser.setProperty(Target.constraints, ConstraintsProperty.CONSTRAINTS);
+      optionsParser.setProperty(Target.constraintAdditions, ConstraintsProperty.ADDITIONS);
       optionsParser.setProperty(Target.allow, ConstraintsProperty.ALLOW);
       optionsParser.setProperty(Target.disallow, ConstraintsProperty.DISALLOW);
     }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
index 85082de..a03cb6c 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
@@ -140,6 +140,7 @@
     public static final String kind = "kind";
     public static final String constraintsGroup = "constraints";
     public static final String constraints = "constraints";
+    public static final String constraintAdditions = "constraintAdditions";
     public static final String allow = "allow";
     public static final String disallow = "disallow";
   }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraints.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraints.java
index 65673ec..a4be849 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraints.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraints.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.keepanno.ast;
 
+import com.android.tools.r8.keepanno.ast.KeepOptions.KeepOption;
 import com.google.common.collect.ImmutableSet;
 import java.util.Collections;
 import java.util.HashSet;
@@ -21,6 +22,10 @@
     return Defaults.INSTANCE;
   }
 
+  public static KeepConstraints defaultAdditions(KeepConstraints additionalConstraints) {
+    return new Additions(additionalConstraints);
+  }
+
   public static Builder builder() {
     return new Builder();
   }
@@ -87,6 +92,32 @@
     }
   }
 
+  private static class Additions extends KeepConstraints {
+
+    private final KeepConstraints additions;
+
+    public Additions(KeepConstraints additions) {
+      this.additions = additions;
+    }
+
+    @Override
+    public KeepOptions convertToKeepOptions(KeepOptions defaultOptions) {
+      KeepOptions additionalOptions = additions.convertToKeepOptions(defaultOptions);
+      KeepOptions.Builder builder = KeepOptions.disallowBuilder();
+      for (KeepOption option : KeepOption.values()) {
+        if (!additionalOptions.isAllowed(option) || !defaultOptions.isAllowed(option)) {
+          builder.add(option);
+        }
+      }
+      return builder.build();
+    }
+
+    @Override
+    public Set<KeepAttribute> getRequiredKeepAttributes() {
+      return additions.getRequiredKeepAttributes();
+    }
+  }
+
   private static class Constraints extends KeepConstraints {
 
     private final Set<KeepConstraint> constraints;
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepAccessVisibilityFlagsTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepAccessVisibilityFlagsTest.java
index 2454356..afa1871 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepAccessVisibilityFlagsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepAccessVisibilityFlagsTest.java
@@ -187,29 +187,17 @@
       @KeepTarget(
           kind = KeepItemKind.CLASS_AND_MEMBERS,
           classConstant = FieldRuleTarget.class,
-          constraints = {
-            KeepConstraint.LOOKUP,
-            KeepConstraint.NAME,
-            KeepConstraint.VISIBILITY_INVARIANT
-          },
+          constraintAdditions = {KeepConstraint.VISIBILITY_INVARIANT},
           fieldAccess = {FieldAccessFlags.NON_PRIVATE}),
       @KeepTarget(
           kind = KeepItemKind.CLASS_AND_MEMBERS,
           classConstant = MethodRuleTarget.class,
-          constraints = {
-            KeepConstraint.LOOKUP,
-            KeepConstraint.NAME,
-            KeepConstraint.VISIBILITY_INVARIANT
-          },
+          constraintAdditions = {KeepConstraint.VISIBILITY_INVARIANT},
           methodAccess = {MethodAccessFlags.NON_PACKAGE_PRIVATE}),
       @KeepTarget(
           kind = KeepItemKind.CLASS_AND_MEMBERS,
           classConstant = MemberRuleTarget.class,
-          constraints = {
-            KeepConstraint.LOOKUP,
-            KeepConstraint.NAME,
-            KeepConstraint.VISIBILITY_INVARIANT
-          },
+          constraintAdditions = {KeepConstraint.VISIBILITY_INVARIANT},
           memberAccess = {MemberAccessFlags.PACKAGE_PRIVATE, MemberAccessFlags.PRIVATE}),
     })
     void foo() {
diff --git a/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java b/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
index 18d8d6d..642e269 100644
--- a/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
@@ -122,19 +122,19 @@
           classConstant = OnMembers.class,
           kind = KeepItemKind.CLASS_AND_MEMBERS,
           memberAnnotatedByClassConstant = A.class,
-          constraints = {KeepConstraint.LOOKUP, KeepConstraint.ANNOTATIONS, KeepConstraint.NAME}),
+          constraintAdditions = {KeepConstraint.ANNOTATIONS}),
       @KeepTarget(
           classConstant = OnFields.class,
           kind = KeepItemKind.CLASS_AND_FIELDS,
           fieldAnnotatedByClassName =
               "com.android.tools.r8.keepanno.MembersAnnotatedByPatternsTest$B",
-          constraints = {KeepConstraint.LOOKUP, KeepConstraint.ANNOTATIONS, KeepConstraint.NAME}),
+          constraintAdditions = {KeepConstraint.ANNOTATIONS}),
       @KeepTarget(
           classConstant = OnMethods.class,
           kind = KeepItemKind.CLASS_AND_METHODS,
           methodAnnotatedByClassNamePattern =
               @ClassNamePattern(simpleName = "MembersAnnotatedByPatternsTest$C"),
-          constraints = {KeepConstraint.LOOKUP, KeepConstraint.ANNOTATIONS, KeepConstraint.NAME})
+          constraintAdditions = {KeepConstraint.ANNOTATIONS})
     })
     public void foo(Class<?> clazz) throws Exception {
       for (Field field : clazz.getDeclaredFields()) {
diff --git a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
index b12f190..6344760 100644
--- a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
+++ b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
@@ -490,6 +490,7 @@
     private Group getKeepConstraintsGroup() {
       return new Group(CONSTRAINTS_GROUP)
           .addMember(constraints())
+          .addMember(constraintAdditions())
           .addMember(
               new GroupMember("allow")
                   .setDeprecated("Use " + docLink(constraints()) + " instead.")
@@ -543,6 +544,17 @@
           .defaultArrayEmpty(KeepConstraint.class);
     }
 
+    private static GroupMember constraintAdditions() {
+      return new GroupMember("constraintAdditions")
+          .setDocTitle("Add additional usage constraints of the target.")
+          .addParagraph(
+              "The specified constraints must remain valid for the target",
+              "in addition to the default constraints.")
+          .addParagraph("The default constraints are documented in " + docLink(constraints()))
+          .setDocReturn("Additional usage constraints for the target.")
+          .defaultArrayEmpty(KeepConstraint.class);
+    }
+
     private GroupMember bindingName() {
       return new GroupMember("bindingName")
           .setDocTitle(