[KeepAnno] Finish remaining proto encoding

Bug: b/343389186
Change-Id: I0bd71f0cc1fd55171698e385ad03a71fd1d79ef4
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AccessVisibility.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AccessVisibility.java
index 690bae6..19e72a5 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AccessVisibility.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AccessVisibility.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.keepanno.ast;
 
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 import java.util.HashSet;
@@ -42,4 +43,35 @@
   public static Set<AccessVisibility> all() {
     return ALL;
   }
+
+  public KeepSpecProtos.AccessVisibility buildProto() {
+    switch (this) {
+      case PUBLIC:
+        return KeepSpecProtos.AccessVisibility.ACCESS_PUBLIC;
+      case PROTECTED:
+        return KeepSpecProtos.AccessVisibility.ACCESS_PROTECTED;
+      case PACKAGE_PRIVATE:
+        return KeepSpecProtos.AccessVisibility.ACCESS_PACKAGE_PRIVATE;
+      case PRIVATE:
+        return KeepSpecProtos.AccessVisibility.ACCESS_PRIVATE;
+      default:
+        return KeepSpecProtos.AccessVisibility.ACCESS_UNSPECIFIED;
+    }
+  }
+
+  public static AccessVisibility fromProto(KeepSpecProtos.AccessVisibility proto) {
+    switch (proto.getNumber()) {
+      case KeepSpecProtos.AccessVisibility.ACCESS_PUBLIC_VALUE:
+        return PUBLIC;
+      case KeepSpecProtos.AccessVisibility.ACCESS_PROTECTED_VALUE:
+        return PROTECTED;
+      case KeepSpecProtos.AccessVisibility.ACCESS_PACKAGE_PRIVATE_VALUE:
+        return PACKAGE_PRIVATE;
+      case KeepSpecProtos.AccessVisibility.ACCESS_PRIVATE_VALUE:
+        return PRIVATE;
+      default:
+        assert proto == KeepSpecProtos.AccessVisibility.ACCESS_UNSPECIFIED;
+        return null;
+    }
+  }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java
index 5c7cf96..13d4df3 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.keepanno.ast;
 
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.AnnotationPattern;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.AnnotationRetention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
@@ -38,6 +40,21 @@
     return new Builder();
   }
 
+  public static KeepAnnotationPattern fromProto(AnnotationPattern proto) {
+    return builder().applyProto(proto).build();
+  }
+
+  public AnnotationPattern.Builder buildProto() {
+    AnnotationPattern.Builder builder = AnnotationPattern.newBuilder();
+    builder.setName(namePattern.buildProto());
+    if (retentionPolicies == RUNTIME_RETENTION_MASK) {
+      builder.setRetention(AnnotationRetention.RETENTION_RUNTIME);
+    } else if (retentionPolicies == CLASS_RETENTION_MASK) {
+      builder.setRetention(AnnotationRetention.RETENTION_CLASS);
+    }
+    return builder;
+  }
+
   public static class Builder {
 
     private KeepQualifiedClassNamePattern namePattern = KeepQualifiedClassNamePattern.any();
@@ -45,6 +62,31 @@
 
     private Builder() {}
 
+    public Builder applyProto(AnnotationPattern proto) {
+      assert namePattern.isAny();
+      if (proto.hasName()) {
+        setNamePattern(KeepQualifiedClassNamePattern.fromProto(proto.getName()));
+      }
+      // The builder is configured to check that retention is set.
+      // Thus, we apply the default case here explicitly.
+      assert retentionPolicies != ANY_RETENTION_MASK;
+      retentionPolicies = ANY_RETENTION_MASK;
+      if (proto.hasRetention()) {
+        switch (proto.getRetention().getNumber()) {
+          case AnnotationRetention.RETENTION_RUNTIME_VALUE:
+            retentionPolicies = RUNTIME_RETENTION_MASK;
+            break;
+          case AnnotationRetention.RETENTION_CLASS_VALUE:
+            retentionPolicies = CLASS_RETENTION_MASK;
+            break;
+          default:
+            // default any applies.
+            assert retentionPolicies == ANY_RETENTION_MASK;
+        }
+      }
+      return this;
+    }
+
     public Builder setNamePattern(KeepQualifiedClassNamePattern namePattern) {
       this.namePattern = namePattern;
       return this;
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 28ff0b1..b0045f5 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,6 +3,7 @@
 // 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.KeepSpecUtils.BindingResolver;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Bindings;
 import java.util.Collections;
@@ -88,6 +89,13 @@
             .collect(Collectors.joining(", "));
   }
 
+  public static BindingResolver fromProto(Bindings proto) {
+    if (proto == null) {
+      throw new KeepEdgeException("Invalid keep spec, must have valid bindings.");
+    }
+    return new BindingResolver(builder().applyProto(proto));
+  }
+
   public KeepSpecProtos.Bindings.Builder buildProto() {
     KeepSpecProtos.Bindings.Builder builder = KeepSpecProtos.Bindings.newBuilder();
     bindings.forEach(
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 c59fe13..c7d6d84 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
@@ -3,6 +3,7 @@
 // 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.KeepSpecUtils.BindingResolver;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Check;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.CheckKind;
@@ -36,19 +37,11 @@
           setKind(KeepCheckKind.REMOVED);
       }
 
-      // Bindings are not optional.
-      if (!proto.hasBindings()) {
-        throw new KeepEdgeException("Invalid Check, must have valid bindings.");
-      }
-      KeepBindings.Builder bindingsBuilder = KeepBindings.builder().applyProto(proto.getBindings());
-      setBindings(bindingsBuilder.build());
-
-      // The check item reference is not optional.
-      if (!proto.hasItem() || proto.getItem().getName().isEmpty()) {
-        throw new KeepEdgeException("Invalid check, must have a valid item reference.");
-      }
-      setItemReference(
-          bindingsBuilder.getBindingReferenceForUserBinding(proto.getItem().getName()));
+      // Bindings are non-optional (checked in fromProto).
+      BindingResolver resolver = KeepBindings.fromProto(proto.getBindings());
+      setBindings(resolver.getBindings());
+      // Item is non-optional (checked in mapReference).
+      setItemReference(resolver.mapReference(proto.getItem()));
       return this;
     }
 
@@ -131,7 +124,12 @@
 
   @Override
   public String toString() {
-    return "KeepCheck{kind=" + kind + ", item=" + itemReference + "}";
+    return toProtoString();
+  }
+
+  @Override
+  public String toProtoString() {
+    return buildCheckProto().toString();
   }
 
   public static KeepCheck fromCheckProto(Check proto, KeepSpecVersion version) {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java
index 8d27307..4ccfad3 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java
@@ -24,9 +24,10 @@
   }
 
   public ClassItemPattern.Builder buildClassProto() {
-    // TODO(b/343389186): Add instance-of.
-    // TODO(b/343389186): Add annotated-by.
-    return ClassItemPattern.newBuilder().setClassName(classNamePattern.buildProto());
+    ClassItemPattern.Builder builder = ClassItemPattern.newBuilder();
+    KeepSpecUtils.buildAnnotatedByProto(annotatedByPattern, builder::setAnnotatedBy);
+    instanceOfPattern.buildProto(builder::setInstanceOf);
+    return builder.setClassName(classNamePattern.buildProto());
   }
 
   public static class Builder {
@@ -43,9 +44,14 @@
       if (protoItem.hasClassName()) {
         setClassNamePattern(KeepQualifiedClassNamePattern.fromProto(protoItem.getClassName()));
       }
-
-      // TODO(b/343389186): Add instance-of.
-      // TODO(b/343389186): Add annotated-by.
+      assert annotatedByPattern.isAbsent();
+      if (protoItem.hasAnnotatedBy()) {
+        setAnnotatedByPattern(KeepSpecUtils.annotatedByFromProto(protoItem.getAnnotatedBy()));
+      }
+      assert instanceOfPattern.isAny();
+      if (protoItem.hasInstanceOf()) {
+        setInstanceOfPattern(KeepInstanceOfPattern.fromProto(protoItem.getInstanceOf()));
+      }
       return this;
     }
 
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 96c0f4d..7e619d9 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
@@ -3,6 +3,9 @@
 // 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.KeepSpecUtils.BindingResolver;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Condition;
+
 /**
  * A keep condition is the content of an item in the set of preconditions.
  *
@@ -17,12 +20,25 @@
     return new Builder();
   }
 
+  public Condition.Builder buildProto() {
+    return Condition.newBuilder().setItem(item.buildProto());
+  }
+
+  public static KeepCondition fromProto(Condition proto, BindingResolver resolver) {
+    return builder().applyProto(proto, resolver).build();
+  }
+
   public static class Builder {
 
     private KeepBindingReference item;
 
     private Builder() {}
 
+    public Builder applyProto(Condition proto, BindingResolver resolver) {
+      // Item is not optional and the resolver will throw if not present.
+      return setItemReference(resolver.mapReference(proto.getItem()));
+    }
+
     public Builder setItemReference(KeepBindingReference item) {
       this.item = item;
       return this;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConsequences.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConsequences.java
index 1322746..2fdc4c3 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConsequences.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConsequences.java
@@ -3,6 +3,8 @@
 // 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.KeepSpecUtils.BindingResolver;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Target;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
@@ -11,19 +13,30 @@
 /**
  * Set of consequences of a keep edge.
  *
- * <p>The consequences are "targets" described by item patterns along with "keep options" which
+ * <p>The consequences are "targets" described by item references along with "keep options" which
  * detail what aspects of the items must be retained.
  *
  * <p>The consequences come into effect if the preconditions of an edge are met.
  */
 public final class KeepConsequences {
 
+  public static KeepConsequences fromProto(List<Target> protoList, BindingResolver resolver) {
+    return builder().applyProto(protoList, resolver).build();
+  }
+
   public static class Builder {
 
     private List<KeepTarget> targets = new ArrayList<>();
 
     private Builder() {}
 
+    public Builder applyProto(List<Target> protoList, BindingResolver resolver) {
+      for (Target target : protoList) {
+        addTarget(KeepTarget.fromProto(target, resolver));
+      }
+      return this;
+    }
+
     public Builder addTarget(KeepTarget target) {
       targets.add(target);
       return this;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraint.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraint.java
index 2ae5f93..f33e14e 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraint.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepConstraint.java
@@ -5,10 +5,67 @@
 
 import com.android.tools.r8.keepanno.ast.AnnotationConstants.Constraints;
 import com.android.tools.r8.keepanno.ast.KeepOptions.KeepOption;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Constraint;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.ConstraintElement;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public abstract class KeepConstraint {
 
+  public Constraint.Builder buildProto() {
+    return Constraint.newBuilder().setElement(buildElementProto());
+  }
+
+  public abstract ConstraintElement buildElementProto();
+
+  public static void fromProto(Constraint proto, Consumer<KeepConstraint> callback) {
+    if (proto.hasElement()) {
+      KeepConstraint constraint = getConstraintFromProtoEnum(proto.getElement());
+      if (constraint != null) {
+        callback.accept(constraint);
+      }
+      return;
+    }
+    if (proto.hasAnnotation()) {
+      callback.accept(
+          KeepConstraint.annotation(KeepAnnotationPattern.fromProto(proto.getAnnotation())));
+    }
+  }
+
+  private static KeepConstraint getConstraintFromProtoEnum(ConstraintElement proto) {
+    switch (proto.getNumber()) {
+      case ConstraintElement.CONSTRAINT_LOOKUP_VALUE:
+        return lookup();
+      case ConstraintElement.CONSTRAINT_NAME_VALUE:
+        return name();
+      case ConstraintElement.CONSTRAINT_VISIBILITY_RELAX_VALUE:
+        return visibilityRelax();
+      case ConstraintElement.CONSTRAINT_VISIBILITY_RESTRICT_VALUE:
+        return visibilityRestrict();
+      case ConstraintElement.CONSTRAINT_NEVER_INLINE_VALUE:
+        return neverInline();
+      case ConstraintElement.CONSTRAINT_CLASS_INSTANTIATE_VALUE:
+        return classInstantiate();
+      case ConstraintElement.CONSTRAINT_CLASS_OPEN_HIERARCHY_VALUE:
+        return classOpenHierarchy();
+      case ConstraintElement.CONSTRAINT_METHOD_INVOKE_VALUE:
+        return methodInvoke();
+      case ConstraintElement.CONSTRAINT_METHOD_REPLACE_VALUE:
+        return methodReplace();
+      case ConstraintElement.CONSTRAINT_FIELD_GET_VALUE:
+        return fieldGet();
+      case ConstraintElement.CONSTRAINT_FIELD_SET_VALUE:
+        return fieldSet();
+      case ConstraintElement.CONSTRAINT_FIELD_REPLACE_VALUE:
+        return fieldReplace();
+      case ConstraintElement.CONSTRAINT_GENERIC_SIGNATURE_VALUE:
+        return genericSignature();
+      default:
+        assert proto == ConstraintElement.CONSTRAINT_UNSPECIFIED;
+        return null;
+    }
+  }
+
   @Override
   public String toString() {
     String typeName = getClass().getTypeName();
@@ -87,6 +144,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.SHRINKING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_LOOKUP;
+    }
   }
 
   public static Name name() {
@@ -113,6 +175,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OBFUSCATING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_NAME;
+    }
   }
 
   public static VisibilityRelax visibilityRelax() {
@@ -139,6 +206,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       // The compiler currently satisfies that access is never restricted.
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_VISIBILITY_RELAX;
+    }
   }
 
   public static VisibilityRestrict visibilityRestrict() {
@@ -166,6 +238,11 @@
       // We don't have directional rules so this prohibits any modification.
       builder.add(KeepOption.ACCESS_MODIFICATION);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_VISIBILITY_RESTRICT;
+    }
   }
 
   public static NeverInline neverInline() {
@@ -192,6 +269,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_NEVER_INLINE;
+    }
   }
 
   public static ClassInstantiate classInstantiate() {
@@ -223,6 +305,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_CLASS_INSTANTIATE;
+    }
   }
 
   public static ClassOpenHierarchy classOpenHierarchy() {
@@ -254,6 +341,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_CLASS_OPEN_HIERARCHY;
+    }
   }
 
   public static MethodInvoke methodInvoke() {
@@ -285,6 +377,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_METHOD_INVOKE;
+    }
   }
 
   public static MethodReplace methodReplace() {
@@ -316,6 +413,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_METHOD_REPLACE;
+    }
   }
 
   public static FieldGet fieldGet() {
@@ -347,6 +449,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_FIELD_GET;
+    }
   }
 
   public static FieldSet fieldSet() {
@@ -378,6 +485,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_FIELD_SET;
+    }
   }
 
   public static FieldReplace fieldReplace() {
@@ -409,6 +521,11 @@
     public void convertToDisallowKeepOptions(KeepOptions.Builder builder) {
       builder.add(KeepOption.OPTIMIZING);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_FIELD_REPLACE;
+    }
   }
 
   public static GenericSignature genericSignature() {
@@ -440,6 +557,11 @@
     public void addRequiredKeepAttributes(Set<KeepAttribute> attributes) {
       attributes.add(KeepAttribute.GENERIC_SIGNATURES);
     }
+
+    @Override
+    public ConstraintElement buildElementProto() {
+      return ConstraintElement.CONSTRAINT_GENERIC_SIGNATURE;
+    }
   }
 
   public static Annotation annotationsAll() {
@@ -496,6 +618,16 @@
     }
 
     @Override
+    public ConstraintElement buildElementProto() {
+      throw new KeepEdgeException("Unexpected attempt to build element for annotation constraint");
+    }
+
+    @Override
+    public Constraint.Builder buildProto() {
+      return Constraint.newBuilder().setAnnotation(annotationPattern.buildProto());
+    }
+
+    @Override
     public void accept(KeepConstraintVisitor visitor) {
       visitor.onAnnotation(this);
     }
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 6c55e6c..01c8844 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
@@ -6,11 +6,14 @@
 
 import com.android.tools.r8.keepanno.ast.KeepConstraint.Annotation;
 import com.android.tools.r8.keepanno.ast.KeepOptions.KeepOption;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
 import com.google.common.collect.ImmutableSet;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -41,6 +44,27 @@
     getConstraints().forEach(c -> c.accept(visitor));
   }
 
+  public abstract void buildProto(
+      Consumer<KeepSpecProtos.Constraints> setConstraints,
+      Consumer<KeepSpecProtos.Constraint> addConstraintAddition);
+
+  public void fromProto(
+      KeepSpecProtos.Constraints proto,
+      List<KeepSpecProtos.Constraint> protoAdditions,
+      Consumer<KeepConstraints> setConstraints) {
+    if (proto == null && protoAdditions.isEmpty()) {
+      return;
+    }
+    Builder builder = builder();
+    if (proto == null) {
+      builder.copyFrom(defaultConstraints());
+    } else {
+      proto.getConstraintsList().forEach(c -> KeepConstraint.fromProto(c, builder::add));
+    }
+    protoAdditions.forEach(c -> KeepConstraint.fromProto(c, builder::add));
+    setConstraints.accept(builder.build());
+  }
+
   public static class Builder {
 
     private boolean defaultAdditions = false;
@@ -149,6 +173,15 @@
     public KeepOptions convertToKeepOptions(KeepOptions defaultOptions) {
       return KeepOptions.keepAll();
     }
+
+    @Override
+    public void buildProto(
+        Consumer<KeepSpecProtos.Constraints> setConstraints,
+        Consumer<KeepSpecProtos.Constraint> addConstraintAddition) {
+      KeepSpecProtos.Constraints.Builder builder = KeepSpecProtos.Constraints.newBuilder();
+      constraints.forEach(c -> builder.addConstraints(c.buildProto()));
+      setConstraints.accept(builder.build());
+    }
   }
 
   private static class Defaults extends KeepConstraints {
@@ -165,6 +198,11 @@
             KeepConstraint.fieldSet());
 
     @Override
+    public boolean isDefault() {
+      return true;
+    }
+
+    @Override
     Set<KeepConstraint> getConstraints() {
       return constraints;
     }
@@ -184,6 +222,13 @@
       // The default set of keep rules for any kind of target requires no additional attributes.
       return Collections.emptySet();
     }
+
+    @Override
+    public void buildProto(
+        Consumer<KeepSpecProtos.Constraints> setConstraints,
+        Consumer<KeepSpecProtos.Constraint> addConstraintAddition) {
+      // Nothing to add as these are the defaults.
+    }
   }
 
   private static class Additions extends KeepConstraints {
@@ -218,6 +263,15 @@
     public Set<KeepAttribute> getRequiredKeepAttributes() {
       return additions.getRequiredKeepAttributes();
     }
+
+    @Override
+    public void buildProto(
+        Consumer<KeepSpecProtos.Constraints> setConstraints,
+        Consumer<KeepSpecProtos.Constraint> addConstraintAddition) {
+      // Map all nested constraints into additions.
+      additions.buildProto(
+          cs -> cs.getConstraintsList().forEach(addConstraintAddition), addConstraintAddition);
+    }
   }
 
   private static class Constraints extends KeepConstraints {
@@ -229,6 +283,15 @@
     }
 
     @Override
+    public void buildProto(
+        Consumer<KeepSpecProtos.Constraints> setConstraints,
+        Consumer<KeepSpecProtos.Constraint> addConstraintAddition) {
+      KeepSpecProtos.Constraints.Builder builder = KeepSpecProtos.Constraints.newBuilder();
+      constraints.forEach(c -> builder.addConstraints(c.buildProto()));
+      setConstraints.accept(builder.build());
+    }
+
+    @Override
     public Set<KeepConstraint> getConstraints() {
       return constraints;
     }
@@ -262,4 +325,8 @@
   public abstract KeepOptions convertToKeepOptions(KeepOptions defaultOptions);
 
   public abstract Set<KeepAttribute> getRequiredKeepAttributes();
+
+  public boolean isDefault() {
+    return false;
+  }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepDeclaration.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepDeclaration.java
index 12d1d31..a2cc7de 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepDeclaration.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepDeclaration.java
@@ -50,6 +50,8 @@
     throw new RuntimeException();
   }
 
+  public abstract String toProtoString();
+
   public final Declaration.Builder buildDeclarationProto() {
     Declaration.Builder builder = Declaration.newBuilder();
     return apply(
@@ -57,13 +59,13 @@
         check -> builder.setCheck(check.buildCheckProto()));
   }
 
-  public static KeepDeclaration fromProto(
+  public static KeepDeclaration fromDeclarationProto(
       KeepSpecProtos.Declaration declaration, KeepSpecVersion version) {
     if (declaration.hasEdge()) {
-      return KeepEdge.builder().applyProto(declaration.getEdge(), version).build();
+      return KeepEdge.fromEdgeProto(declaration.getEdge(), version);
     }
     if (declaration.hasCheck()) {
-      return KeepCheck.builder().applyProto(declaration.getCheck(), version).build();
+      return KeepCheck.fromCheckProto(declaration.getCheck(), version);
     }
     return null;
   }
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 3060010..ff8e507 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
@@ -3,8 +3,8 @@
 // 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.KeepSpecUtils.BindingResolver;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Edge;
-import com.android.tools.r8.keepanno.utils.Unimplemented;
 
 /**
  * An edge in the keep graph.
@@ -147,9 +147,14 @@
 
     private Builder() {}
 
-    public Builder applyProto(Edge edge, KeepSpecVersion version) {
-      // TODO(b/343389186): implement this.
-      KeepEdgeMetaInfo.builder().applyProto(edge.getMetaInfo(), version).build();
+    public Builder applyProto(Edge proto, KeepSpecVersion version) {
+      // Proto MetaInfo is optional but the `fromProto` deals with the null case.
+      setMetaInfo(KeepEdgeMetaInfo.fromProto(proto.getMetaInfo(), version));
+      // Bindings are non-optional (checked in fromProto).
+      BindingResolver resolver = KeepBindings.fromProto(proto.getBindings());
+      setBindings(resolver.getBindings());
+      setPreconditions(KeepPreconditions.fromProto(proto.getPreconditionsList(), resolver));
+      setConsequences(KeepConsequences.fromProto(proto.getConsequencesList(), resolver));
       return this;
     }
 
@@ -257,17 +262,24 @@
 
   @Override
   public String toString() {
-    return "KeepEdge{metainfo="
-        + getMetaInfo()
-        + ", preconditions="
-        + preconditions
-        + ", consequences="
-        + consequences
-        + '}';
+    return toProtoString();
+  }
+
+  @Override
+  public String toProtoString() {
+    return buildEdgeProto().toString();
+  }
+
+  public static KeepEdge fromEdgeProto(Edge proto, KeepSpecVersion version) {
+    return KeepEdge.builder().applyProto(proto, version).build();
   }
 
   public Edge.Builder buildEdgeProto() {
-    Edge.newBuilder().setMetaInfo(getMetaInfo().buildProto());
-    throw new Unimplemented();
+    Edge.Builder builder = Edge.newBuilder();
+    builder.setMetaInfo(getMetaInfo().buildProto());
+    builder.setBindings(bindings.buildProto());
+    preconditions.forEach(condition -> builder.addPreconditions(condition.buildProto()));
+    consequences.forEachTarget(target -> builder.addConsequences(target.buildProto()));
+    return builder;
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java
index 55c15c2..b9bf204 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java
@@ -5,7 +5,9 @@
 
 import com.android.tools.r8.keepanno.keeprules.RulePrinter;
 import com.android.tools.r8.keepanno.keeprules.RulePrintingUtils;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.MemberAccessField;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class KeepFieldAccessPattern extends KeepMemberAccessPattern {
 
@@ -41,6 +43,10 @@
     this.transientPattern = transientPattern;
   }
 
+  public static KeepFieldAccessPattern fromFieldProto(MemberAccessField proto) {
+    return builder().applyFieldProto(proto).build();
+  }
+
   @Override
   public String toString() {
     if (isAny()) {
@@ -64,6 +70,17 @@
     return transientPattern;
   }
 
+  public void buildFieldProto(Consumer<MemberAccessField.Builder> callback) {
+    if (isAny()) {
+      return;
+    }
+    MemberAccessField.Builder builder = MemberAccessField.newBuilder();
+    buildGeneralProto(builder::setGeneralAccess);
+    volatilePattern.buildProto(builder::setVolatilePattern);
+    transientPattern.buildProto(builder::setTransientPattern);
+    callback.accept(builder);
+  }
+
   public static class Builder extends BuilderBase<KeepFieldAccessPattern, Builder> {
 
     private ModifierPattern volatilePattern = ModifierPattern.any();
@@ -106,5 +123,20 @@
     public ModifierPattern getTransientPattern() {
       return transientPattern;
     }
+
+    public Builder applyFieldProto(MemberAccessField proto) {
+      if (proto.hasGeneralAccess()) {
+        applyGeneralProto(proto.getGeneralAccess());
+      }
+      assert volatilePattern.isAny();
+      if (proto.hasVolatilePattern()) {
+        setVolatile(proto.getVolatilePattern().getValue());
+      }
+      assert transientPattern.isAny();
+      if (proto.hasTransientPattern()) {
+        setTransient(proto.getTransientPattern().getValue());
+      }
+      return this;
+    }
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
index f863c2e..d6ec06d 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.keepanno.ast;
 
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.MemberPatternField;
-import com.android.tools.r8.keepanno.utils.Unimplemented;
 import java.util.Objects;
 
 public final class KeepFieldPattern extends KeepMemberPattern {
@@ -31,6 +30,31 @@
       return this;
     }
 
+    public Builder applyProto(MemberPatternField proto) {
+      assert namePattern.isAny();
+      if (proto.hasName()) {
+        setNamePattern(
+            KeepFieldNamePattern.fromStringPattern(KeepStringPattern.fromProto(proto.getName())));
+      }
+
+      assert typePattern.isAny();
+      if (proto.hasFieldType()) {
+        setTypePattern(
+            KeepFieldTypePattern.fromType(KeepTypePattern.fromProto(proto.getFieldType())));
+      }
+
+      assert accessPattern.isAny();
+      if (proto.hasAccess()) {
+        setAccessPattern(KeepFieldAccessPattern.fromFieldProto(proto.getAccess()));
+      }
+
+      assert annotatedByPattern.isAbsent();
+      if (proto.hasAnnotatedBy()) {
+        setAnnotatedByPattern(KeepSpecUtils.annotatedByFromProto(proto.getAnnotatedBy()));
+      }
+      return self();
+    }
+
     public Builder copyFromMemberPattern(KeepMemberPattern memberPattern) {
       assert memberPattern.isGeneralMember();
       return setAccessPattern(
@@ -148,7 +172,17 @@
         + '}';
   }
 
+  public static KeepFieldPattern fromFieldMemberProto(MemberPatternField proto) {
+    return builder().applyProto(proto).build();
+  }
+
   public MemberPatternField.Builder buildFieldProto() {
-    throw new Unimplemented();
+    MemberPatternField.Builder builder =
+        MemberPatternField.newBuilder()
+            .setName(namePattern.asStringPattern().buildProto())
+            .setFieldType(typePattern.asType().buildProto());
+    accessPattern.buildFieldProto(builder::setAccess);
+    KeepSpecUtils.buildAnnotatedByProto(annotatedByPattern, builder::setAnnotatedBy);
+    return builder;
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java
index 79e2f43..114ada8 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.keepanno.ast;
 
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.InstanceOfPattern;
+import java.util.function.Consumer;
+
 /** Pattern for matching the instance-of properties of a class. */
 public abstract class KeepInstanceOfPattern {
 
@@ -10,6 +13,20 @@
     return Some.getAnyInstance();
   }
 
+  public static KeepInstanceOfPattern fromProto(InstanceOfPattern proto) {
+    return builder().applyProto(proto).build();
+  }
+
+  public void buildProto(Consumer<InstanceOfPattern.Builder> setter) {
+    if (isAny()) {
+      return;
+    }
+    setter.accept(
+        InstanceOfPattern.newBuilder()
+            .setInclusive(isInclusive())
+            .setClassName(getClassNamePattern().buildProto()));
+  }
+
   public static class Builder {
 
     private KeepQualifiedClassNamePattern namePattern = KeepQualifiedClassNamePattern.any();
@@ -17,6 +34,18 @@
 
     private Builder() {}
 
+    public Builder applyProto(InstanceOfPattern proto) {
+      assert namePattern.isAny();
+      if (proto.hasClassName()) {
+        classPattern(KeepQualifiedClassNamePattern.fromProto(proto.getClassName()));
+      }
+      assert isInclusive;
+      if (proto.hasInclusive()) {
+        setInclusive(proto.getInclusive());
+      }
+      return this;
+    }
+
     public Builder classPattern(KeepQualifiedClassNamePattern namePattern) {
       this.namePattern = namePattern;
       return this;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java
index 8b18105..487ddc8 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java
@@ -5,7 +5,11 @@
 
 import com.android.tools.r8.keepanno.keeprules.RulePrinter;
 import com.android.tools.r8.keepanno.keeprules.RulePrintingUtils;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.AccessVisibilitySet;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.MemberAccessGeneral;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class KeepMemberAccessPattern {
 
@@ -83,6 +87,28 @@
     return syntheticPattern;
   }
 
+  public static KeepMemberAccessPattern fromGeneralProto(MemberAccessGeneral proto) {
+    return memberBuilder().applyGeneralProto(proto).build();
+  }
+
+  public void buildGeneralProto(Consumer<MemberAccessGeneral.Builder> callback) {
+    if (isAny()) {
+      return;
+    }
+    MemberAccessGeneral.Builder builder = MemberAccessGeneral.newBuilder();
+    if (!isAnyVisibility()) {
+      AccessVisibilitySet.Builder visibilityBuilder = AccessVisibilitySet.newBuilder();
+      for (AccessVisibility visibility : allowedVisibilities) {
+        visibilityBuilder.addAccessVisibility(visibility.buildProto());
+      }
+      builder.setAccessVisibility(visibilityBuilder.build());
+    }
+    staticPattern.buildProto(builder::setStaticPattern);
+    finalPattern.buildProto(builder::setFinalPattern);
+    syntheticPattern.buildProto(builder::setSyntheticPattern);
+    callback.accept(builder);
+  }
+
   public static class Builder extends BuilderBase<KeepMemberAccessPattern, Builder> {
 
     @Override
@@ -185,5 +211,32 @@
       syntheticPattern = ModifierPattern.fromAllowValue(allow);
       return self();
     }
+
+    public B applyGeneralProto(MemberAccessGeneral proto) {
+      assert getAllowedVisibilities() == AccessVisibility.all();
+      if (proto.hasAccessVisibility()) {
+        AccessVisibilitySet protoSet = proto.getAccessVisibility();
+        for (KeepSpecProtos.AccessVisibility protoVisibility : protoSet.getAccessVisibilityList()) {
+          // Map "unspecified" value to no effect, e.g. any visibility.
+          AccessVisibility visibility = AccessVisibility.fromProto(protoVisibility);
+          if (visibility != null) {
+            setAccessVisibility(visibility, true);
+          }
+        }
+      }
+      assert staticPattern.isAny();
+      if (proto.hasStaticPattern()) {
+        setStatic(proto.getStaticPattern().getValue());
+      }
+      assert finalPattern.isAny();
+      if (proto.hasFinalPattern()) {
+        setFinal(proto.getFinalPattern().getValue());
+      }
+      assert syntheticPattern.isAny();
+      if (proto.hasSyntheticPattern()) {
+        setSynthetic(proto.getSyntheticPattern().getValue());
+      }
+      return self();
+    }
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
index 5c784bc..67bbcd2 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.MemberPattern;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.MemberPatternGeneral;
-import com.android.tools.r8.keepanno.utils.Unimplemented;
 import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -21,9 +20,22 @@
   }
 
   public static class Builder {
-    private OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern;
+    private OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern =
+        OptionalPattern.absent();
     private KeepMemberAccessPattern accessPattern = KeepMemberAccessPattern.anyMemberAccess();
 
+    public Builder applyProto(MemberPatternGeneral proto) {
+      assert annotatedByPattern.isAbsent();
+      if (proto.hasAnnotatedBy()) {
+        setAnnotatedByPattern(KeepSpecUtils.annotatedByFromProto(proto.getAnnotatedBy()));
+      }
+      assert accessPattern.isAny();
+      if (proto.hasAccess()) {
+        setAccessPattern(KeepMemberAccessPattern.fromGeneralProto(proto.getAccess()));
+      }
+      return this;
+    }
+
     public Builder setAnnotatedByPattern(
         OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern) {
       this.annotatedByPattern = annotatedByPattern;
@@ -94,8 +106,15 @@
           + '}';
     }
 
-    public MemberPatternGeneral.Builder buildGeneralProto() {
-      throw new Unimplemented();
+    public MemberPatternGeneral.Builder buildGeneralMemberProto() {
+      MemberPatternGeneral.Builder builder = MemberPatternGeneral.newBuilder();
+      accessPattern.buildGeneralProto(builder::setAccess);
+      KeepSpecUtils.buildAnnotatedByProto(annotatedByPattern, builder::setAnnotatedBy);
+      return builder;
+    }
+
+    public static KeepMemberPattern fromGeneralMemberProto(MemberPatternGeneral proto) {
+      return memberBuilder().applyProto(proto).build();
     }
   }
 
@@ -156,7 +175,7 @@
   public MemberPattern.Builder buildProto() {
     MemberPattern.Builder builder = MemberPattern.newBuilder();
     match(
-        general -> builder.setGeneralMember(((Some) general).buildGeneralProto()),
+        general -> builder.setGeneralMember(((Some) general).buildGeneralMemberProto()),
         field -> builder.setFieldMember(field.buildFieldProto()),
         method -> builder.setMethodMember(method.buildMethodProto()));
     return builder;
@@ -164,15 +183,13 @@
 
   public static KeepMemberPattern fromMemberProto(MemberPattern memberPattern) {
     if (memberPattern.hasGeneralMember()) {
-      // return KeepMemberPattern.memberBuilder().applyProto(memberPattern.getGeneralMember());
-      throw new Unimplemented();
+      return Some.fromGeneralMemberProto(memberPattern.getGeneralMember());
     }
     if (memberPattern.hasFieldMember()) {
-      // return KeepFieldPattern.builder().applyProto(memberPattern.getFieldMember());
-      throw new Unimplemented();
+      return KeepFieldPattern.fromFieldMemberProto(memberPattern.getFieldMember());
     }
     if (memberPattern.hasMethodMember()) {
-      return KeepMethodPattern.fromMethodProto(memberPattern.getMethodMember());
+      return KeepMethodPattern.fromMethodMemberProto(memberPattern.getMethodMember());
     }
     return KeepMemberPattern.allMembers();
   }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
index c8f83b2..5b3a1bd 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
@@ -5,7 +5,9 @@
 
 import com.android.tools.r8.keepanno.keeprules.RulePrinter;
 import com.android.tools.r8.keepanno.keeprules.RulePrintingUtils;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.MemberAccessMethod;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class KeepMethodAccessPattern extends KeepMemberAccessPattern {
 
@@ -53,6 +55,24 @@
     this.strictFpPattern = strictFpPattern;
   }
 
+  public static KeepMethodAccessPattern fromMethodProto(MemberAccessMethod proto) {
+    return builder().applyMethodProto(proto).build();
+  }
+
+  public void buildMethodProto(Consumer<MemberAccessMethod.Builder> callback) {
+    if (isAny()) {
+      return;
+    }
+    MemberAccessMethod.Builder builder = MemberAccessMethod.newBuilder();
+    buildGeneralProto(builder::setGeneralAccess);
+    synchronizedPattern.buildProto(builder::setSynchronizedPattern);
+    bridgePattern.buildProto(builder::setBridgePattern);
+    nativePattern.buildProto(builder::setNativePattern);
+    abstractPattern.buildProto(builder::setAbstractPattern);
+    strictFpPattern.buildProto(builder::setStrictFpPattern);
+    callback.accept(builder);
+  }
+
   @Override
   public String toString() {
     if (isAny()) {
@@ -123,6 +143,33 @@
       return pattern.isAny() ? anyMethodAccess() : pattern;
     }
 
+    public Builder applyMethodProto(MemberAccessMethod proto) {
+      if (proto.hasGeneralAccess()) {
+        applyGeneralProto(proto.getGeneralAccess());
+      }
+      assert synchronizedPattern.isAny();
+      if (proto.hasSynchronizedPattern()) {
+        setSynchronized(proto.getSynchronizedPattern().getValue());
+      }
+      assert bridgePattern.isAny();
+      if (proto.hasBridgePattern()) {
+        setBridge(proto.getBridgePattern().getValue());
+      }
+      assert nativePattern.isAny();
+      if (proto.hasNativePattern()) {
+        setNative(proto.getNativePattern().getValue());
+      }
+      assert abstractPattern.isAny();
+      if (proto.hasAbstractPattern()) {
+        setAbstract(proto.getAbstractPattern().getValue());
+      }
+      assert strictFpPattern.isAny();
+      if (proto.hasStrictFpPattern()) {
+        setStrictFp(proto.getStrictFpPattern().getValue());
+      }
+      return this;
+    }
+
     public Builder setSynchronized(boolean allow) {
       synchronizedPattern = ModifierPattern.fromAllowValue(allow);
       return this;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
index 504bba8..11f5cea 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
@@ -34,17 +34,16 @@
       return this;
     }
 
-    public Builder applyProto(MemberPatternMethod methodMember) {
+    public Builder applyProto(MemberPatternMethod proto) {
       assert namePattern.isAny();
-      if (methodMember.hasName()) {
+      if (proto.hasName()) {
         setNamePattern(
-            KeepMethodNamePattern.fromStringPattern(
-                KeepStringPattern.fromProto(methodMember.getName())));
+            KeepMethodNamePattern.fromStringPattern(KeepStringPattern.fromProto(proto.getName())));
       }
 
       assert returnTypePattern.isAny();
-      if (methodMember.hasReturnType()) {
-        MethodReturnTypePattern returnType = methodMember.getReturnType();
+      if (proto.hasReturnType()) {
+        MethodReturnTypePattern returnType = proto.getReturnType();
         if (returnType.hasVoidType()) {
           setReturnTypeVoid();
         } else if (returnType.hasSomeType()) {
@@ -55,8 +54,8 @@
       }
 
       assert parametersPattern.isAny();
-      if (methodMember.hasParameterTypes()) {
-        MethodParameterTypesPattern parameterTypes = methodMember.getParameterTypes();
+      if (proto.hasParameterTypes()) {
+        MethodParameterTypesPattern parameterTypes = proto.getParameterTypes();
         KeepMethodParametersPattern.Builder parametersBuilder =
             KeepMethodParametersPattern.builder();
         for (TypePattern typePattern : parameterTypes.getTypesList()) {
@@ -65,8 +64,15 @@
         setParametersPattern(parametersBuilder.build());
       }
 
-      // TODO(b/343389186): Add annotated-by.
-      // TODO(b/343389186): Add access.
+      assert accessPattern.isAny();
+      if (proto.hasAccess()) {
+        setAccessPattern(KeepMethodAccessPattern.fromMethodProto(proto.getAccess()));
+      }
+
+      assert annotatedByPattern.isAbsent();
+      if (proto.hasAnnotatedBy()) {
+        setAnnotatedByPattern(KeepSpecUtils.annotatedByFromProto(proto.getAnnotatedBy()));
+      }
       return this;
     }
 
@@ -217,7 +223,7 @@
         + '}';
   }
 
-  public static KeepMemberPattern fromMethodProto(MemberPatternMethod methodMember) {
+  public static KeepMemberPattern fromMethodMemberProto(MemberPatternMethod methodMember) {
     return builder().applyProto(methodMember).build();
   }
 
@@ -229,8 +235,8 @@
     if (!parametersPattern.isAny()) {
       builder.setParameterTypes(parametersPattern.buildProto());
     }
-    // TODO(b/343389186): Add annotated-by.
-    // TODO(b/343389186): Add access.
+    accessPattern.buildMethodProto(builder::setAccess);
+    KeepSpecUtils.buildAnnotatedByProto(annotatedByPattern, builder::setAnnotatedBy);
     return builder;
   }
 }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java
index 16d9ef2..3483ff7 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPackagePattern.java
@@ -45,7 +45,7 @@
 
   public static class Builder {
 
-    private KeepPackagePattern pattern;
+    private KeepPackagePattern pattern = KeepPackagePattern.any();
 
     public Builder applyProto(PackagePattern pkg) {
       if (pkg.hasExactPackageHack()) {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java
index 246b20c..2cdf7d9 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepPreconditions.java
@@ -3,12 +3,18 @@
 // 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.KeepSpecUtils.BindingResolver;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Condition;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
 
 public abstract class KeepPreconditions {
 
+  public static KeepPreconditions fromProto(List<Condition> protoList, BindingResolver resolver) {
+    return builder().applyProto(protoList, resolver).build();
+  }
+
   public abstract void forEach(Consumer<KeepCondition> fn);
 
   public static class Builder {
@@ -17,6 +23,14 @@
 
     private Builder() {}
 
+    public Builder applyProto(List<Condition> protoList, BindingResolver resolver) {
+      for (Condition condition : protoList) {
+        addCondition(KeepCondition.fromProto(condition, resolver));
+      }
+      assert !protoList.isEmpty() || build().isAlways();
+      return this;
+    }
+
     public Builder addCondition(KeepCondition condition) {
       preconditions.add(condition);
       return this;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
index 4b1fcf7..94445bb 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
@@ -50,7 +50,8 @@
   }
 
   public ClassNamePattern.Builder buildProto() {
-    return ClassNamePattern.newBuilder()
+    ClassNamePattern.Builder builder = ClassNamePattern.newBuilder();
+    return builder
         .setPackage(packagePattern.buildProto())
         .setUnqualifiedName(namePattern.buildProto());
   }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java
index b5f934b..5a76764 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java
@@ -4,8 +4,9 @@
 
 package com.android.tools.r8.keepanno.ast;
 
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.AnnotatedByPattern;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.TypeDesc;
-import com.google.protobuf.MessageOrBuilder;
 import java.util.function.Consumer;
 
 public final class KeepSpecUtils {
@@ -15,4 +16,49 @@
   public static TypeDesc desc(String descriptor) {
     return TypeDesc.newBuilder().setDesc(descriptor).build();
   }
+
+  // Helper to resolve binding reference strings into symbols when parsing protos.
+  public static class BindingResolver {
+
+    // Builder is retained to resolve and does not escape this resolver.
+    private final KeepBindings.Builder builder;
+
+    // Bindings is the "build once" structure of the actual bindings.
+    private final KeepBindings bindings;
+
+    public BindingResolver(KeepBindings.Builder builder) {
+      this.builder = builder;
+      this.bindings = builder.build();
+    }
+
+    public KeepBindings getBindings() {
+      return bindings;
+    }
+
+    public KeepBindingReference mapReference(KeepSpecProtos.BindingReference reference) {
+      if (reference == null || reference.getName().isEmpty()) {
+        throw new KeepEdgeException("Invalid binding reference");
+      }
+      return builder.getBindingReferenceForUserBinding(reference.getName());
+    }
+  }
+
+  // Helpers to read/write the annotated-by pattern which does not have its own AST node.
+  public static void buildAnnotatedByProto(
+      OptionalPattern<KeepQualifiedClassNamePattern> pattern,
+      Consumer<AnnotatedByPattern.Builder> callback) {
+    // If the annotated-by pattern is absent then no restrictions are present, and we don't set it.
+    if (pattern.isPresent()) {
+      callback.accept(AnnotatedByPattern.newBuilder().setName(pattern.get().buildProto()));
+    }
+  }
+
+  public static OptionalPattern<KeepQualifiedClassNamePattern> annotatedByFromProto(
+      AnnotatedByPattern proto) {
+    if (!proto.hasName()) {
+      // No name implies any annotation (in contrast to no restrictions).
+      return OptionalPattern.of(KeepQualifiedClassNamePattern.any());
+    }
+    return OptionalPattern.of(KeepQualifiedClassNamePattern.fromProto(proto.getName()));
+  }
 }
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 0d7dc03..1a8321b 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
@@ -3,10 +3,22 @@
 // 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.KeepSpecUtils.BindingResolver;
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos.Target;
 import java.util.Objects;
 
 public class KeepTarget {
 
+  public Target.Builder buildProto() {
+    Target.Builder builder = Target.newBuilder();
+    constraints.buildProto(builder::setConstraints, builder::addConstraintAdditions);
+    return builder.setItem(item.buildProto());
+  }
+
+  public static KeepTarget fromProto(Target proto, BindingResolver resolver) {
+    return builder().applyProto(proto, resolver).build();
+  }
+
   public static class Builder {
 
     private KeepBindingReference item;
@@ -14,6 +26,16 @@
 
     private Builder() {}
 
+    public Builder applyProto(Target proto, BindingResolver resolver) {
+      setItemReference(resolver.mapReference(proto.getItem()));
+      assert constraints.isDefault();
+      constraints.fromProto(
+          proto.hasConstraints() ? proto.getConstraints() : null,
+          proto.getConstraintAdditionsList(),
+          this::setConstraints);
+      return this;
+    }
+
     public Builder setItemReference(KeepBindingReference itemReference) {
       this.item = itemReference;
       return this;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
index a123e61..15cfef7 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.keepanno.ast;
 
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.TypePattern;
-import com.android.tools.r8.keepanno.utils.Unimplemented;
 import com.google.common.collect.ImmutableMap;
 import java.util.Map;
 import java.util.Objects;
@@ -58,21 +57,6 @@
     throw new KeepEdgeException("Invalid type descriptor: " + typeDescriptor);
   }
 
-  public static KeepTypePattern fromProto(TypePattern typeProto) {
-    if (typeProto.hasPrimitive()) {
-      return KeepTypePattern.fromPrimitive(
-          KeepPrimitiveTypePattern.fromProto(typeProto.getPrimitive()));
-    }
-    if (typeProto.hasArray()) {
-      return KeepTypePattern.fromArray(KeepArrayTypePattern.fromProto(typeProto.getArray()));
-    }
-    if (typeProto.hasClazz()) {
-      return KeepTypePattern.fromClass(
-          KeepQualifiedClassNamePattern.fromProto(typeProto.getClazz()));
-    }
-    return KeepTypePattern.any();
-  }
-
   public abstract <T> T apply(
       Supplier<T> onAny,
       Function<KeepPrimitiveTypePattern, T> onPrimitive,
@@ -281,6 +265,25 @@
     }
   }
 
+  public static KeepTypePattern fromProto(TypePattern typeProto) {
+    if (typeProto.hasPrimitive()) {
+      return KeepTypePattern.fromPrimitive(
+          KeepPrimitiveTypePattern.fromProto(typeProto.getPrimitive()));
+    }
+    if (typeProto.hasArray()) {
+      return KeepTypePattern.fromArray(KeepArrayTypePattern.fromProto(typeProto.getArray()));
+    }
+    if (typeProto.hasClazz()) {
+      return KeepTypePattern.fromClass(
+          KeepQualifiedClassNamePattern.fromProto(typeProto.getClazz()));
+    }
+    if (typeProto.hasInstanceOf()) {
+      return KeepTypePattern.fromInstanceOf(
+          KeepInstanceOfPattern.fromProto(typeProto.getInstanceOf()));
+    }
+    return KeepTypePattern.any();
+  }
+
   public TypePattern.Builder buildProto() {
     TypePattern.Builder builder = TypePattern.newBuilder();
     match(
@@ -291,7 +294,14 @@
         array -> builder.setArray(array.buildProto()),
         clazz -> builder.setClazz(clazz.buildProto()),
         instanceOf -> {
-          throw new Unimplemented();
+          if (instanceOf.isAny()) {
+            // Note that an "any" instance-of pattern should match any class-type
+            // TODO(b/350647134): This should become evident when introducing a class-pattern.
+            //  When doing so, consider also if/how to match a general reference type.
+            builder.setClazz(KeepQualifiedClassNamePattern.any().buildProto());
+          } else {
+            instanceOf.buildProto(builder::setInstanceOf);
+          }
         });
     return builder;
   }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java
index 77ce8ad..1afe19e 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.keepanno.ast;
 
+import com.android.tools.r8.keepanno.proto.KeepSpecProtos;
+import java.util.function.Consumer;
+
 /** Three-point valued matcher on an access modifier. */
 public class ModifierPattern {
 
@@ -69,4 +72,12 @@
   public int hashCode() {
     return System.identityHashCode(this);
   }
+
+  public void buildProto(Consumer<KeepSpecProtos.ModifierPattern.Builder> callback) {
+    if (isOnlyPositive()) {
+      callback.accept(KeepSpecProtos.ModifierPattern.newBuilder().setValue(true));
+    } else if (isOnlyNegative()) {
+      callback.accept(KeepSpecProtos.ModifierPattern.newBuilder().setValue(false));
+    }
+  }
 }
diff --git a/src/keepanno/proto/keepspec.proto b/src/keepanno/proto/keepspec.proto
index 451b137..fd52a93 100644
--- a/src/keepanno/proto/keepspec.proto
+++ b/src/keepanno/proto/keepspec.proto
@@ -83,7 +83,9 @@
 
 message Edge {
   MetaInfo meta_info = 1;
-  // TODO(b/343389186): Add content.
+  Bindings bindings = 2;
+  repeated Condition preconditions = 3;
+  repeated Target consequences = 4;
 }
 
 message Bindings {
@@ -99,6 +101,55 @@
   string name = 1;
 }
 
+message Condition {
+  BindingReference item = 1;
+}
+
+message Target {
+  BindingReference item = 1;
+  optional Constraints constraints = 2;
+  repeated Constraint constraint_additions = 3;
+}
+
+message Constraints {
+  repeated Constraint constraints = 1;
+}
+
+enum ConstraintElement {
+  CONSTRAINT_UNSPECIFIED = 0;
+  CONSTRAINT_LOOKUP = 1;
+  CONSTRAINT_NAME = 2;
+  CONSTRAINT_VISIBILITY_RELAX = 3;
+  CONSTRAINT_VISIBILITY_RESTRICT = 4;
+  CONSTRAINT_NEVER_INLINE = 5;
+  CONSTRAINT_CLASS_INSTANTIATE = 6;
+  CONSTRAINT_CLASS_OPEN_HIERARCHY = 7;
+  CONSTRAINT_METHOD_INVOKE = 8;
+  CONSTRAINT_METHOD_REPLACE = 9;
+  CONSTRAINT_FIELD_GET = 10;
+  CONSTRAINT_FIELD_SET = 11;
+  CONSTRAINT_FIELD_REPLACE = 12;
+  CONSTRAINT_GENERIC_SIGNATURE = 13;
+}
+
+message AnnotationPattern {
+  optional AnnotationRetention retention = 1;
+  optional ClassNamePattern name = 2;
+}
+
+enum AnnotationRetention {
+  RETENTION_UNSPECIFIED = 0;
+  RETENTION_RUNTIME = 1;
+  RETENTION_CLASS = 2;
+}
+
+message Constraint {
+  oneof constraint_oneof {
+    ConstraintElement element = 1;
+    AnnotationPattern annotation = 2;
+  }
+}
+
 message ItemPattern {
   oneof item_oneof {
     ClassItemPattern class_item = 1;
@@ -108,8 +159,13 @@
 
 message ClassItemPattern {
   optional ClassNamePattern class_name = 1;
-  // TODO(b/343389186): Add instance-of.
-  // TODO(b/343389186): Add annotated-by.
+  optional InstanceOfPattern instance_of = 2;
+  optional AnnotatedByPattern annotated_by = 3;
+}
+
+message InstanceOfPattern {
+  optional bool inclusive = 1;
+  optional ClassNamePattern class_name = 2;
 }
 
 message ClassNamePattern {
@@ -151,6 +207,10 @@
   optional StringPattern name = 1;
 }
 
+message AnnotatedByPattern {
+  optional ClassNamePattern name = 1;
+}
+
 message MemberItemPattern {
   BindingReference class_reference = 1;
   optional MemberPattern member_pattern = 2;
@@ -164,20 +224,64 @@
   }
 }
 
+enum AccessVisibility {
+  ACCESS_UNSPECIFIED = 0;
+  ACCESS_PUBLIC = 1;
+  ACCESS_PROTECTED = 2;
+  ACCESS_PACKAGE_PRIVATE = 3;
+  ACCESS_PRIVATE = 4;
+}
+
+message AccessVisibilitySet {
+  repeated AccessVisibility access_visibility = 1;
+}
+
+// Placeholder for an optional boolean modifier.
+// The optional value is encoded by it not being present at the reference point.
+message ModifierPattern {
+  bool value = 1;
+}
+
+message MemberAccessGeneral {
+  optional AccessVisibilitySet access_visibility = 1;
+  optional ModifierPattern static_pattern = 2;
+  optional ModifierPattern final_pattern = 3;
+  optional ModifierPattern synthetic_pattern = 4;
+}
+
+message MemberAccessField {
+  optional MemberAccessGeneral general_access = 1;
+  optional ModifierPattern volatile_pattern = 2;
+  optional ModifierPattern transient_pattern = 3;
+}
+
+message MemberAccessMethod {
+  optional MemberAccessGeneral general_access = 1;
+  optional ModifierPattern synchronized_pattern = 2;
+  optional ModifierPattern bridge_pattern = 3;
+  optional ModifierPattern native_pattern = 4;
+  optional ModifierPattern abstract_pattern = 5;
+  optional ModifierPattern strict_fp_pattern = 6;
+}
+
 message MemberPatternGeneral {
-  // TODO(b/343389186): Add content.
+  optional MemberAccessGeneral access = 1;
+  optional AnnotatedByPattern annotated_by = 2;
 }
 
 message MemberPatternField {
-  // TODO(b/343389186): Add content.
+  optional MemberAccessField access = 1;
+  optional AnnotatedByPattern annotated_by = 2;
+  optional StringPattern name = 3;
+  optional TypePattern field_type = 4;
 }
 
 message MemberPatternMethod {
-  optional StringPattern name = 1;
-  optional MethodReturnTypePattern return_type = 2;
-  optional MethodParameterTypesPattern parameter_types = 3;
-  // TODO(b/343389186): Add annotated-by.
-  // TODO(b/343389186): Add access.
+  optional MemberAccessMethod access = 1;
+  optional AnnotatedByPattern annotated_by = 2;
+  optional StringPattern name = 3;
+  optional MethodReturnTypePattern return_type = 4;
+  optional MethodParameterTypesPattern parameter_types = 5;
 }
 
 message MethodReturnTypePattern {
@@ -202,7 +306,7 @@
     TypePatternPrimitive primitive = 1;
     TypePatternArray array = 2;
     ClassNamePattern clazz = 3;
-    // TODO(b/343389186): Add instance-of.
+    InstanceOfPattern instance_of = 4;
   }
 }
 
@@ -223,4 +327,3 @@
   optional uint32 dimensions = 1;
   optional TypePattern base_type = 2;
 }
-
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepSpecificationSource.java b/src/main/java/com/android/tools/r8/shaking/KeepSpecificationSource.java
index 1dfda01..72f1164 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepSpecificationSource.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepSpecificationSource.java
@@ -45,7 +45,8 @@
       throw new ResourceException(getOrigin(), "Unknown keepspec version " + spec.getVersion());
     }
     for (Declaration declaration : spec.getDeclarationsList()) {
-      KeepDeclaration parsedDeclaration = KeepDeclaration.fromProto(declaration, version);
+      KeepDeclaration parsedDeclaration =
+          KeepDeclaration.fromDeclarationProto(declaration, version);
       if (parsedDeclaration == null) {
         throw new ResourceException(getOrigin(), "Unable to parse declaration " + declaration);
       } else {
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java b/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java
index f39df8f..2c328d0 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.keepanno;
 
-import static com.android.tools.r8.utils.CfUtils.extractClassDescriptor;
 
 import com.android.tools.r8.ExternalR8TestBuilder;
 import com.android.tools.r8.ProguardTestBuilder;
@@ -18,18 +17,13 @@
 import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.keepanno.KeepAnnoParameters.KeepAnnoConfig;
 import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
-import com.android.tools.r8.keepanno.asm.KeepEdgeWriter;
 import com.android.tools.r8.keepanno.ast.KeepDeclaration;
 import com.android.tools.r8.keepanno.ast.KeepSpecVersion;
 import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractorOptions;
 import com.android.tools.r8.keepanno.proto.KeepSpecProtos.KeepSpec;
-import com.android.tools.r8.keepanno.utils.Unimplemented;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -38,8 +32,6 @@
 import java.util.List;
 import java.util.function.Consumer;
 import org.junit.rules.TemporaryFolder;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.Opcodes;
 
 public abstract class KeepAnnoTestBuilder {
 
@@ -283,49 +275,14 @@
       if (isNormalizeEdges()) {
         List<KeepDeclaration> declarations = KeepEdgeReader.readKeepEdges(classFileData);
         if (!declarations.isEmpty()) {
-          List<KeepDeclaration> legacyExtract = new ArrayList<>();
           KeepSpec.Builder keepSpecBuilder = KeepSpec.newBuilder();
           keepSpecBuilder.setVersion(KeepSpecVersion.getCurrent().buildProto());
           for (KeepDeclaration declaration : declarations) {
-            try {
-              keepSpecBuilder.addDeclarations(declaration.buildDeclarationProto());
-            } catch (Unimplemented e) {
-              legacyExtract.add(declaration);
-            }
+            keepSpecBuilder.addDeclarations(declaration.buildDeclarationProto());
           }
           builder
               .getBuilder()
               .addKeepSpecificationData(keepSpecBuilder.build().toByteArray(), Origin.unknown());
-          if (legacyExtract.isEmpty()) {
-            // TODO(b/343389186): Finish the proto encoding and remove the below extraction.
-            return;
-          }
-          String binaryName =
-              DescriptorUtils.getBinaryNameFromDescriptor(extractClassDescriptor(classFileData));
-          String synthesizingTarget = binaryName + "$$ExtractedKeepEdges";
-          ClassWriter classWriter = new ClassWriter(InternalOptions.ASM_VERSION);
-          classWriter.visit(
-              Opcodes.V1_8,
-              ClassAccessFlags.createPublicFinalSynthetic().getAsCfAccessFlags(),
-              synthesizingTarget,
-              null,
-              "java/lang/Object",
-              null);
-          KeepEdgeWriter.writeExtractedEdges(
-              legacyExtract,
-              (descriptor, visible) ->
-                  KeepAnnoTestUtils.wrap(classWriter.visitAnnotation(descriptor, visible)));
-          classWriter.visitEnd();
-          builder
-              .getBuilder()
-              .addClassProgramData(
-                  classWriter.toByteArray(),
-                  new Origin(Origin.root()) {
-                    @Override
-                    public String part() {
-                      return "edge-extraction";
-                    }
-                  });
         }
       }
     }
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepInclusiveInstanceOfTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepInclusiveInstanceOfTest.java
index 85809df..1293e79 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepInclusiveInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepInclusiveInstanceOfTest.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.keepanno;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
 import com.android.tools.r8.keepanno.annotations.KeepTarget;
 import com.android.tools.r8.keepanno.annotations.UsesReflection;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -34,11 +37,14 @@
         .addKeepMainRule(TestClass.class)
         .setExcludedOuterClass(getClass())
         .run(TestClass.class)
-        .assertSuccessWithOutput(EXPECTED);
+        .assertSuccessWithOutput(EXPECTED)
+        .applyIf(
+            parameters.isShrinker(),
+            r -> r.inspect(inspector -> assertThat(inspector.clazz(Unrelated.class), isAbsent())));
   }
 
   public List<Class<?>> getInputClasses() {
-    return ImmutableList.of(TestClass.class, Base.class, Sub.class, A.class);
+    return ImmutableList.of(TestClass.class, Base.class, Sub.class, A.class, Unrelated.class);
   }
 
   static class Base {
@@ -53,6 +59,12 @@
     }
   }
 
+  static class Unrelated {
+    static void hiddenMethod() {
+      System.out.println("on Unrelated");
+    }
+  }
+
   static class A {
 
     @UsesReflection({
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java
index 8c96fe1..f85dcd7 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionOnFieldTest.java
@@ -41,19 +41,6 @@
         .addProgramClasses(getInputClasses())
         .addKeepMainRule(TestClass.class)
         .setExcludedOuterClass(getClass())
-        .inspectOutputConfig(
-            rules -> {
-              if (parameters.isNativeR8()) {
-                // TODO(b/323816623): Once a final distribution format is defined for normalized
-                //  edges, that format should likely be the bases of the annotation printing too.
-                assertThat(rules, containsString("context=" + descriptor(A.class) + "foo()V"));
-                assertThat(
-                    rules, containsString("description=\"Keep the\\nstring-valued fields\""));
-              } else {
-                assertThat(rules, containsString("context: " + descriptor(A.class) + "foo()V"));
-                assertThat(rules, containsString("description: Keep the\\nstring-valued fields"));
-              }
-            })
         .run(TestClass.class)
         .assertSuccessWithOutput(EXPECTED)
         .applyIf(parameters.isShrinker(), r -> r.inspect(this::checkOutput));