[KeepAnno] Support edges with field preconditions

Edges with field (or class) preconditions are currently soft-pinned as
done for legacy rules. Follow-up work should remove the restriction by
tracking changes via the lens or "original positions" as done for
methods.

Bug: b/323816623
Change-Id: I1729a413299cdf05d8a17c1233b810bb5be58293
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 23fcee7..7138f53 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1688,11 +1688,11 @@
     }
   }
 
-  void markEffectivelyLiveOriginalReference(DexMethod method) {
-    // TODO(b/325014359): It might be reasonable to reduce this map size by tracking which methods
+  void markEffectivelyLiveOriginalReference(DexReference reference) {
+    // TODO(b/325014359): It might be reasonable to reduce this map size by tracking which items
     //  actually are used in preconditions.
-    if (effectivelyLiveOriginalReferences.add(method)) {
-      effectivelyLiveOriginalReferences.add(method.getHolderType());
+    if (effectivelyLiveOriginalReferences.add(reference) && reference.isDexMember()) {
+      effectivelyLiveOriginalReferences.add(reference.getContextType());
     }
   }
 
@@ -3274,6 +3274,13 @@
     }
   }
 
+  private void addEffectivelyLiveOriginalField(ProgramField field) {
+    if (!options.testing.isKeepAnnotationsEnabled()) {
+      return;
+    }
+    markEffectivelyLiveOriginalReference(field.getReference());
+  }
+
   private void markFieldAsLive(ProgramField field, ProgramMethod context) {
     markFieldAsLive(field, context, KeepReason.fieldReferencedIn(context));
   }
@@ -3286,6 +3293,7 @@
       // Already live.
       return;
     }
+    addEffectivelyLiveOriginalField(field);
 
     // Mark the field as targeted.
     if (field.getAccessFlags().isStatic()) {
@@ -3327,13 +3335,12 @@
       graphReporter.registerField(field.getDefinition(), reason);
       return;
     }
-
+    addEffectivelyLiveOriginalField(field);
     traceFieldDefinition(field);
 
     analyses.forEach(analysis -> analysis.notifyMarkFieldAsReachable(field, worklist));
   }
 
-  @SuppressWarnings("UnusedVariable")
   private void traceFieldDefinition(ProgramField field) {
     markTypeAsLive(field.getHolder(), field);
     markTypeAsLive(field.getType(), field);
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 13b1b4f..82c28fb 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
@@ -107,6 +107,19 @@
               minimumKeepInfoCollection.getOrCreateMinimumKeepInfoFor(item.getReference());
           updateWithConstraints(item, joiner, result.constraints.get(i), result.edge);
         });
+    // TODO(b/323816623): Encode originals instead of soft-pinning class/field preconditions.
+    for (ProgramDefinition precondition : result.preconditions) {
+      if (precondition.isClass() || precondition.isField()) {
+        minimumKeepInfoCollection
+            .getOrCreateMinimumKeepInfoFor(precondition.getReference())
+            .disallowOptimization();
+        if (precondition.isField()) {
+          minimumKeepInfoCollection
+              .getOrCreateMinimumKeepInfoFor(precondition.getContextType())
+              .disallowOptimization();
+        }
+      }
+    }
     return minimumKeepInfoCollection;
   }
 
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
index 92f2515..15f96ab 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
@@ -35,6 +35,7 @@
   @Test
   public void test() throws Exception {
     testForKeepAnno(parameters)
+        .enableNativeInterpretation()
         .addProgramClasses(getInputClasses())
         .addKeepMainRule(TestClass.class)
         .setExcludedOuterClass(getClass())