Extend testing for conditional keep on field

Add test for proguard and add test for not keeping the class if no live references.

Bug: b/239634618
Change-Id: I84e23fdf863e2871cd4c52a0ffadd341ea8bdc44
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfRuleWithFieldAnnotation.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfRuleWithFieldAnnotation.java
index 3349571..8105b81 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfRuleWithFieldAnnotation.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfRuleWithFieldAnnotation.java
@@ -3,9 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking.ifrule;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
 
+import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -19,6 +22,15 @@
 public class IfRuleWithFieldAnnotation extends TestBase {
 
   static final String EXPECTED = "foobar";
+  public static final String CONDITIONAL_KEEP_RULE =
+      "-if class * {"
+          + " @com.android.tools.r8.shaking.ifrule.IfRuleWithFieldAnnotation$SerializedName"
+          + " <fields>; }\n"
+          + "-keep,allowobfuscation class <1> {\n"
+          + "  <init>(...);\n"
+          + "  @com.android.tools.r8.shaking.ifrule.IfRuleWithFieldAnnotation$SerializedNamed"
+          + " <fields>;\n"
+          + "}";
 
   private final TestParameters parameters;
 
@@ -36,15 +48,7 @@
     testForR8(parameters.getBackend())
         .addProgramClasses(Foo.class, Bar.class, SerializedName.class)
         .addKeepMainRule(Foo.class)
-        .addKeepRules(
-            "-if class * {"
-                + " @com.android.tools.r8.shaking.ifrule.IfRuleWithFieldAnnotation$SerializedName"
-                + " <fields>; }\n"
-                + "-keep,allowobfuscation class <1> {\n"
-                + "  <init>(...);\n"
-                + "  @com.android.tools.r8.shaking.ifrule.IfRuleWithFieldAnnotation$SerializedNamed"
-                + " <fields>;\n"
-                + "}")
+        .addKeepRules(CONDITIONAL_KEEP_RULE)
         .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(
@@ -54,13 +58,75 @@
             })
         .run(parameters.getRuntime(), Foo.class)
         .assertSuccessWithOutputLines(EXPECTED);
+    // We should remove the class if the usage of the field is not live.
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Foo.class, Bar.class, SerializedName.class, FooNotCallingBar.class)
+        .addKeepMainRule(FooNotCallingBar.class)
+        .addKeepRules(CONDITIONAL_KEEP_RULE)
+        .allowUnusedProguardConfigurationRules()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            codeInspector -> {
+              assertThat(codeInspector.clazz(Bar.class), isAbsent());
+            })
+        .run(parameters.getRuntime(), FooNotCallingBar.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testProguard() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForProguard(ProguardVersion.V7_0_0)
+        .addProgramClasses(Foo.class, Bar.class, SerializedName.class)
+        .addDontWarn(getClass())
+        .addKeepMainRule(Foo.class)
+        .addKeepRules(CONDITIONAL_KEEP_RULE)
+        .compile()
+        .inspect(
+            codeInspector -> {
+              assertThat(codeInspector.clazz(Bar.class).field("int", "value"), isPresent());
+              assertThat(codeInspector.clazz(Bar.class).init("int"), isPresent());
+            })
+        .run(parameters.getRuntime(), Foo.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+    testForProguard(ProguardVersion.V7_0_0)
+        .addProgramClasses(Foo.class, Bar.class, SerializedName.class, FooNotCallingBar.class)
+        .addDontWarn(getClass())
+        .addKeepMainRule(FooNotCallingBar.class)
+        .noMinification()
+        .addKeepRules(CONDITIONAL_KEEP_RULE)
+        .compile()
+        .inspect(
+            codeInspector -> {
+              // The if rule above will make proguard keep the class and the constructor, but not
+              // the field. If we don't have the rule, proguard will remove the class, see test
+              // below.
+              assertThat(codeInspector.clazz(Bar.class), isPresent());
+              assertThat(codeInspector.clazz(Bar.class).init("int"), isPresent());
+              assertThat(codeInspector.clazz(Bar.class).field("int", "value"), isAbsent());
+            })
+        .run(parameters.getRuntime(), FooNotCallingBar.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+    // Test that without the conditional keep rule proguard correctly removes the class.
+    testForProguard(ProguardVersion.V7_0_0)
+        .addProgramClasses(Foo.class, Bar.class, SerializedName.class, FooNotCallingBar.class)
+        .addDontWarn(getClass())
+        .addKeepMainRule(FooNotCallingBar.class)
+        .noMinification()
+        .compile()
+        .inspect(
+            codeInspector -> {
+              assertThat(codeInspector.clazz(Bar.class), isAbsent());
+            })
+        .run(parameters.getRuntime(), FooNotCallingBar.class)
+        .assertSuccessWithOutputLines(EXPECTED);
   }
 
   @Retention(RetentionPolicy.RUNTIME)
   public @interface SerializedName {}
 
   public static class Foo {
-    public static Object object;
 
     public static void main(String[] args) {
       callOnBar(args);
@@ -84,6 +150,12 @@
     }
   }
 
+  public static class FooNotCallingBar {
+    public static void main(String[] args) {
+      System.out.println("foobar");
+    }
+  }
+
   public static class Bar {
     @SerializedName public int value;