[KeepAnno] Clean up AST after CLASS_AND_MEMBERS is a derived form

This also removed the 'any' item such that an item is now either
a class or a member, but cannot be both.

Bug: b/248408342
Change-Id: I9705191b94f0ff37216a854766b4c43b0f2eec14
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 5f7f156..d3fc1ba 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
@@ -34,7 +34,6 @@
 import com.android.tools.r8.keepanno.ast.KeepFieldNamePattern;
 import com.android.tools.r8.keepanno.ast.KeepFieldPattern;
 import com.android.tools.r8.keepanno.ast.KeepFieldTypePattern;
-import com.android.tools.r8.keepanno.ast.KeepItemKind;
 import com.android.tools.r8.keepanno.ast.KeepItemPattern;
 import com.android.tools.r8.keepanno.ast.KeepItemReference;
 import com.android.tools.r8.keepanno.ast.KeepMemberAccessPattern;
@@ -491,10 +490,8 @@
         if (!descriptor.equals(itemDescriptor)) {
           throw new KeepEdgeException("@KeepForApi must reference its class context " + className);
         }
-        if (itemPattern.getKind().equals(KeepItemKind.ONLY_MEMBERS)) {
-          if (items.size() == 1) {
+        if (itemPattern.isMemberItemPattern() && items.size() == 1) {
             throw new KeepEdgeException("@KeepForApi kind must include its class");
-          }
         }
         if (!itemPattern.getExtendsPattern().isAny()) {
           throw new KeepEdgeException("@KeepForApi cannot define an 'extends' pattern.");
@@ -668,10 +665,8 @@
           throw new KeepEdgeException(
               "@" + getAnnotationName() + " must reference its class context " + className);
         }
-        if (itemPattern.getKind().equals(KeepItemKind.ONLY_MEMBERS)) {
-          if (items.size() == 1) {
-            throw new KeepEdgeException("@" + getAnnotationName() + " kind must include its class");
-          }
+        if (itemPattern.isMemberItemPattern() && items.size() == 1) {
+          throw new KeepEdgeException("@" + getAnnotationName() + " kind must include its class");
         }
         if (!itemPattern.getExtendsPattern().isAny()) {
           throw new KeepEdgeException(
@@ -701,7 +696,7 @@
     private final KeepEdgeMetaInfo.Builder metaInfoBuilder = KeepEdgeMetaInfo.builder();
     private final UserBindingsHelper bindingsHelper = new UserBindingsHelper();
     private final KeepConsequences.Builder consequences = KeepConsequences.builder();
-    private KeepItemKind kind = KeepItemKind.ONLY_MEMBERS;
+    private String kind = Kind.ONLY_MEMBERS;
 
     UsedByReflectionMemberVisitor(
         String annotationDescriptor,
@@ -739,13 +734,9 @@
           // The default value is obtained by not assigning a kind (e.g., null in the builder).
           break;
         case Kind.ONLY_CLASS:
-          kind = KeepItemKind.ONLY_CLASS;
-          break;
         case Kind.ONLY_MEMBERS:
-          kind = KeepItemKind.ONLY_MEMBERS;
-          break;
         case Kind.CLASS_AND_MEMBERS:
-          kind = KeepItemKind.CLASS_AND_MEMBERS;
+          kind = value;
           break;
         default:
           super.visitEnum(name, descriptor, value);
@@ -771,11 +762,11 @@
 
     @Override
     public void visitEnd() {
-      if (kind.equals(KeepItemKind.ONLY_CLASS)) {
+      if (Kind.ONLY_CLASS.equals(kind)) {
         throw new KeepEdgeException("@" + getAnnotationName() + " kind must include its member");
       }
-      assert context.getKind() == KeepItemKind.ONLY_MEMBERS;
-      if (kind.equals(KeepItemKind.CLASS_AND_MEMBERS)) {
+      assert context.isMemberItemPattern();
+      if (Kind.CLASS_AND_MEMBERS.equals(kind)) {
         consequences.addTarget(
             KeepTarget.builder()
                 .setItemPattern(
@@ -1436,21 +1427,24 @@
         assert !itemReference.isBindingReference();
         KeepItemPattern itemPattern = itemReference.asItemPattern();
         KeepItemPattern classPattern;
+        KeepItemPattern memberPattern;
         if (itemPattern.isClassItemPattern()) {
           classPattern = itemPattern;
+          memberPattern =
+              KeepItemPattern.builder()
+                  .copyFrom(itemPattern)
+                  .setMemberPattern(KeepMemberPattern.allMembers())
+                  .build();
         } else {
+          memberPattern = itemPattern;
           classPattern =
               KeepItemPattern.builder()
                   .copyFrom(itemPattern)
-                  .setKind(KeepItemKind.ONLY_CLASS)
                   .setMemberPattern(KeepMemberPattern.none())
                   .build();
         }
-        KeepItemPattern memberPattern =
-            KeepItemPattern.builder()
-                .copyFrom(itemPattern)
-                .setKind(KeepItemKind.ONLY_MEMBERS)
-                .build();
+        assert classPattern.isClassItemPattern();
+        assert memberPattern.isMemberItemPattern();
         return ImmutableList.of(
             KeepItemReference.fromItemPattern(classPattern),
             KeepItemReference.fromItemPattern(memberPattern));
@@ -1470,27 +1464,31 @@
       assert kind != null;
       if (Kind.CLASS_AND_MEMBERS.equals(kind)) {
         KeepItemPattern itemPattern = itemReference.asItemPattern();
+        KeepMemberPattern memberPattern;
         KeepItemPattern classPattern;
         if (itemPattern.isClassItemPattern()) {
+          memberPattern = KeepMemberPattern.allMembers();
           classPattern = itemPattern;
         } else {
+          memberPattern = itemPattern.getMemberPattern();
           classPattern =
               KeepItemPattern.builder()
                   .copyFrom(itemPattern)
-                  .setKind(KeepItemKind.ONLY_CLASS)
                   .setMemberPattern(KeepMemberPattern.none())
                   .build();
         }
         BindingSymbol symbol = getBindingsHelper().defineFreshBinding("CLASS", classPattern);
-        KeepItemPattern memberPattern =
+        KeepItemPattern memberItemPattern =
             KeepItemPattern.builder()
                 .copyFrom(itemPattern)
                 .setClassReference(KeepClassReference.fromBindingReference(symbol))
-                .setKind(KeepItemKind.ONLY_MEMBERS)
+                .setMemberPattern(memberPattern)
                 .build();
+        assert classPattern.isClassItemPattern();
+        assert memberItemPattern.isMemberItemPattern();
         return ImmutableList.of(
             KeepItemReference.fromItemPattern(classPattern),
-            KeepItemReference.fromItemPattern(memberPattern));
+            KeepItemReference.fromItemPattern(memberItemPattern));
       } else {
         return Collections.singletonList(itemReference);
       }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
index dc8e7c9..ec3fb30 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
@@ -138,12 +138,6 @@
   }
 
   private void writeItem(AnnotationVisitor itemVisitor, KeepItemPattern item) {
-    if (item.isAny(
-        binding -> {
-          throw new Unimplemented();
-        })) {
-      throw new Unimplemented();
-    }
     KeepClassReference classReference = item.getClassReference();
     if (classReference.isBindingReference()) {
       throw new Unimplemented();
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindings.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindings.java
index 790fb9e..a3ba447 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindings.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindings.java
@@ -45,26 +45,6 @@
     bindings.forEach((name, binding) -> fn.accept(name, binding.getItem()));
   }
 
-  public boolean isAny(KeepItemReference itemReference) {
-    return itemReference.isBindingReference()
-        ? isAny(get(itemReference.asBindingReference()).getItem())
-        : isAny(itemReference.asItemPattern());
-  }
-
-  public boolean isAny(KeepItemPattern itemPattern) {
-    return itemPattern.isAny(this::isAnyClassNamePattern);
-  }
-
-  // If the outer-most item has been judged to be "any" then we internally only need to check
-  // that the class-name pattern itself is "any". The class-name could potentially reference names
-  // of other item bindings so this is a recursive search.
-  private boolean isAnyClassNamePattern(BindingSymbol bindingName) {
-    KeepClassReference classReference = get(bindingName).getItem().getClassReference();
-    return classReference.isBindingReference()
-        ? isAnyClassNamePattern(classReference.asBindingReference())
-        : classReference.asClassNamePattern().isAny();
-  }
-
   @Override
   public String toString() {
     return "{"
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
index b2e541a..3b11a28 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
@@ -37,11 +37,7 @@
  *   ITEM_REFERENCE  ::= BINDING_REFERENCE | ITEM_PATTERN
  *   CLASS_REFERENCE ::= BINDING_REFERENCE | QUALIFIED_CLASS_NAME_PATTERN
  *
- *   ITEM_PATTERN
- *     ::= any
- *       | ITEM_KIND class CLASS_REFERENCE extends EXTENDS_PATTERN { MEMBER_PATTERN }
- *
- *   ITEM_KIND ::= ONLY_CLASS | ONLY_MEMBERS | CLASS_AND_MEMBERS
+ *   ITEM_PATTERN ::= class CLASS_REFERENCE extends EXTENDS_PATTERN { MEMBER_PATTERN }
  *
  *   TYPE_PATTERN ::= any | exact type-descriptor
  *   PACKAGE_PATTERN ::= any | exact package-name
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemKind.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemKind.java
deleted file mode 100644
index 0d59769..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemKind.java
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) 2023, 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.ast;
-
-public enum KeepItemKind {
-  ONLY_CLASS,
-  ONLY_MEMBERS,
-  CLASS_AND_MEMBERS
-}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
index d81dde9..7634c68 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
@@ -6,7 +6,6 @@
 import com.android.tools.r8.keepanno.ast.KeepBindings.BindingSymbol;
 import java.util.Collection;
 import java.util.Objects;
-import java.util.function.Predicate;
 
 /**
  * A pattern for matching items in the program.
@@ -20,29 +19,28 @@
  */
 public class KeepItemPattern {
 
-  public static KeepItemPattern any() {
-    return builder().any().build();
+  public static KeepItemPattern anyClass() {
+    return builder().setMemberPattern(KeepMemberPattern.none()).build();
+  }
+
+  public static KeepItemPattern anyMember() {
+    return builder().setMemberPattern(KeepMemberPattern.allMembers()).build();
   }
 
   public static Builder builder() {
     return new Builder();
   }
 
-  public boolean isClassAndMemberPattern() {
-    return kind == KeepItemKind.CLASS_AND_MEMBERS;
-  }
-
   public boolean isClassItemPattern() {
-    return kind == KeepItemKind.ONLY_CLASS;
+    return memberPattern.isNone();
   }
 
   public boolean isMemberItemPattern() {
-    return kind == KeepItemKind.ONLY_MEMBERS;
+    return !isClassItemPattern();
   }
 
   public static class Builder {
 
-    private KeepItemKind kind = null;
     private KeepClassReference classReference =
         KeepClassReference.fromClassNamePattern(KeepQualifiedClassNamePattern.any());
     private KeepExtendsPattern extendsPattern = KeepExtendsPattern.any();
@@ -51,25 +49,11 @@
     private Builder() {}
 
     public Builder copyFrom(KeepItemPattern pattern) {
-      return setKind(pattern.getKind())
-          .setClassReference(pattern.getClassReference())
+      return setClassReference(pattern.getClassReference())
           .setExtendsPattern(pattern.getExtendsPattern())
           .setMemberPattern(pattern.getMemberPattern());
     }
 
-    public Builder any() {
-      kind = KeepItemKind.CLASS_AND_MEMBERS;
-      classReference = KeepClassReference.fromClassNamePattern(KeepQualifiedClassNamePattern.any());
-      extendsPattern = KeepExtendsPattern.any();
-      memberPattern = KeepMemberPattern.allMembers();
-      return this;
-    }
-
-    public Builder setKind(KeepItemKind kind) {
-      this.kind = kind;
-      return this;
-    }
-
     public Builder setClassReference(KeepClassReference classReference) {
       this.classReference = classReference;
       return this;
@@ -90,56 +74,27 @@
     }
 
     public KeepItemPattern build() {
-      if (kind == null) {
-        kind = memberPattern.isNone() ? KeepItemKind.ONLY_CLASS : KeepItemKind.ONLY_MEMBERS;
-      }
-      if (kind == KeepItemKind.ONLY_CLASS && !memberPattern.isNone()) {
-        throw new KeepEdgeException(
-            "Invalid kind ONLY_CLASS for item with member pattern: " + memberPattern);
-      }
-      if (kind == KeepItemKind.ONLY_MEMBERS && memberPattern.isNone()) {
-        throw new KeepEdgeException("Invalid kind ONLY_MEMBERS for item with no member pattern");
-      }
-      if (kind == KeepItemKind.CLASS_AND_MEMBERS && memberPattern.isNone()) {
-        throw new KeepEdgeException(
-            "Invalid kind CLASS_AND_MEMBERS for item with no member pattern");
-      }
-      return new KeepItemPattern(kind, classReference, extendsPattern, memberPattern);
+      return new KeepItemPattern(classReference, extendsPattern, memberPattern);
     }
   }
 
-  private final KeepItemKind kind;
   private final KeepClassReference classReference;
   private final KeepExtendsPattern extendsPattern;
   private final KeepMemberPattern memberPattern;
   // TODO: class annotations
 
   private KeepItemPattern(
-      KeepItemKind kind,
       KeepClassReference classReference,
       KeepExtendsPattern extendsPattern,
       KeepMemberPattern memberPattern) {
-    assert kind != null;
     assert classReference != null;
     assert extendsPattern != null;
     assert memberPattern != null;
-    this.kind = kind;
     this.classReference = classReference;
     this.extendsPattern = extendsPattern;
     this.memberPattern = memberPattern;
   }
 
-  public boolean isAny(Predicate<BindingSymbol> onReference) {
-    return kind.equals(KeepItemKind.CLASS_AND_MEMBERS)
-        && extendsPattern.isAny()
-        && memberPattern.isAllMembers()
-        && classReference.isAny(onReference);
-  }
-
-  public KeepItemKind getKind() {
-    return kind;
-  }
-
   public KeepClassReference getClassReference() {
     return classReference;
   }
@@ -157,37 +112,40 @@
   }
 
   @Override
-  @SuppressWarnings("EqualsGetClass")
   public boolean equals(Object obj) {
     if (this == obj) {
       return true;
     }
-    if (obj == null || getClass() != obj.getClass()) {
+    if (!(obj instanceof KeepItemPattern)) {
       return false;
     }
     KeepItemPattern that = (KeepItemPattern) obj;
-    return kind.equals(that.kind)
-        && classReference.equals(that.classReference)
+    return classReference.equals(that.classReference)
         && extendsPattern.equals(that.extendsPattern)
         && memberPattern.equals(that.memberPattern);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(kind, classReference, extendsPattern, memberPattern);
+    return Objects.hash(classReference, extendsPattern, memberPattern);
   }
 
   @Override
   public String toString() {
-    return "KeepClassPattern{"
-        + "kind="
-        + kind
-        + ", classReference="
-        + classReference
-        + ", extendsPattern="
-        + extendsPattern
-        + ", memberPattern="
-        + memberPattern
-        + '}';
+    StringBuilder builder = new StringBuilder();
+    if (isClassItemPattern()) {
+      builder.append("KeepClassPattern");
+    } else {
+      assert isMemberItemPattern();
+      builder.append("KeepMemberPattern");
+    }
+    builder.append("{ class=").append(classReference);
+    if (!extendsPattern.isAny()) {
+      builder.append(", extends=").append(extendsPattern);
+    }
+    if (!memberPattern.isNone()) {
+      builder.append(", members=").append(memberPattern);
+    }
+    return builder.append('}').toString();
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepEdgeNormalizer.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepEdgeNormalizer.java
index cf79e0f..9bd2c09 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepEdgeNormalizer.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepEdgeNormalizer.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.keepanno.ast.KeepCondition;
 import com.android.tools.r8.keepanno.ast.KeepConsequences;
 import com.android.tools.r8.keepanno.ast.KeepEdge;
-import com.android.tools.r8.keepanno.ast.KeepItemKind;
 import com.android.tools.r8.keepanno.ast.KeepItemPattern;
 import com.android.tools.r8.keepanno.ast.KeepItemReference;
 import com.android.tools.r8.keepanno.ast.KeepPreconditions;
@@ -119,10 +118,8 @@
 
   private KeepItemPattern getMemberItemPattern(
       KeepItemPattern fromPattern, KeepClassReference classReference) {
-    assert fromPattern.getKind().equals(KeepItemKind.ONLY_MEMBERS)
-        || fromPattern.getKind().equals(KeepItemKind.CLASS_AND_MEMBERS);
+    assert fromPattern.isMemberItemPattern();
     return KeepItemPattern.builder()
-        .setKind(fromPattern.getKind())
         .setClassReference(classReference)
         .setMemberPattern(fromPattern.getMemberPattern())
         .build();
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
index 3dffb77..5ad2ae3 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
@@ -297,15 +297,6 @@
     List<BindingSymbol> targetMembers = new ArrayList<>();
     for (BindingSymbol targetReference : targets) {
       KeepItemPattern item = bindings.get(targetReference).getItem();
-      if (bindings.isAny(item)) {
-        // If the target is "any item" then it contains any other target pattern.
-        memberPatterns.put(targetReference, item.getMemberPattern());
-        callback.accept(
-            memberPatterns,
-            Collections.singletonList(targetReference),
-            TargetKeepKind.CLASS_OR_MEMBERS);
-        return;
-      }
       if (item.isClassItemPattern()) {
         keepKind = TargetKeepKind.CLASS_AND_MEMBERS;
       } else {
diff --git a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
index 64f9378..602ee63 100644
--- a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
@@ -45,22 +45,34 @@
         KeepEdge.builder()
             .setConsequences(
                 KeepConsequences.builder()
-                    .addTarget(KeepTarget.builder().setItemPattern(KeepItemPattern.any()).build())
+                    .addTarget(
+                        KeepTarget.builder().setItemPattern(KeepItemPattern.anyClass()).build())
+                    .addTarget(
+                        KeepTarget.builder().setItemPattern(KeepItemPattern.anyMember()).build())
                     .build())
             .build();
-    assertEquals(StringUtils.unixLines("-keep class * { *; }"), extract(edge));
+    assertEquals(
+        StringUtils.unixLines(
+            "-keep class * { void finalize(); }", "-keepclassmembers class * { *; }"),
+        extract(edge));
   }
 
   @Test
   public void testSoftPinViaDisallow() {
+    KeepOptions disallowOptions = KeepOptions.disallow(KeepOption.OPTIMIZING);
     KeepEdge edge =
         KeepEdge.builder()
             .setConsequences(
                 KeepConsequences.builder()
                     .addTarget(
                         KeepTarget.builder()
-                            .setItemPattern(KeepItemPattern.any())
-                            .setOptions(KeepOptions.disallow(KeepOption.OPTIMIZING))
+                            .setItemPattern(KeepItemPattern.anyClass())
+                            .setOptions(disallowOptions)
+                            .build())
+                    .addTarget(
+                        KeepTarget.builder()
+                            .setItemPattern(KeepItemPattern.anyMember())
+                            .setOptions(disallowOptions)
                             .build())
                     .build())
             .build();
@@ -70,26 +82,37 @@
     String allows = String.join(",allow", options);
     // The "any" item will be split in two rules, one for the targeted types and one for the
     // targeted members.
-    assertEquals(StringUtils.unixLines("-keep,allow" + allows + " class * { *; }"), extract(edge));
+    assertEquals(
+        StringUtils.unixLines(
+            "-keep,allow" + allows + " class * { void finalize(); }",
+            "-keepclassmembers,allow" + allows + " class * { *; }"),
+        extract(edge));
   }
 
   @Test
   public void testSoftPinViaAllow() {
+    KeepOptions allowOptions = KeepOptions.allow(KeepOption.OBFUSCATING, KeepOption.SHRINKING);
     KeepEdge edge =
         KeepEdge.builder()
             .setConsequences(
                 KeepConsequences.builder()
                     .addTarget(
                         KeepTarget.builder()
-                            .setItemPattern(KeepItemPattern.any())
-                            .setOptions(
-                                KeepOptions.allow(KeepOption.OBFUSCATING, KeepOption.SHRINKING))
+                            .setItemPattern(KeepItemPattern.anyClass())
+                            .setOptions(allowOptions)
+                            .build())
+                    .addTarget(
+                        KeepTarget.builder()
+                            .setItemPattern(KeepItemPattern.anyMember())
+                            .setOptions(allowOptions)
                             .build())
                     .build())
             .build();
     // Allow is just the ordered list of options.
     assertEquals(
-        StringUtils.unixLines("-keep,allowshrinking,allowobfuscation class * { *; }"),
+        StringUtils.unixLines(
+            "-keep,allowshrinking,allowobfuscation class * { void finalize(); }",
+            "-keepclassmembers,allowshrinking,allowobfuscation class * { *; }"),
         extract(edge));
   }