Merge commit '61e65f473ce3ab4bc034feb4a8d43d5a3fffde44' into dev-release

Change-Id: Ifa158dd3b361a0103b94cd3fc31411d7dca4982f
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ContextDescriptor.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ContextDescriptor.java
index eceec17..fee72cc 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ContextDescriptor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ContextDescriptor.java
@@ -123,7 +123,7 @@
     }
     KeepMemberItemPattern memberItem =
         KeepMemberItemPattern.builder()
-            .setClassBindingReference(classBinding)
+            .setClassReference(classBinding)
             .setMemberPattern(memberPattern)
             .build();
     return bindingsHelper.defineFreshMemberBinding(memberItem);
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 641eb23..ad230d1 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
@@ -31,7 +31,6 @@
 import com.android.tools.r8.keepanno.ast.KeepCheck.KeepCheckKind;
 import com.android.tools.r8.keepanno.ast.KeepClassBindingReference;
 import com.android.tools.r8.keepanno.ast.KeepClassItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepClassItemReference;
 import com.android.tools.r8.keepanno.ast.KeepCondition;
 import com.android.tools.r8.keepanno.ast.KeepConsequences;
 import com.android.tools.r8.keepanno.ast.KeepConstraint;
@@ -471,7 +470,7 @@
                   KeepTypePattern.fromDescriptor(returnTypeDescriptor));
 
       return KeepMemberItemPattern.builder()
-          .setClassBindingReference(classReferenceFromName(className, bindingsHelper))
+          .setClassReference(classReferenceFromName(className, bindingsHelper))
           .setMemberPattern(
               KeepMethodPattern.builder()
                   .setNamePattern(KeepMethodNamePattern.exact(methodName))
@@ -608,7 +607,7 @@
       KeepFieldTypePattern typePattern =
           KeepFieldTypePattern.fromType(KeepTypePattern.fromDescriptor(fieldTypeDescriptor));
       return KeepMemberItemPattern.builder()
-          .setClassBindingReference(classReferenceFromName(className, bindingsHelper))
+          .setClassReference(classReferenceFromName(className, bindingsHelper))
           .setMemberPattern(
               KeepFieldPattern.builder()
                   .setNamePattern(KeepFieldNamePattern.exact(fieldName))
@@ -764,10 +763,8 @@
       return item.asMemberItemPattern();
     }
 
-    public KeepClassItemPattern getClassItemForReference(KeepClassItemReference itemReference) {
-      return itemReference.isBindingReference()
-          ? getItem(itemReference.asBindingReference()).asClassItemPattern()
-          : itemReference.asClassItemPattern();
+    public KeepClassItemPattern getClassItemForReference(KeepClassBindingReference itemReference) {
+      return getItem(itemReference).asClassItemPattern();
     }
 
     public KeepBindings build() {
@@ -920,7 +917,7 @@
           .setMetaInfo(metaInfo)
           .setKind(kind)
           .setBindings(bindingsHelper.build())
-          .setItemBindingReference(itemReference)
+          .setItemReference(itemReference)
           .build();
     }
   }
@@ -1061,7 +1058,7 @@
         KeepClassItemPattern classItemPattern = item.asClassItemPattern();
         if (classItemPattern == null) {
           assert item.isMemberItemPattern();
-          KeepClassItemReference classReference = item.asMemberItemPattern().getClassReference();
+          KeepClassBindingReference classReference = item.asMemberItemPattern().getClassReference();
           classItemPattern = bindingsHelper.getClassItemForReference(classReference);
         }
         String descriptor = KeepEdgeReaderUtils.getDescriptorFromClassTypeName(className);
@@ -1077,7 +1074,7 @@
         }
         consequences.addTarget(
             KeepTarget.builder()
-                .setItemBindingReference(bindingReference)
+                .setItemReference(bindingReference)
                 .setConstraints(defaultForApiConstraints)
                 .build());
       }
@@ -1114,33 +1111,12 @@
       this.parent = parent;
       addContext.accept(metaInfoBuilder);
       KeepMemberItemPattern context = contextBuilder.apply(bindingsHelper);
-      KeepClassItemReference classReference = context.getClassReference();
-      if (classReference.isBindingReference()) {
-        consequences.addTarget(
-            KeepTarget.builder()
-                .setItemBindingReference(bindingsHelper.defineFreshMemberBinding(context))
-                .build());
-        consequences.addTarget(
-            KeepTarget.builder()
-                .setItemBindingReference(classReference.asBindingReference())
-                .build());
-      } else {
-        // Create a binding for the context such that the class and member are shared.
-        KeepClassItemPattern classContext = classReference.asClassItemPattern();
-        KeepClassBindingReference classBindingReference =
-            bindingsHelper.defineFreshClassBinding(classContext);
-        consequences.addTarget(
-            KeepTarget.builder()
-                .setItemBindingReference(
-                    bindingsHelper.defineFreshMemberBinding(
-                        KeepMemberItemPattern.builder()
-                            .copyFrom(context)
-                            .setClassBindingReference(classBindingReference)
-                            .build()))
-                .build());
-        consequences.addTarget(
-            KeepTarget.builder().setItemBindingReference(classBindingReference).build());
-      }
+      KeepClassBindingReference classReference = context.getClassReference();
+      consequences.addTarget(
+          KeepTarget.builder()
+              .setItemReference(bindingsHelper.defineFreshMemberBinding(context))
+              .build());
+      consequences.addTarget(KeepTarget.builder().setItemReference(classReference).build());
     }
 
     @Override
@@ -1321,7 +1297,7 @@
         verifyItemStructure(bindingReference);
         consequences.addTarget(
             KeepTarget.builder()
-                .setItemBindingReference(bindingReference)
+                .setItemReference(bindingReference)
                 .setConstraints(
                     constraintsParser.getValueOrDefault(KeepConstraints.defaultConstraints()))
                 .build());
@@ -1443,7 +1419,7 @@
           KeepTarget.builder()
               .setConstraints(
                   constraintsParser.getValueOrDefault(KeepConstraints.defaultConstraints()))
-              .setItemBindingReference(contextBinding)
+              .setItemReference(contextBinding)
               .build());
       parent.accept(
           builder
@@ -1486,8 +1462,7 @@
       KeepItemPattern context = contextBuilder.apply(bindingsHelper);
       KeepBindingReference contextBinding =
           bindingsHelper.defineFreshItemBinding("CONTEXT", context);
-      preconditions.addCondition(
-          KeepCondition.builder().setItemBindingReference(contextBinding).build());
+      preconditions.addCondition(KeepCondition.builder().setItemReference(contextBinding).build());
       addContext.accept(metaInfoBuilder);
     }
 
@@ -1662,7 +1637,7 @@
               .setMetaInfo(metaInfoBuilder.build())
               .setKind(kind)
               .setBindings(itemVisitor.getBindingsHelper().build())
-              .setItemBindingReference(itemVisitor.getItemReference())
+              .setItemReference(itemVisitor.getItemReference())
               .build());
     }
   }
@@ -2157,23 +2132,13 @@
         return;
       }
 
-      KeepClassItemReference holderReference =
+      KeepClassBindingReference holderReference =
           getBindingsHelper().getItem(memberBinding).asMemberItemPattern().getClassReference();
       itemReferences =
           ImmutableList.of(ensureCorrectBindingForMemberHolder(holderReference), memberBinding);
     }
 
     private KeepClassBindingReference ensureCorrectBindingForMemberHolder(
-        KeepClassItemReference holderReference) {
-      if (holderReference.isBindingReference()) {
-        KeepClassBindingReference bindingReference =
-            holderReference.asBindingReference().asClassBindingReference();
-        return ensureCorrectBindingForMemberHolder(bindingReference);
-      }
-      return getBindingsHelper().defineFreshClassBinding(holderReference.asClassItemPattern());
-    }
-
-    private KeepClassBindingReference ensureCorrectBindingForMemberHolder(
         KeepClassBindingReference bindingReference) {
       return useBindingForClassAndMembers()
           ? bindingReference
@@ -2246,7 +2211,7 @@
           getBindingsHelper()
               .defineFreshMemberBinding(
                   KeepMemberItemPattern.builder()
-                      .setClassBindingReference(classReference)
+                      .setClassReference(classReference)
                       .setMemberPattern(memberPattern)
                       .build()));
       if (kind.includesClass()) {
@@ -2334,7 +2299,7 @@
       builder.setConstraints(
           constraintsParser.getValueOrDefault(KeepConstraints.defaultConstraints()));
       for (KeepBindingReference item : getItems()) {
-        parent.accept(builder.setItemBindingReference(item).build());
+        parent.accept(builder.setItemReference(item).build());
       }
     }
   }
@@ -2361,7 +2326,7 @@
     @Override
     public void visitEnd() {
       super.visitEnd();
-      parent.accept(KeepCondition.builder().setItemBindingReference(getItemReference()).build());
+      parent.accept(KeepCondition.builder().setItemReference(getItemReference()).build());
     }
   }
 
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 9151b1b..c1f8c13 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
@@ -25,8 +25,8 @@
 import com.android.tools.r8.keepanno.ast.KeepAnnotationPattern;
 import com.android.tools.r8.keepanno.ast.KeepBindingReference;
 import com.android.tools.r8.keepanno.ast.KeepBindings;
+import com.android.tools.r8.keepanno.ast.KeepClassBindingReference;
 import com.android.tools.r8.keepanno.ast.KeepClassItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepClassItemReference;
 import com.android.tools.r8.keepanno.ast.KeepConsequences;
 import com.android.tools.r8.keepanno.ast.KeepConstraint;
 import com.android.tools.r8.keepanno.ast.KeepConstraints;
@@ -38,7 +38,6 @@
 import com.android.tools.r8.keepanno.ast.KeepFieldPattern;
 import com.android.tools.r8.keepanno.ast.KeepInstanceOfPattern;
 import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepItemReference;
 import com.android.tools.r8.keepanno.ast.KeepMemberAccessPattern;
 import com.android.tools.r8.keepanno.ast.KeepMemberItemPattern;
 import com.android.tools.r8.keepanno.ast.KeepMemberPattern;
@@ -259,19 +258,10 @@
   }
 
   private void writeConstraints(
-      AnnotationVisitor visitor, KeepConstraints constraints, KeepItemReference item) {
+      AnnotationVisitor visitor, KeepConstraints constraints, KeepBindingReference item) {
     Set<KeepConstraint> typedConstraints;
-    if (item.isClassItemReference()) {
+    if (item.isClassType()) {
       typedConstraints = constraints.getClassConstraints();
-    } else if (item.isMemberItemPattern()) {
-      KeepMemberPattern memberPattern = item.asMemberItemPattern().getMemberPattern();
-      if (memberPattern.isMethod()) {
-        typedConstraints = constraints.getMethodConstraints();
-      } else if (memberPattern.isField()) {
-        typedConstraints = constraints.getFieldConstraints();
-      } else {
-        typedConstraints = constraints.getMemberConstraints();
-      }
     } else {
       typedConstraints = constraints.getMemberConstraints();
     }
@@ -340,15 +330,11 @@
     }
   }
 
-  private void writeItemReference(AnnotationVisitor visitor, KeepItemReference itemReference) {
-    if (itemReference.isBindingReference()) {
-      KeepBindingReference bindingReference = itemReference.asBindingReference();
-      String bindingProperty =
-          bindingReference.isClassType() ? Item.classFromBinding : Item.memberFromBinding;
-      visitor.visit(bindingProperty, bindingReference.getName().toString());
-    } else {
-      writeItem(visitor, itemReference.asItemPattern());
-    }
+  private void writeItemReference(
+      AnnotationVisitor visitor, KeepBindingReference bindingReference) {
+    String bindingProperty =
+        bindingReference.isClassType() ? Item.classFromBinding : Item.memberFromBinding;
+    visitor.visit(bindingProperty, bindingReference.getName().toString());
   }
 
   private void writeItem(AnnotationVisitor itemVisitor, KeepItemPattern item) {
@@ -386,13 +372,8 @@
 
   private void writeMemberItem(
       KeepMemberItemPattern memberItemPattern, AnnotationVisitor itemVisitor) {
-    KeepClassItemReference classReference = memberItemPattern.getClassReference();
-    if (classReference.isBindingReference()) {
-      KeepBindingReference bindingReference = classReference.asBindingReference();
-      itemVisitor.visit(Item.classFromBinding, bindingReference.getName().toString());
-    } else {
-      writeClassItem(classReference.asClassItemPattern(), itemVisitor);
-    }
+    KeepClassBindingReference bindingReference = memberItemPattern.getClassReference();
+    itemVisitor.visit(Item.classFromBinding, bindingReference.getName().toString());
     writeMember(memberItemPattern.getMemberPattern(), itemVisitor);
   }
 
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingReference.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingReference.java
index 6097e39..481a6f2 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingReference.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingReference.java
@@ -5,6 +5,9 @@
 package com.android.tools.r8.keepanno.ast;
 
 import com.android.tools.r8.keepanno.ast.KeepBindings.KeepBindingSymbol;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 public abstract class KeepBindingReference {
 
@@ -26,8 +29,6 @@
     this.name = name;
   }
 
-  public abstract KeepItemReference toItemReference();
-
   public KeepBindingSymbol getName() {
     return name;
   }
@@ -48,8 +49,40 @@
     return null;
   }
 
+  public final <T> T apply(
+      Function<KeepClassBindingReference, T> onClass,
+      Function<KeepMemberBindingReference, T> onMember) {
+    if (isClassType()) {
+      return onClass.apply(asClassBindingReference());
+    }
+    assert isMemberType();
+    return onMember.apply(asMemberBindingReference());
+  }
+
+  public final void match(
+      Consumer<KeepClassBindingReference> onClass, Consumer<KeepMemberBindingReference> onMember) {
+    apply(AstUtils.toVoidFunction(onClass), AstUtils.toVoidFunction(onMember));
+  }
+
   @Override
   public String toString() {
     return name.toString();
   }
+
+  @Override
+  public final boolean equals(Object obj) {
+    if (obj == this) {
+      return true;
+    }
+    if (!(obj instanceof KeepBindingReference)) {
+      return false;
+    }
+    KeepBindingReference other = (KeepBindingReference) obj;
+    return isClassType() == other.isClassType() && name.equals(other.name);
+  }
+
+  @Override
+  public final int hashCode() {
+    return Objects.hash(isClassType(), name);
+  }
 }
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 46ee664..4df258d 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
@@ -3,8 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.keepanno.ast;
 
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
@@ -39,6 +37,34 @@
     return bindings.get(bindingReference);
   }
 
+  public KeepClassItemPattern getClassItem(KeepClassBindingReference reference) {
+    KeepBindingSymbol symbol = reference.getName();
+    Binding binding = get(symbol);
+    if (binding == null) {
+      throw new KeepEdgeException("Unbound binding for reference '" + symbol + "'");
+    }
+    KeepItemPattern item = binding.getItem();
+    if (!item.isClassItemPattern()) {
+      throw new KeepEdgeException(
+          "Attempt to get class item from non-class binding '" + symbol + "'");
+    }
+    return item.asClassItemPattern();
+  }
+
+  public KeepMemberItemPattern getMemberItem(KeepMemberBindingReference reference) {
+    KeepBindingSymbol symbol = reference.getName();
+    Binding binding = get(symbol);
+    if (binding == null) {
+      throw new KeepEdgeException("Unbound binding for reference '" + symbol + "'");
+    }
+    KeepItemPattern item = binding.getItem();
+    if (!item.isMemberItemPattern()) {
+      throw new KeepEdgeException(
+          "Attempt to get member item from non-member binding '" + symbol + "'");
+    }
+    return item.asMemberItemPattern();
+  }
+
   public int size() {
     return bindings.size();
   }
@@ -59,28 +85,6 @@
             .collect(Collectors.joining(", "));
   }
 
-  public void verify(KeepItemReference... references) {
-    verify(Arrays.asList(references));
-  }
-
-  public void verify(Collection<KeepItemReference> references) {
-    for (KeepItemReference reference : references) {
-      if (reference.isBindingReference()) {
-        KeepBindingReference bindingReference = reference.asBindingReference();
-        if (!bindings.containsKey(bindingReference.getName())) {
-          throw new KeepEdgeException("Unbound reference to " + bindingReference);
-        }
-      } else {
-        KeepItemPattern itemPattern = reference.asItemPattern();
-        for (KeepBindingReference bindingReference : itemPattern.getBindingReferences()) {
-          if (!bindings.containsKey(bindingReference.getName())) {
-            throw new KeepEdgeException("Unbound reference to " + bindingReference);
-          }
-        }
-      }
-    }
-  }
-
   /**
    * A unique binding.
    *
@@ -223,7 +227,6 @@
       return bindings.get(symbol);
     }
 
-    @SuppressWarnings("ReferenceEquality")
     public KeepBindings build() {
       if (bindings.isEmpty()) {
         return NONE_INSTANCE;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingsNormalizer.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingsNormalizer.java
new file mode 100644
index 0000000..f4fc861
--- /dev/null
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepBindingsNormalizer.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2024, 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;
+
+import com.android.tools.r8.keepanno.ast.KeepBindings.Binding;
+import com.android.tools.r8.keepanno.ast.KeepBindings.KeepBindingSymbol;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+/**
+ * Verify and normalize a set of bindings.
+ *
+ * <p>This does a few things as part of normalization:
+ *
+ * <ul>
+ *   <li>It verifies that bindings are defined and type correct (no member-reference of a class
+ *       binding).
+ *   <li>It replaces class-references to members by a reference to the member's holder class.
+ *   <li>It removes unused bindings.
+ * </ul>
+ */
+public class KeepBindingsNormalizer {
+
+  public static KeepBindingsNormalizer create(KeepBindings bindings) {
+    return new KeepBindingsNormalizer(bindings);
+  }
+
+  private KeepBindings bindings;
+
+  // Set of bindings that are used via 'register'. Building the final bindings will trim down
+  // the actual bindings based on this set.
+  private final Set<KeepBindingSymbol> used = new HashSet<>();
+
+  // Bit to track if any references are actually updated.
+  // If not, then rebuilding can be avoided.
+  private boolean replacedReferences = false;
+
+  private KeepBindingsNormalizer(KeepBindings bindings) {
+    this.bindings = bindings;
+  }
+
+  /* True if any binding reference needed to be changed. */
+  public boolean didReplaceReferences() {
+    return replacedReferences;
+  }
+
+  public KeepBindings buildBindings() {
+    // Fast path will typically use all bindings.
+    if (bindings.size() == used.size()) {
+      return bindings;
+    }
+    KeepBindings.Builder builder = KeepBindings.builder();
+    for (KeepBindingSymbol symbol : used) {
+      builder.addBinding(symbol, bindings.get(symbol).getItem());
+    }
+    // Guard against use after building.
+    bindings = null;
+    return builder.build();
+  }
+
+  public <T> T registerAndNormalizeReference(
+      KeepBindingReference reference,
+      T defaultValue,
+      BiFunction<KeepBindingReference, T, T> newValueBuilder) {
+    KeepBindingSymbol symbol = reference.getName();
+    Binding binding = bindings.get(symbol);
+    if (binding == null) {
+      throw new KeepEdgeException("Unbound reference to '" + symbol + "'");
+    }
+    KeepItemPattern item = binding.getItem();
+    KeepMemberItemPattern memberItem = item.asMemberItemPattern();
+    // Mark the binding as used and if it is a member also mark its class as used.
+    used.add(symbol);
+    if (memberItem != null) {
+      used.add(memberItem.getClassReference().getName());
+    }
+    T value = defaultValue;
+    if (reference.isClassType() && memberItem != null) {
+      // A class-type reference is allowed to reference a member-typed binding.
+      // In this case, the normalized reference is to the class of the member.
+      KeepClassBindingReference classReference = memberItem.getClassReference();
+      value = newValueBuilder.apply(classReference, defaultValue);
+      replacedReferences = true;
+    } else if (reference.isMemberType() && item.isClassItemPattern()) {
+      throw new KeepEdgeException(
+          "Invalid member-reference the class-type binding '" + symbol + "'");
+    }
+    return value;
+  }
+}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCheck.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCheck.java
index 4c21cad..d29459f 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCheck.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCheck.java
@@ -15,7 +15,7 @@
     private KeepEdgeMetaInfo metaInfo = KeepEdgeMetaInfo.none();
     private KeepCheckKind kind = KeepCheckKind.REMOVED;
     private KeepBindings bindings = KeepBindings.none();
-    private KeepItemReference itemReference;
+    private KeepBindingReference itemReference;
 
     public Builder setMetaInfo(KeepEdgeMetaInfo metaInfo) {
       this.metaInfo = metaInfo;
@@ -32,12 +32,7 @@
       return this;
     }
 
-    public Builder setItemBindingReference(KeepBindingReference bindingReference) {
-      this.itemReference = bindingReference.toItemReference();
-      return this;
-    }
-
-    public Builder setItemReference(KeepItemReference itemReference) {
+    public Builder setItemReference(KeepBindingReference itemReference) {
       this.itemReference = itemReference;
       return this;
     }
@@ -46,8 +41,15 @@
       if (itemReference == null) {
         throw new KeepEdgeException("KeepCheck must have an item pattern.");
       }
-      bindings.verify(itemReference);
-      return new KeepCheck(metaInfo, kind, bindings, itemReference);
+
+      KeepBindingsNormalizer normalizer = KeepBindingsNormalizer.create(bindings);
+      itemReference =
+          normalizer.registerAndNormalizeReference(
+              itemReference,
+              itemReference,
+              (newItemReference, oldItemReference) -> newItemReference);
+
+      return new KeepCheck(metaInfo, kind, normalizer.buildBindings(), itemReference);
     }
   }
 
@@ -58,13 +60,13 @@
   private final KeepEdgeMetaInfo metaInfo;
   private final KeepCheckKind kind;
   private final KeepBindings bindings;
-  private final KeepItemReference itemReference;
+  private final KeepBindingReference itemReference;
 
   private KeepCheck(
       KeepEdgeMetaInfo metaInfo,
       KeepCheckKind kind,
       KeepBindings bindings,
-      KeepItemReference itemReference) {
+      KeepBindingReference itemReference) {
     this.metaInfo = metaInfo;
     this.kind = kind;
     this.bindings = bindings;
@@ -88,15 +90,8 @@
     return bindings;
   }
 
-  public KeepItemReference getItemReference() {
-    return itemReference;
-  }
-
   public KeepItemPattern getItemPattern() {
-    if (itemReference.isBindingReference()) {
-      return bindings.get(itemReference.asBindingReference()).getItem();
-    }
-    return itemReference.asItemPattern();
+    return bindings.get(itemReference).getItem();
   }
 
   @Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassBindingReference.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassBindingReference.java
index 19fc080..3760b3a 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassBindingReference.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassBindingReference.java
@@ -17,15 +17,6 @@
     return this;
   }
 
-  public KeepClassItemReference toClassItemReference() {
-    return KeepClassItemReference.fromBindingReference(this);
-  }
-
-  @Override
-  public KeepItemReference toItemReference() {
-    return toClassItemReference();
-  }
-
   @Override
   public String toString() {
     return "class-ref(" + super.toString() + ")";
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemReference.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemReference.java
deleted file mode 100644
index b912471..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemReference.java
+++ /dev/null
@@ -1,78 +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;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-public abstract class KeepClassItemReference extends KeepItemReference {
-
-  public static KeepClassItemReference fromBindingReference(
-      KeepClassBindingReference bindingReference) {
-    return new ClassBinding(bindingReference);
-  }
-
-  @Override
-  public final KeepClassItemReference asClassItemReference() {
-    return this;
-  }
-
-  public final <T> T applyClassItemReference(
-      Function<KeepBindingReference, T> onBinding, Function<KeepClassItemPattern, T> onPattern) {
-    if (isBindingReference()) {
-      return onBinding.apply(asBindingReference());
-    }
-    return onPattern.apply(asClassItemPattern());
-  }
-
-  public final void matchClassItemReference(
-      Consumer<KeepBindingReference> onBinding, Consumer<KeepClassItemPattern> onPattern) {
-    applyClassItemReference(AstUtils.toVoidFunction(onBinding), AstUtils.toVoidFunction(onPattern));
-  }
-
-  public abstract Collection<KeepBindingReference> getBindingReferences();
-
-  private static class ClassBinding extends KeepClassItemReference {
-    private final KeepClassBindingReference bindingReference;
-
-    private ClassBinding(KeepClassBindingReference bindingReference) {
-      assert bindingReference != null;
-      this.bindingReference = bindingReference;
-    }
-
-    @Override
-    public KeepClassBindingReference asBindingReference() {
-      return bindingReference;
-    }
-
-    @Override
-    public Collection<KeepBindingReference> getBindingReferences() {
-      return Collections.singletonList(bindingReference);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (!(o instanceof ClassBinding)) {
-        return false;
-      }
-      ClassBinding that = (ClassBinding) o;
-      return bindingReference.equals(that.bindingReference);
-    }
-
-    @Override
-    public int hashCode() {
-      return bindingReference.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return bindingReference.toString();
-    }
-  }
-}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCondition.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCondition.java
index b4aa28a..96c0f4d 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCondition.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepCondition.java
@@ -19,16 +19,11 @@
 
   public static class Builder {
 
-    private KeepItemReference item;
+    private KeepBindingReference item;
 
     private Builder() {}
 
-    public Builder setItemBindingReference(KeepBindingReference item) {
-      this.item = item.toItemReference();
-      return this;
-    }
-
-    public Builder setItemReference(KeepItemReference item) {
+    public Builder setItemReference(KeepBindingReference item) {
       this.item = item;
       return this;
     }
@@ -38,14 +33,14 @@
     }
   }
 
-  private final KeepItemReference item;
+  private final KeepBindingReference item;
 
-  private KeepCondition(KeepItemReference item) {
+  private KeepCondition(KeepBindingReference item) {
     assert item != null;
     this.item = item;
   }
 
-  public KeepItemReference getItem() {
+  public KeepBindingReference getItem() {
     return item;
   }
 
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 607d981..6a741ce 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
@@ -175,7 +175,36 @@
       if (consequences.isEmpty()) {
         throw new KeepEdgeException("KeepEdge must have non-empty set of consequences.");
       }
-      return new KeepEdge(metaInfo, bindings, preconditions, consequences);
+      KeepBindingsNormalizer normalizer = KeepBindingsNormalizer.create(bindings);
+
+      KeepPreconditions.Builder preconditionsBuilder = KeepPreconditions.builder();
+      preconditions.forEach(
+          condition ->
+              preconditionsBuilder.addCondition(
+                  normalizer.registerAndNormalizeReference(
+                      condition.getItem(),
+                      condition,
+                      (newReference, oldCondition) ->
+                          KeepCondition.builder().setItemReference(newReference).build())));
+
+      KeepConsequences.Builder consequencesBuilder = KeepConsequences.builder();
+      consequences.forEachTarget(
+          target ->
+              consequencesBuilder.addTarget(
+                  normalizer.registerAndNormalizeReference(
+                      target.getItem(),
+                      target,
+                      (newReference, oldTarget) ->
+                          KeepTarget.builder()
+                              .setConstraints(oldTarget.getConstraints())
+                              .setItemReference(newReference)
+                              .build())));
+
+      return new KeepEdge(
+          metaInfo,
+          normalizer.buildBindings(),
+          normalizer.didReplaceReferences() ? preconditionsBuilder.build() : preconditions,
+          normalizer.didReplaceReferences() ? consequencesBuilder.build() : consequences);
     }
   }
 
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemReference.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemReference.java
deleted file mode 100644
index d17f6ee..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemReference.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2022, 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;
-
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/**
- * A reference to an item pattern.
- *
- * <p>A reference can either be a binding-reference to an item pattern or the item pattern itself.
- */
-public abstract class KeepItemReference {
-
-  public final boolean isClassItemReference() {
-    return asClassItemReference() != null;
-  }
-
-  public final boolean isMemberItemReference() {
-    return asMemberItemReference() != null;
-  }
-
-  public KeepClassItemReference asClassItemReference() {
-    return null;
-  }
-
-  public KeepMemberItemReference asMemberItemReference() {
-    return null;
-  }
-
-  // Helpers below.
-
-  /* Returns true if the reference is a binding to a class or member. */
-  public final boolean isBindingReference() {
-    return asBindingReference() != null;
-  }
-
-  /* Returns true if the reference is an item pattern for a class or member. */
-  public final boolean isItemPattern() {
-    return asItemPattern() != null;
-  }
-
-  public final boolean isClassItemPattern() {
-    return asClassItemPattern() != null;
-  }
-
-  public final boolean isMemberItemPattern() {
-    return asMemberItemPattern() != null;
-  }
-
-  public KeepBindingReference asBindingReference() {
-    return null;
-  }
-
-  public KeepItemPattern asItemPattern() {
-    return null;
-  }
-
-  public KeepClassItemPattern asClassItemPattern() {
-    return null;
-  }
-
-  public KeepMemberItemPattern asMemberItemPattern() {
-    return null;
-  }
-
-  public <T> T apply(
-      Function<KeepBindingReference, T> onBinding, Function<KeepItemPattern, T> onItem) {
-    if (isBindingReference()) {
-      return onBinding.apply(asBindingReference());
-    }
-    assert isItemPattern();
-    return onItem.apply(asItemPattern());
-  }
-
-  public void match(Consumer<KeepBindingReference> onBinding, Consumer<KeepItemPattern> onItem) {
-    apply(AstUtils.toVoidFunction(onBinding), AstUtils.toVoidFunction(onItem));
-  }
-}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberBindingReference.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberBindingReference.java
index a79578f..1fb3ea1 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberBindingReference.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberBindingReference.java
@@ -18,15 +18,6 @@
   }
 
   @Override
-  public KeepItemReference toItemReference() {
-    return KeepMemberItemReference.fromBindingReference(this);
-  }
-
-  public KeepMemberItemReference toMemberItemReference() {
-    return KeepMemberItemReference.fromBindingReference(this);
-  }
-
-  @Override
   public String toString() {
     return "member-ref(" + super.toString() + ")";
   }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemPattern.java
index 3fbe013..0c22c66 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemPattern.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.keepanno.ast;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Objects;
 
 public class KeepMemberItemPattern extends KeepItemPattern {
@@ -15,7 +16,7 @@
 
   public static class Builder {
 
-    private KeepClassItemReference classReference = null;
+    private KeepClassBindingReference classReference = null;
     private KeepMemberPattern memberPattern = KeepMemberPattern.allMembers();
 
     private Builder() {}
@@ -25,12 +26,7 @@
           .setMemberPattern(pattern.getMemberPattern());
     }
 
-    public Builder setClassBindingReference(KeepClassBindingReference classReference) {
-      this.classReference = classReference.toClassItemReference();
-      return this;
-    }
-
-    public Builder setClassReference(KeepClassItemReference classReference) {
+    public Builder setClassReference(KeepClassBindingReference classReference) {
       this.classReference = classReference;
       return this;
     }
@@ -49,11 +45,11 @@
     }
   }
 
-  private final KeepClassItemReference classReference;
+  private final KeepClassBindingReference classReference;
   private final KeepMemberPattern memberPattern;
 
   private KeepMemberItemPattern(
-      KeepClassItemReference classReference, KeepMemberPattern memberPattern) {
+      KeepClassBindingReference classReference, KeepMemberPattern memberPattern) {
     assert classReference != null;
     assert memberPattern != null;
     this.classReference = classReference;
@@ -65,7 +61,7 @@
     return this;
   }
 
-  public KeepClassItemReference getClassReference() {
+  public KeepClassBindingReference getClassReference() {
     return classReference;
   }
 
@@ -74,7 +70,7 @@
   }
 
   public Collection<KeepBindingReference> getBindingReferences() {
-    return classReference.getBindingReferences();
+    return Collections.singletonList(classReference);
   }
 
   @Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemReference.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemReference.java
deleted file mode 100644
index aa71f27..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberItemReference.java
+++ /dev/null
@@ -1,37 +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 abstract class KeepMemberItemReference extends KeepItemReference {
-
-  public static KeepMemberItemReference fromBindingReference(
-      KeepMemberBindingReference bindingReference) {
-    return new MemberBinding(bindingReference);
-  }
-
-  @Override
-  public final KeepMemberItemReference asMemberItemReference() {
-    return this;
-  }
-
-  private static final class MemberBinding extends KeepMemberItemReference {
-
-    private final KeepMemberBindingReference bindingReference;
-
-    private MemberBinding(KeepMemberBindingReference bindingReference) {
-      this.bindingReference = bindingReference;
-    }
-
-    @Override
-    public KeepBindingReference asBindingReference() {
-      return bindingReference;
-    }
-
-    @Override
-    public String toString() {
-      return bindingReference.toString();
-    }
-  }
-}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java
index cbf039e..0d7dc03 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java
@@ -9,18 +9,13 @@
 
   public static class Builder {
 
-    private KeepItemReference item;
+    private KeepBindingReference item;
     private KeepConstraints constraints = KeepConstraints.defaultConstraints();
 
     private Builder() {}
 
-    public Builder setItemBindingReference(KeepBindingReference reference) {
-      this.item = reference.toItemReference();
-      return this;
-    }
-
-    public Builder setItemReference(KeepItemReference item) {
-      this.item = item;
+    public Builder setItemReference(KeepBindingReference itemReference) {
+      this.item = itemReference;
       return this;
     }
 
@@ -37,10 +32,10 @@
     }
   }
 
-  private final KeepItemReference item;
+  private final KeepBindingReference item;
   private final KeepConstraints constraints;
 
-  private KeepTarget(KeepItemReference item, KeepConstraints constraints) {
+  private KeepTarget(KeepBindingReference item, KeepConstraints constraints) {
     assert item != null;
     assert constraints != null;
     this.item = item;
@@ -51,7 +46,7 @@
     return new Builder();
   }
 
-  public KeepItemReference getItem() {
+  public KeepBindingReference getItem() {
     return item;
   }
 
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
deleted file mode 100644
index 9806026..0000000
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepEdgeNormalizer.java
+++ /dev/null
@@ -1,131 +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.keeprules;
-
-import com.android.tools.r8.keepanno.ast.KeepBindingReference;
-import com.android.tools.r8.keepanno.ast.KeepBindings;
-import com.android.tools.r8.keepanno.ast.KeepBindings.KeepBindingSymbol;
-import com.android.tools.r8.keepanno.ast.KeepClassItemReference;
-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.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepItemReference;
-import com.android.tools.r8.keepanno.ast.KeepMemberItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepPreconditions;
-import com.android.tools.r8.keepanno.ast.KeepTarget;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Normalize a keep edge with respect to its bindings. This will systematically introduce a binding
- * for each item in the edge. It will also introduce a class binding for the holder of any member
- * item. By introducing a binding for each item the binding can be used as item identity.
- */
-public class KeepEdgeNormalizer {
-
-  private static final String syntheticBindingPrefix = "SyntheticBinding";
-
-  public static KeepEdge normalize(KeepEdge edge) {
-    // Check that all referenced bindings are defined.
-    KeepEdgeNormalizer normalizer = new KeepEdgeNormalizer(edge);
-    return normalizer.run();
-  }
-
-  private final KeepEdge edge;
-
-  private final Map<KeepBindingSymbol, KeepItemPattern> normalizedUserBindings = new HashMap<>();
-  private final KeepBindings.Builder bindingsBuilder = KeepBindings.builder();
-  private final KeepPreconditions.Builder preconditionsBuilder = KeepPreconditions.builder();
-  private final KeepConsequences.Builder consequencesBuilder = KeepConsequences.builder();
-
-  private KeepEdgeNormalizer(KeepEdge edge) {
-    this.edge = edge;
-  }
-
-  private KeepEdge run() {
-    edge.getBindings()
-        .forEach(
-            (name, pattern) -> {
-              KeepItemPattern normalizedItem = normalizeItemPattern(pattern);
-              bindingsBuilder.addBinding(name, normalizedItem);
-              normalizedUserBindings.put(name, normalizedItem);
-            });
-    // TODO(b/248408342): Normalize the preconditions by identifying vacuously true conditions.
-    edge.getPreconditions()
-        .forEach(
-            condition ->
-                preconditionsBuilder.addCondition(
-                    KeepCondition.builder()
-                        .setItemReference(normalizeItemReference(condition.getItem()))
-                        .build()));
-    edge.getConsequences()
-        .forEachTarget(
-            target -> {
-              consequencesBuilder.addTarget(
-                  KeepTarget.builder()
-                      .setConstraints(target.getConstraints())
-                      .setItemReference(normalizeItemReference(target.getItem()))
-                      .build());
-            });
-    return KeepEdge.builder()
-        .setMetaInfo(edge.getMetaInfo())
-        .setBindings(bindingsBuilder.build())
-        .setPreconditions(preconditionsBuilder.build())
-        .setConsequences(consequencesBuilder.build())
-        .build();
-  }
-
-  private KeepBindingSymbol synthesizeFreshBindingSymbol(KeepItemPattern item) {
-    KeepBindingSymbol bindingName = bindingsBuilder.generateFreshSymbol(syntheticBindingPrefix);
-    bindingsBuilder.addBinding(bindingName, item);
-    return bindingName;
-  }
-
-  private KeepBindingReference synthesizeFreshBindingReference(KeepItemPattern item) {
-    KeepBindingSymbol bindingName = synthesizeFreshBindingSymbol(item);
-    return KeepBindingReference.forItem(bindingName, item);
-  }
-
-  private KeepItemReference normalizeItemReference(KeepItemReference item) {
-    if (item.isBindingReference()) {
-      KeepBindingReference bindingReference = item.asBindingReference();
-      if (bindingReference.isClassType()) {
-        // A class-type reference is allowed to reference a member-typed binding.
-        // In this case, the normalized reference is to the class of the member.
-        KeepItemPattern boundItemPattern = normalizedUserBindings.get(bindingReference.getName());
-        if (boundItemPattern.isMemberItemPattern()) {
-          return boundItemPattern.asMemberItemPattern().getClassReference();
-        }
-      }
-      return item;
-    }
-    KeepItemPattern newItemPattern = normalizeItemPattern(item.asItemPattern());
-    return synthesizeFreshBindingReference(newItemPattern).toItemReference();
-  }
-
-  private KeepItemPattern normalizeItemPattern(KeepItemPattern pattern) {
-    if (pattern.isClassItemPattern()) {
-      // If the pattern is just a class pattern it is in normal form.
-      return pattern;
-    }
-    return normalizeMemberItemPattern(pattern.asMemberItemPattern());
-  }
-
-  private KeepMemberItemPattern normalizeMemberItemPattern(
-      KeepMemberItemPattern memberItemPattern) {
-    KeepClassItemReference classReference = memberItemPattern.getClassReference();
-    if (classReference.isBindingReference()) {
-      // If the class is already defined via a binding then no need to introduce a new one and
-      // change the member item pattern.
-      return memberItemPattern;
-    }
-    KeepBindingSymbol bindingName =
-        synthesizeFreshBindingSymbol(classReference.asClassItemPattern());
-    return KeepMemberItemPattern.builder()
-        .copyFrom(memberItemPattern)
-        .setClassReference(KeepBindingReference.forClass(bindingName).toClassItemReference())
-        .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 3a618c9..585eee6 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
@@ -10,19 +10,17 @@
 import com.android.tools.r8.keepanno.ast.KeepBindings.KeepBindingSymbol;
 import com.android.tools.r8.keepanno.ast.KeepCheck;
 import com.android.tools.r8.keepanno.ast.KeepCheck.KeepCheckKind;
+import com.android.tools.r8.keepanno.ast.KeepClassBindingReference;
 import com.android.tools.r8.keepanno.ast.KeepClassItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepClassItemReference;
 import com.android.tools.r8.keepanno.ast.KeepCondition;
 import com.android.tools.r8.keepanno.ast.KeepConstraints;
 import com.android.tools.r8.keepanno.ast.KeepDeclaration;
 import com.android.tools.r8.keepanno.ast.KeepEdge;
-import com.android.tools.r8.keepanno.ast.KeepEdgeException;
 import com.android.tools.r8.keepanno.ast.KeepEdgeMetaInfo;
 import com.android.tools.r8.keepanno.ast.KeepFieldAccessPattern;
 import com.android.tools.r8.keepanno.ast.KeepFieldPattern;
 import com.android.tools.r8.keepanno.ast.KeepInstanceOfPattern;
 import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepItemReference;
 import com.android.tools.r8.keepanno.ast.KeepMemberItemPattern;
 import com.android.tools.r8.keepanno.ast.KeepMemberPattern;
 import com.android.tools.r8.keepanno.ast.KeepMethodAccessPattern;
@@ -36,11 +34,8 @@
 import com.android.tools.r8.keepanno.keeprules.PgRule.PgKeepAttributeRule;
 import com.android.tools.r8.keepanno.keeprules.PgRule.PgUnconditionalRule;
 import com.android.tools.r8.keepanno.keeprules.PgRule.TargetKeepKind;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -79,7 +74,7 @@
     if (declaration.isKeepCheck()) {
       return generateCheckRules(declaration.asKeepCheck());
     }
-    return doSplit(KeepEdgeNormalizer.normalize(declaration.asKeepEdge()));
+    return doSplit(declaration.asKeepEdge());
   }
 
   private List<PgRule> generateCheckRules(KeepCheck check) {
@@ -101,16 +96,10 @@
       targetMembers = Collections.emptyList();
     } else {
       KeepMemberItemPattern memberItemPattern = itemPattern.asMemberItemPattern();
-      KeepClassItemReference classReference = memberItemPattern.getClassReference();
-      if (classReference.isClassItemPattern()) {
-        symbol = builder.generateFreshSymbol("CLASS");
-        builder.addBinding(symbol, classReference.asClassItemPattern());
-      } else {
-        KeepBindingReference bindingReference = classReference.asBindingReference();
-        Binding binding = check.getBindings().get(bindingReference);
-        symbol = bindingReference.getName();
-        builder.addBinding(symbol, binding.getItem());
-      }
+      KeepClassBindingReference classReference = memberItemPattern.getClassReference();
+      Binding binding = check.getBindings().get(classReference);
+      symbol = classReference.getName();
+      builder.addBinding(symbol, binding.getItem());
       KeepMemberPattern memberPattern = memberItemPattern.getMemberPattern();
       // This does not actually allocate a binding as the mapping is maintained in 'memberPatterns'.
       KeepBindingSymbol memberSymbol = new KeepBindingSymbol("MEMBERS");
@@ -255,17 +244,14 @@
     }
 
     public void addCondition(KeepCondition condition) {
-      assert condition.getItem().isBindingReference();
-      conditionRefs.add(condition.getItem().asBindingReference().getName());
+      conditionRefs.add(condition.getItem().getName());
     }
 
     public void addTarget(KeepTarget target) {
-      assert target.getItem().isBindingReference();
       KeepConstraints constraints = target.getConstraints();
       KeepOptions options = constraints.convertToKeepOptions(defaultOptions);
-      targetRefs
-          .computeIfAbsent(options, k -> new HashSet<>())
-          .add(target.getItem().asBindingReference().getName());
+      KeepBindingReference bindingReference = target.getItem();
+      targetRefs.computeIfAbsent(options, k -> new HashSet<>()).add(bindingReference.getName());
     }
   }
 
@@ -587,42 +573,9 @@
   }
 
   private static KeepBindingSymbol getClassItemBindingReference(
-      KeepItemReference itemReference, KeepBindings bindings) {
-    KeepBindingSymbol classReference = null;
-    for (KeepBindingSymbol reference : getTransitiveBindingReferences(itemReference, bindings)) {
-      if (bindings.get(reference).getItem().isClassItemPattern()) {
-        if (classReference != null) {
-          throw new KeepEdgeException("Unexpected reference to multiple class bindings");
-        }
-        classReference = reference;
-      }
-    }
-    return classReference;
-  }
-
-  private static Set<KeepBindingSymbol> getTransitiveBindingReferences(
-      KeepItemReference itemReference, KeepBindings bindings) {
-    Set<KeepBindingSymbol> symbols = new HashSet<>(2);
-    Deque<KeepBindingReference> worklist = new ArrayDeque<>();
-    worklist.addAll(getBindingReference(itemReference));
-    while (!worklist.isEmpty()) {
-      KeepBindingReference bindingReference = worklist.pop();
-      if (symbols.add(bindingReference.getName())) {
-        worklist.addAll(getBindingReference(bindings.get(bindingReference).getItem()));
-      }
-    }
-    return symbols;
-  }
-
-  private static Collection<KeepBindingReference> getBindingReference(
-      KeepItemReference itemReference) {
-    if (itemReference.isBindingReference()) {
-      return Collections.singletonList(itemReference.asBindingReference());
-    }
-    return getBindingReference(itemReference.asItemPattern());
-  }
-
-  private static Collection<KeepBindingReference> getBindingReference(KeepItemPattern itemPattern) {
-    return itemPattern.getBindingReferences();
+      KeepBindingReference itemReference, KeepBindings bindings) {
+    return itemReference.apply(
+        KeepBindingReference::getName,
+        member -> bindings.getMemberItem(member).getClassReference().getName());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
index fb47d43..dea79c9 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
@@ -37,7 +37,6 @@
 import com.android.tools.r8.keepanno.ast.KeepDeclaration;
 import com.android.tools.r8.keepanno.ast.KeepEdge;
 import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepItemReference;
 import com.android.tools.r8.keepanno.ast.KeepMemberItemPattern;
 import com.android.tools.r8.keepanno.ast.KeepTarget;
 import com.android.tools.r8.shaking.KeepAnnotationCollectionInfo.RetentionInfo;
@@ -510,10 +509,6 @@
       return -(key + 1);
     }
 
-    private int defineItemReference(KeepItemReference reference) {
-      return reference.apply(this::defineBindingReference, this::defineItemPattern);
-    }
-
     private int defineBindingReference(KeepBindingReference reference) {
       return symbolToKey.computeIfAbsent(
           reference.getName(), symbol -> defineItemPattern(getItemForBinding(symbol)));
@@ -526,7 +521,8 @@
         classMembers.add(new IntArrayList());
         return encodeClassKey(classIndex);
       } else {
-        int classIndex = defineItemReference(item.asMemberItemPattern().getClassReference());
+        KeepBindingReference reference = item.asMemberItemPattern().getClassReference();
+        int classIndex = defineBindingReference(reference);
         int memberIndex = members.size();
         members.add(item.asMemberItemPattern());
         classMembers.get(classIndex).add(memberIndex);
@@ -535,11 +531,12 @@
     }
 
     public void addPrecondition(KeepCondition condition) {
-      preconditions.add(defineItemReference(condition.getItem()));
+      preconditions.add(defineBindingReference(condition.getItem()));
     }
 
     private void addConsequence(KeepTarget target) {
-      consequences.add(defineItemReference(target.getItem()));
+      KeepBindingReference reference = target.getItem();
+      consequences.add(defineBindingReference(reference));
       constraints.add(target.getConstraints());
     }
   }
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 e0727be..b2beb2e 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
@@ -46,13 +46,9 @@
             .setConsequences(
                 KeepConsequences.builder()
                     .addTarget(
-                        KeepTarget.builder()
-                            .setItemBindingReference(helper.freshAnyClass())
-                            .build())
+                        KeepTarget.builder().setItemReference(helper.freshAnyClass()).build())
                     .addTarget(
-                        KeepTarget.builder()
-                            .setItemBindingReference(helper.freshAnyMember())
-                            .build())
+                        KeepTarget.builder().setItemReference(helper.freshAnyMember()).build())
                     .build())
             .setBindings(helper.build())
             .build();
@@ -79,12 +75,12 @@
                 KeepConsequences.builder()
                     .addTarget(
                         KeepTarget.builder()
-                            .setItemBindingReference(helper.freshAnyClass())
+                            .setItemReference(helper.freshAnyClass())
                             .setConstraints(constraints)
                             .build())
                     .addTarget(
                         KeepTarget.builder()
-                            .setItemBindingReference(helper.freshAnyMember())
+                            .setItemReference(helper.freshAnyMember())
                             .setConstraints(constraints)
                             .build())
                     .build())
@@ -150,7 +146,7 @@
                 KeepPreconditions.builder()
                     .addCondition(
                         KeepCondition.builder()
-                            .setItemBindingReference(helper.freshClassBinding(classItem(CLASS)))
+                            .setItemReference(helper.freshClassBinding(classItem(CLASS)))
                             .build())
                     .build())
             .setConsequences(
@@ -207,7 +203,7 @@
         KeepEdge.builder()
             .setPreconditions(
                 KeepPreconditions.builder()
-                    .addCondition(KeepCondition.builder().setItemBindingReference(clazz).build())
+                    .addCondition(KeepCondition.builder().setItemReference(clazz).build())
                     .build())
             .setConsequences(
                 KeepConsequences.builder()
@@ -215,7 +211,7 @@
                     .addTarget(
                         target(
                             KeepMemberItemPattern.builder()
-                                .setClassBindingReference(clazz)
+                                .setClassReference(clazz)
                                 .setMemberPattern(defaultInitializerPattern())
                                 .build(),
                             helper))
@@ -241,7 +237,7 @@
   }
 
   private KeepTarget target(KeepBindingReference item) {
-    return KeepTarget.builder().setItemBindingReference(item).build();
+    return KeepTarget.builder().setItemReference(item).build();
   }
 
   private KeepCondition condition(KeepItemPattern item, BindingsHelper helper) {
@@ -249,7 +245,7 @@
   }
 
   private KeepCondition condition(KeepBindingReference item) {
-    return KeepCondition.builder().setItemBindingReference(item).build();
+    return KeepCondition.builder().setItemReference(item).build();
   }
 
   private KeepClassItemPattern classItem(String typeName) {
@@ -267,7 +263,7 @@
 
   private static KeepMemberItemPattern.Builder buildMemberItem(KeepClassBindingReference holder) {
     return KeepMemberItemPattern.builder()
-        .setClassBindingReference(holder)
+        .setClassReference(holder)
         .setMemberPattern(KeepMemberPattern.allMembers());
   }
 
diff --git a/tools/download_kotlin_dev.py b/tools/download_kotlin_dev.py
index 7359f1d..337d6c8 100755
--- a/tools/download_kotlin_dev.py
+++ b/tools/download_kotlin_dev.py
@@ -59,16 +59,19 @@
         raise Exception('Url: %s \n returned %s' %
                         (KOTLIN_RELEASE_URL, response.getcode()))
 
+    # Download checked in kotlin dev compiler before owerlaying with the new.
+    # TODO(sgjesse): This should just ensure an empty directory instead of
+    # relying on overlaying and reusing some jars.
+    utils.DownloadFromGoogleCloudStorage(
+        os.path.join(utils.THIRD_PARTY, "kotlin",
+                     "kotlin-compiler-dev.tar.gz.sha1"))
+
     # Check POM for expected dependencies.
     check_pom(top_most_version_and_build)
 
     # We can now download all files related to the kotlin compiler version.
     print("Downloading version: " + top_most_version_and_build)
 
-    utils.DownloadFromGoogleCloudStorage(
-        os.path.join(utils.THIRD_PARTY, "kotlin",
-                     "kotlin-compiler-dev.tar.gz.sha1"))
-
     download_and_save(
         JETBRAINS_KOTLIN_MAVEN_URL +
         "kotlin-compiler/{0}/kotlin-compiler-{0}.jar".format(