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;