Only include default <init>() for empty member rules in compat mode
RELNOTES:
This fixes a bug in R8 full mode where keep rules with absent or empty member rules would implicitly be converted into a stronger keep rule that has a member rule matching the default constructor.
Example:
1. The rule -keep class A would implicitly be converted to -keep class A { void <init>(); }.
2. The rule -keep class A {} would implicitly be converted to -keep class A { void <init>(); }.
For consistency with the R8 full mode documentation in compatibility-faq.md ("The default constructor (<init>()) is not implicitly kept when a class is kept."), this change limits the implicit inclusion of void <init>() to Proguard compatibility mode.
Note that starting with this change, -keepclassmembers rules with no member rules (e.g., -keepclassmembers class A) do no longer have any effect in R8 full mode.
Fixes: b/132318799
Fixes: b/323136645
Change-Id: Ic6049e561bcd35b7a45ee9c8c5b94e1780e538a1diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 819b349..adfaf29 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -669,11 +669,13 @@
ProguardConfigurationParser parser =
new ProguardConfigurationParser(
factory, reporter, parserOptionsBuilder.build(), inputDependencyGraphConsumer);
+ ProguardConfiguration.Builder configurationBuilder =
+ parser
+ .getConfigurationBuilder()
+ .setForceProguardCompatibility(forceProguardCompatibility);
if (!proguardConfigs.isEmpty()) {
parser.parse(proguardConfigs);
}
- ProguardConfiguration.Builder configurationBuilder = parser.getConfigurationBuilder();
- configurationBuilder.setForceProguardCompatibility(forceProguardCompatibility);
if (getMode() == CompilationMode.DEBUG) {
disableMinification = true;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 98bb147..165e520 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -273,8 +273,13 @@
keepDirectories.addPattern(pattern);
}
- public void setForceProguardCompatibility(boolean forceProguardCompatibility) {
+ public boolean isForceProguardCompatibility() {
+ return forceProguardCompatibility;
+ }
+
+ public Builder setForceProguardCompatibility(boolean forceProguardCompatibility) {
this.forceProguardCompatibility = forceProguardCompatibility;
+ return this;
}
public void setConfigurationDebugging(boolean configurationDebugging) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index b2dcea5..d59e2ef 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -846,15 +846,21 @@
.setStart(start);
parseRuleTypeAndModifiers(keepRuleBuilder);
parseClassSpec(keepRuleBuilder);
- if (keepRuleBuilder.getMemberRules().isEmpty()) {
- // If there are no member rules, a default rule for the parameterless constructor
- // applies. So we add that here.
- ProguardMemberRule.Builder defaultRuleBuilder = ProguardMemberRule.builder();
- defaultRuleBuilder.setName(
- IdentifierPatternWithWildcards.withoutWildcards(Constants.INSTANCE_INITIALIZER_NAME));
- defaultRuleBuilder.setRuleType(ProguardMemberType.INIT);
- defaultRuleBuilder.setArguments(Collections.emptyList());
- keepRuleBuilder.getMemberRules().add(defaultRuleBuilder.build());
+ if (configurationBuilder.isForceProguardCompatibility()
+ && keepRuleBuilder.getMemberRules().isEmpty()
+ && keepRuleBuilder.getKeepRuleType() != ProguardKeepRuleType.KEEP_CLASSES_WITH_MEMBERS) {
+ // If there are no member rules, a default rule for the parameterless constructor applies in
+ // compatibility mode.
+ keepRuleBuilder
+ .getMemberRules()
+ .add(
+ ProguardMemberRule.builder()
+ .setName(
+ IdentifierPatternWithWildcards.withoutWildcards(
+ Constants.INSTANCE_INITIALIZER_NAME))
+ .setRuleType(ProguardMemberType.INIT)
+ .setArguments(Collections.emptyList())
+ .build());
}
Position end = getPosition();
keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
index fb02899..308ab6e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
@@ -22,6 +22,10 @@
super();
}
+ public ProguardKeepRuleType getKeepRuleType() {
+ return type;
+ }
+
public B setType(ProguardKeepRuleType type) {
this.type = type;
return self();
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
index 1bd723a..bb999d8 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -333,7 +333,8 @@
@Test
public void testWithMembersStarRuleFullR8() throws Exception {
- testWithMembersStarRule(testForR8(parameters.getBackend()));
+ testWithMembersStarRule(
+ testForR8(parameters.getBackend()).allowUnusedProguardConfigurationRules());
}
// Tests for "-keepclassmembernames" and *no* minification.
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesExtendsTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesExtendsTest.java
index 08fde0f..16bc26e 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesExtendsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesExtendsTest.java
@@ -40,7 +40,7 @@
@Parameter(2)
public boolean repackage;
- static final String EXPECTED = StringUtils.lines("Success!");
+ static final String EXPECTED = StringUtils.lines("Sub1", "Sub2");
@Parameters(name = "{0}, keepPermittedSubclasses = {1}, repackage = {2}")
public static List<Object[]> data() {
@@ -131,15 +131,26 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
}
}
public abstract static class Super /* permits Sub1, Sub2 */ {}
- public static class Sub1 extends Super {}
+ public static class Sub1 extends Super {
- public static class Sub2 extends Super {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
+
+ public static class Sub2 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesHorizontalMergeTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesHorizontalMergeTest.java
index 270637d..9366ecf 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesHorizontalMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesHorizontalMergeTest.java
@@ -29,7 +29,7 @@
@Parameter(0)
public TestParameters parameters;
- static final String EXPECTED = StringUtils.lines("Success!");
+ static final String EXPECTED = StringUtils.lines("Sub1", "Sub2");
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -62,11 +62,10 @@
.addKeepClassRulesWithAllowObfuscation(Super.class)
.addKeepMainRule(TestClass.class)
.addHorizontallyMergedClassesInspector(
- inspector -> {
- inspector
- .assertIsCompleteMergeGroup(Sub2.class, Sub1.class)
- .assertNoOtherClassesMerged();
- })
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(Sub2.class, Sub1.class)
+ .assertNoOtherClassesMerged())
.compile()
.inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class)
@@ -85,15 +84,26 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
}
}
abstract static class Super /* permits Sub1, Sub2 */ {}
- static class Sub1 extends Super {}
+ static class Sub1 extends Super {
- static class Sub2 extends Super {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
+
+ static class Sub2 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassMergedTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassMergedTest.java
index b420268..7d5eefa 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassMergedTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassMergedTest.java
@@ -34,7 +34,7 @@
static final Matcher<String> EXPECTED = containsString("cannot inherit from sealed class");
static final String EXPECTED_WITHOUT_PERMITTED_SUBCLASSES_ATTRIBUTE_OR_FIXED_ATTRIBUTE =
- StringUtils.lines("Success!");
+ StringUtils.lines("Sub1", "Sub2");
@Parameters(name = "{0}, keepPermittedSubclasses = {1}")
public static TestParametersCollection data() {
@@ -101,15 +101,26 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
}
}
abstract static class Super /* permits Sub1 */ {}
- static class Sub1 extends Super {}
+ static class Sub1 extends Super {
- static class Sub2 extends Super {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
+
+ static class Sub2 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassTest.java
index 240b7a9..cf6aef5 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesIllegalSubclassTest.java
@@ -42,7 +42,7 @@
static final Matcher<String> EXPECTED = containsString("cannot inherit from sealed class");
static final String EXPECTED_WITHOUT_PERMITTED_SUBCLASSES_ATTRIBUTE =
- StringUtils.lines("Success!");
+ StringUtils.lines("Sub1", "Sub2", "Sub3");
@Parameters(name = "{0}, keepPermittedSubclasses = {1}")
public static List<Object[]> data() {
@@ -135,18 +135,35 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- new Sub3();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
+ System.out.println(new Sub3());
}
}
abstract static class Super /* permits Sub1, Sub2 */ {}
- static class Sub1 extends Super {}
+ static class Sub1 extends Super {
- static class Sub2 extends Super {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
- static class Sub3 extends Super {}
+ static class Sub2 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
+
+ static class Sub3 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub3";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesImplementsTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesImplementsTest.java
index ac61cf8..a275617 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesImplementsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesImplementsTest.java
@@ -38,7 +38,7 @@
@Parameter(1)
public boolean keepPermittedSubclassesAttribute;
- static final String EXPECTED = StringUtils.lines("Success!");
+ static final String EXPECTED = StringUtils.lines("Sub1", "Sub2");
@Parameters(name = "{0}, keepPermittedSubclasses = {1}")
public static List<Object[]> data() {
@@ -137,9 +137,8 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
}
}
@@ -147,7 +146,19 @@
interface Iface2 /* permits Sub1, Sub2 */ {}
- static class Sub1 implements Iface1, Iface2 {}
+ static class Sub1 implements Iface1, Iface2 {
- static class Sub2 implements Iface1 {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
+
+ static class Sub2 implements Iface1 {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesMergeTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesMergeTest.java
index bcd774a..74ee559 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesMergeTest.java
@@ -29,7 +29,7 @@
@Parameter(0)
public TestParameters parameters;
- static final String EXPECTED = StringUtils.lines("Success!");
+ static final String EXPECTED = StringUtils.lines("Sub1", "Sub2");
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -62,11 +62,10 @@
.addKeepClassRulesWithAllowObfuscation(Super.class)
.addKeepMainRule(TestClass.class)
.addHorizontallyMergedClassesInspector(
- inspector -> {
- inspector
- .assertIsCompleteMergeGroup(Sub2.class, Sub1.class)
- .assertNoOtherClassesMerged();
- })
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(Sub2.class, Sub1.class)
+ .assertNoOtherClassesMerged())
.compile()
.inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class)
@@ -85,15 +84,26 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
}
}
abstract static class Super /* permits Sub1, Sub2 */ {}
- static class Sub1 extends Super {}
+ static class Sub1 extends Super {
- static class Sub2 extends Super {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
+
+ static class Sub2 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesShrinkingTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesShrinkingTest.java
index 1893e3b..a5a68a0 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesShrinkingTest.java
@@ -79,14 +79,19 @@
static class TestClass {
public static void main(String[] args) {
- new UsedSub();
- System.out.println("Success!");
+ System.out.println(new UsedSub());
}
}
abstract static class Super /* permits UsedSub, UnusedSub */ {}
- static class UsedSub extends Super {}
+ static class UsedSub extends Super {
+
+ @Override
+ public String toString() {
+ return "Success!";
+ }
+ }
static class UnusedSub extends Super {}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesTestAllowPermittedSubclassesRemovalTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesTestAllowPermittedSubclassesRemovalTest.java
index c220e9d..4b96a42 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesTestAllowPermittedSubclassesRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedClassesTestAllowPermittedSubclassesRemovalTest.java
@@ -30,7 +30,7 @@
@Parameter(0)
public TestParameters parameters;
- static final String EXPECTED = StringUtils.lines("Success!");
+ static final String EXPECTED = StringUtils.lines("Sub1", "Sub2");
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -85,15 +85,26 @@
static class TestClass {
public static void main(String[] args) {
- new Sub1();
- new Sub2();
- System.out.println("Success!");
+ System.out.println(new Sub1());
+ System.out.println(new Sub2());
}
}
abstract static class Super /* permits Sub1, Sub2 */ {}
- static class Sub1 extends Super {}
+ static class Sub1 extends Super {
- static class Sub2 extends Super {}
+ @Override
+ public String toString() {
+ return "Sub1";
+ }
+ }
+
+ static class Sub2 extends Super {
+
+ @Override
+ public String toString() {
+ return "Sub2";
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java
index bf5614e..5c94d28 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterFieldTypeStrengtheningTest.java
@@ -66,8 +66,8 @@
testBuilder ->
testBuilder.addLibraryFiles(
parameters.getDefaultAndroidJarAbove(AndroidApiLevel.K)));
- assertEquals(processResult.exitCode, 0);
- assertEquals(processResult.stdout, EXPECTED);
+ assertEquals(processResult.stdout + processResult.stderr, 0, processResult.exitCode);
+ assertEquals(EXPECTED, processResult.stdout);
}
public abstract static class BaseSuperClass implements RunInterface {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/KeptClassInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/KeptClassInliningTest.java
index be84e82..0fd3754 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/KeptClassInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/KeptClassInliningTest.java
@@ -57,7 +57,7 @@
.enableInliningAnnotations()
.addProgramClasses(KeptClass.class, Main.class)
.addKeepMainRule(Main.class)
- .addKeepClassRules(KeptClass.class)
+ .addKeepClassAndDefaultConstructor(KeptClass.class)
.setMinApi(parameters)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("used()")
diff --git a/src/test/java/com/android/tools/r8/keepanno/compatissues/EmptyClassWithMembersRuleTest.java b/src/test/java/com/android/tools/r8/keepanno/compatissues/EmptyClassWithMembersRuleTest.java
index 3b1ef5f..1f16eb9 100644
--- a/src/test/java/com/android/tools/r8/keepanno/compatissues/EmptyClassWithMembersRuleTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/compatissues/EmptyClassWithMembersRuleTest.java
@@ -9,10 +9,12 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.transformers.ClassFileTransformer.FieldPredicate;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.StringUtils;
@@ -30,11 +32,16 @@
public enum Shrinker {
PG,
- R8;
+ R8,
+ R8_COMPAT;
public boolean isPG() {
return this == PG;
}
+
+ public boolean isCompat() {
+ return this == R8_COMPAT;
+ }
}
@Parameter(0)
@@ -48,12 +55,14 @@
return buildParameters(getTestParameters().withDefaultCfRuntime().build(), Shrinker.values());
}
- private TestRunResult<?> runTest(String... keepRules) throws Exception {
+ private TestRunResult<?> runTest(
+ ThrowableConsumer<TestShrinkerBuilder<?, ?, ?, ?, ?>> configuration) throws Exception {
TestShrinkerBuilder<?, ?, ?, ?, ?> builder;
if (shrinker.isPG()) {
- builder = testForProguard(ProguardVersion.getLatest()).addDontWarn(getClass());
+ builder =
+ testForProguard(ProguardVersion.getLatest()).addDontWarn(getClass()).apply(configuration);
} else {
- builder = testForR8(parameters.getBackend()).allowUnusedProguardConfigurationRules();
+ builder = testForR8Compat(parameters.getBackend(), shrinker.isCompat()).apply(configuration);
}
return builder
.addProgramClassFileData(
@@ -63,48 +72,61 @@
.transform())
.addProgramClasses(TestClass.class)
.addKeepMainRule(TestClass.class)
- .addKeepRules(keepRules)
.run(parameters.getRuntime(), TestClass.class);
}
@Test
public void testNoKeep() throws Exception {
- runTest("-keep class missingClassToForceUnusedRuleDiagnostic")
+ runTest(
+ builder ->
+ builder
+ .addKeepRules("-keep class missingClassToForceUnusedRuleDiagnostic")
+ .applyIfR8(R8TestBuilder::allowUnusedProguardConfigurationRules))
.assertSuccessWithOutput(EXPECTED_RENAMED)
.inspect(inspector -> assertThat(inspector.clazz(A.class), isPresentAndRenamed()));
}
@Test
public void testNoMembers() throws Exception {
- // TODO(b/323136645): This is incorrect behavior for R8.
- // R8 implicitly replaces the member rule with a member rule for <init>() which does not match.
- runTest("-keepclasseswithmembers class " + typeName(A.class) + " { }")
- .assertSuccessWithOutput(shrinker.isPG() ? EXPECTED_KEPT : EXPECTED_RENAMED)
- .inspect(
- inspector ->
- assertThat(
- inspector.clazz(A.class),
- shrinker.isPG() ? isPresentAndNotRenamed() : isPresentAndRenamed()));
+ runTest(
+ builder ->
+ builder.addKeepRules("-keepclasseswithmembers class " + typeName(A.class) + " {}"))
+ .assertSuccessWithOutput(EXPECTED_KEPT)
+ .inspect(inspector -> assertThat(inspector.clazz(A.class), isPresentAndNotRenamed()));
}
@Test
public void testAllMembers() throws Exception {
// Surprising, but consistent for PG and R8, "any member" pattern does not match an empty class.
- runTest("-keepclasseswithmembers class " + typeName(A.class) + " { *; }")
+ runTest(
+ builder ->
+ builder
+ .addKeepRules("-keepclasseswithmembers class " + typeName(A.class) + " { *; }")
+ .applyIfR8(R8TestBuilder::allowUnusedProguardConfigurationRules))
.assertSuccessWithOutput(EXPECTED_RENAMED)
.inspect(inspector -> assertThat(inspector.clazz(A.class), isPresentAndRenamed()));
}
@Test
public void testAllMethods() throws Exception {
- runTest("-keepclasseswithmembers class " + typeName(A.class) + " { *** *(...); }")
+ runTest(
+ builder ->
+ builder
+ .addKeepRules(
+ "-keepclasseswithmembers class " + typeName(A.class) + " { *** *(...); }")
+ .applyIfR8(R8TestBuilder::allowUnusedProguardConfigurationRules))
.assertSuccessWithOutput(EXPECTED_RENAMED)
.inspect(inspector -> assertThat(inspector.clazz(A.class), isPresentAndRenamed()));
}
@Test
public void testAllMethods2() throws Exception {
- runTest("-keepclasseswithmembers class " + typeName(A.class) + " { <methods>; }")
+ runTest(
+ builder ->
+ builder
+ .addKeepRules(
+ "-keepclasseswithmembers class " + typeName(A.class) + " { <methods>; }")
+ .applyIfR8(R8TestBuilder::allowUnusedProguardConfigurationRules))
.assertSuccessWithOutput(EXPECTED_RENAMED)
.inspect(inspector -> assertThat(inspector.clazz(A.class), isPresentAndRenamed()));
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/compatissues/NonDefaultInitClassWithMembersRuleTest.java b/src/test/java/com/android/tools/r8/keepanno/compatissues/NonDefaultInitClassWithMembersRuleTest.java
index 944b39b..9b46168 100644
--- a/src/test/java/com/android/tools/r8/keepanno/compatissues/NonDefaultInitClassWithMembersRuleTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/compatissues/NonDefaultInitClassWithMembersRuleTest.java
@@ -87,15 +87,9 @@
@Test
public void testNoMembers() throws Exception {
- // TODO(b/323136645): This is incorrect behavior for R8.
- // R8 implicitly replaces the member rule with a member rule for <init>() which does not match.
- runTestAllowingUnusedRules("-keepclasseswithmembers class " + typeName(A.class) + " { }")
- .assertSuccessWithOutput(shrinker.isPG() ? EXPECTED_KEPT : EXPECTED_RENAMED)
- .inspect(
- inspector ->
- assertThat(
- inspector.clazz(A.class),
- shrinker.isPG() ? isPresentAndNotRenamed() : isPresentAndRenamed()));
+ runTest("-keepclasseswithmembers class " + typeName(A.class) + " { }")
+ .assertSuccessWithOutput(EXPECTED_KEPT)
+ .inspect(inspector -> assertThat(inspector.clazz(A.class), isPresentAndNotRenamed()));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
index 8731d5e..3ad68c9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -92,7 +92,7 @@
baseLibJar, kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(extLibJarMap.getForConfiguration(kotlinParameters))
// Keep the Extra class and its interface (which has the method).
- .addKeepRules("-keep class **.Extra")
+ .addKeepClassAndDefaultConstructor("**.Extra")
// Keep Super, but allow minification.
.addKeepRules("-keep,allowobfuscation class **.Impl")
// Keep the ImplKt extension method which requires metadata
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
index 2c7400a..fe8c747 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -120,7 +120,7 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(companionLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .addKeepClassAndDefaultConstructor("**.B")
// Property in companion with @JvmField is defined in the host class, without accessors.
.addKeepRules("-keepclassmembers class **.B { *** elt2; }")
.addKeepRules("-keep class **.I { <methods>; }")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
index 73e4534..969f5a7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -103,7 +103,10 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(extLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .applyIf(
+ full,
+ b -> b.addKeepClassAndDefaultConstructor("**.B"),
+ b -> b.addKeepClassRules("**.B"))
.addKeepRules("-keep class **.I { <methods>; }")
// Keep the BKt extension function which requires metadata
// to be called with Kotlin syntax from other kotlin code.
@@ -158,7 +161,7 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(extLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .addKeepClassAndDefaultConstructor("**.B")
.addKeepRules("-keep class **.I { <methods>; }")
// Keep Super, but allow minification.
.addKeepRules("-keep,allowobfuscation class **.Super")
@@ -198,7 +201,7 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(extLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .addKeepClassAndDefaultConstructor("**.B")
.addKeepRules("-keep class **.I { <methods>; }")
// Keep Super, but allow minification.
.addKeepRules("-keep,allowobfuscation class **.Super")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
index a177f44..2780a6b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -93,7 +93,10 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(extLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .applyIf(
+ full,
+ b -> b.addKeepClassAndDefaultConstructor("**.B"),
+ b -> b.addKeepClassRules("**.B"))
.addKeepRules("-keep class **.I { <methods>; }")
// Keep the BKt extension property which requires metadata
// to be called with Kotlin syntax from other kotlin code.
@@ -157,7 +160,7 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(extLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .addKeepClassAndDefaultConstructor("**.B")
.addKeepRules("-keep class **.I { <methods>; }")
// Keep Super, but allow minification.
.addKeepRules("-keep,allowobfuscation class **.Super")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
index da87d5f..c6fa158 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -92,7 +92,10 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(funLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .applyIf(
+ full,
+ b -> b.addKeepClassAndDefaultConstructor("**.B"),
+ b -> b.addKeepClassRules("**.B"))
.addKeepRules("-keep class **.I { <methods>; }")
// Keep the BKt method, which will be called from other kotlin code.
.addKeepRules("-keep class **.BKt { <methods>; }")
@@ -154,7 +157,7 @@
.addClasspathFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
.addProgramFiles(funLibJarMap.getForConfiguration(kotlinParameters))
// Keep the B class and its interface (which has the doStuff method).
- .addKeepRules("-keep class **.B")
+ .addKeepClassAndDefaultConstructor("**.B")
.addKeepRules("-keep class **.I { <methods>; }")
// Keep Super, but allow minification.
.addKeepRules("-keep,allowobfuscation class **.Super { <methods>; }")
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
index 28b621a..cc150aa 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
@@ -68,11 +68,12 @@
"iput-object v0, p0, LExample;->aClassName:Ljava/lang/String;",
"return-void");
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class " + CLASS_NAME + " { java.lang.String aClassName; }",
- "-keep class " + CLASS_NAME,
- "-keepclassmembers,allowobfuscation class " + CLASS_NAME + " { !static <fields>; }",
- "-dontoptimize");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class " + CLASS_NAME + " { java.lang.String aClassName; }",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keepclassmembers,allowobfuscation class " + CLASS_NAME + " { !static <fields>; }",
+ "-dontoptimize");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
@@ -101,11 +102,12 @@
"iput-object v1, p0, LExample;->aClassName:Ljava/lang/String;",
"return-void");
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class " + CLASS_NAME + " { java.lang.String aClassName; }",
- "-keep class " + CLASS_NAME,
- "-keepclassmembers,allowobfuscation class " + CLASS_NAME + " { !static <fields>; }",
- "-dontoptimize");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class " + CLASS_NAME + " { java.lang.String aClassName; }",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keepclassmembers,allowobfuscation class " + CLASS_NAME + " { !static <fields>; }",
+ "-dontoptimize");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
@@ -140,12 +142,13 @@
"return-void");
builder.addClass(BOO);
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class " + CLASS_NAME + " { java.lang.String aClassName; }",
- "-keep class " + CLASS_NAME,
- "-keepclassmembers,allowobfuscation class " + CLASS_NAME + " { !static <fields>; }",
- "-keep,allowobfuscation class " + BOO,
- "-dontoptimize");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class " + CLASS_NAME + " { java.lang.String aClassName; }",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keepclassmembers,allowobfuscation class " + CLASS_NAME + " { !static <fields>; }",
+ "-keep,allowobfuscation class " + BOO,
+ "-dontoptimize");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
@@ -392,8 +395,8 @@
.addKeepRules(
"-identifiernamestring class "
+ CLASS_NAME
- + " { static void foo(...); }",
- "-keep class " + CLASS_NAME)
+ + " { static void foo(...); }")
+ .addKeepClassAndDefaultConstructor(CLASS_NAME)
.allowDiagnosticWarningMessages())
.assertAllWarningMessagesMatch(
containsString("Cannot determine what 'Mixed/form.Boo' refers to"))
@@ -439,7 +442,7 @@
List<String> pgConfigs =
ImmutableList.of(
"-identifiernamestring class " + CLASS_NAME + " { static void foo(...); }",
- "-keep class " + CLASS_NAME,
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
"-dontoptimize");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
@@ -483,7 +486,7 @@
List<String> pgConfigs =
ImmutableList.of(
"-identifiernamestring class " + CLASS_NAME + " { static void foo(...); }",
- "-keep class " + CLASS_NAME,
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
"-keep,allowobfuscation class " + BOO,
"-dontoptimize");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
@@ -534,12 +537,13 @@
"move-result-object v0",
"return-object v0");
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class * {\n"
- + " static java.lang.reflect.Field *(java.lang.Class,java.lang.String);\n"
- + "}",
- "-keep class " + CLASS_NAME,
- "-keep class R { *; }");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class * {\n"
+ + " static java.lang.reflect.Field *(java.lang.Class,java.lang.String);\n"
+ + "}",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keep class R { *; }");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
@@ -584,12 +588,13 @@
"move-result-object v0",
"return-object v0");
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class * {\n"
- + " static java.lang.reflect.Field *(java.lang.Class,java.lang.String);\n"
- + "}",
- "-keep class " + CLASS_NAME,
- "-keep,allowobfuscation class R { *; }");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class * {\n"
+ + " static java.lang.reflect.Field *(java.lang.Class,java.lang.String);\n"
+ + "}",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keep,allowobfuscation class R { *; }");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
@@ -640,13 +645,14 @@
"move-result-object v0",
"return-object v0");
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class * {\n"
- + " static java.lang.reflect.Method"
- + " *(java.lang.Class,java.lang.String,java.lang.Class[]);\n"
- + "}",
- "-keep class " + CLASS_NAME,
- "-keep class R { *; }");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class * {\n"
+ + " static java.lang.reflect.Method"
+ + " *(java.lang.Class,java.lang.String,java.lang.Class[]);\n"
+ + "}",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keep class R { *; }");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
@@ -715,13 +721,14 @@
"move-result-object v0",
"return-object v0");
- List<String> pgConfigs = ImmutableList.of(
- "-identifiernamestring class * {\n"
- + " static java.lang.reflect.Method"
- + " *(java.lang.Class,java.lang.String,java.lang.Class[]);\n"
- + "}",
- "-keep class " + CLASS_NAME,
- "-keep,allowobfuscation class R { *; }");
+ List<String> pgConfigs =
+ ImmutableList.of(
+ "-identifiernamestring class * {\n"
+ + " static java.lang.reflect.Method"
+ + " *(java.lang.Class,java.lang.String,java.lang.Class[]);\n"
+ + "}",
+ "-keep class " + CLASS_NAME + " { void <init>(); }",
+ "-keep,allowobfuscation class R { *; }");
CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithStringIdentifier.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithStringIdentifier.java
index a4bc84c..b3df30f 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithStringIdentifier.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithStringIdentifier.java
@@ -44,7 +44,7 @@
"-identifiernamestring class "
+ Main.class.getTypeName()
+ " { java.lang.String name; }")
- .addKeepRules("-keepclassmembers,allowshrinking class **")
+ .addKeepRules("-keepclassmembers,allowshrinking class * { void <init>(); }")
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
index 8df062f..b7c0d9a 100644
--- a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
@@ -144,7 +144,7 @@
public void testSatisfiedClassMembersPresentAnnotation() throws Exception {
testForR8(Backend.CF)
.addProgramFiles(R8_JAR)
- .addKeepClassRules(CLASS_WITH_ANNOTATED_METHOD)
+ .addKeepClassAndDefaultConstructor(CLASS_WITH_ANNOTATED_METHOD)
.addKeepRules("-keepclassmembers class * { @" + PRESENT_ANNOTATION + " *** *(...); }")
.compile()
.inspect(
@@ -182,7 +182,7 @@
public void testSatisfiedConditionalPresentAnnotation() throws Exception {
testForR8(Backend.CF)
.addProgramFiles(R8_JAR)
- .addKeepClassRules(CLASS_WITH_ANNOTATED_METHOD)
+ .addKeepClassAndDefaultConstructor(CLASS_WITH_ANNOTATED_METHOD)
.addKeepRules("-if class * -keep class <1> { @" + PRESENT_ANNOTATION + " *** *(...); }")
.compile()
.inspect(
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepIfKeptTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepIfKeptTest.java
index 902d86a..96aa8fd 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepIfKeptTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepIfKeptTest.java
@@ -8,7 +8,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -63,9 +62,7 @@
ClassSubject classSubject = inspector.clazz(StaticallyReferenced.class);
assertThat(classSubject, isPresent());
assertEquals(0, classSubject.allFields().size());
- // TODO(b/132318799): Should not keep <init>() when not specified.
- assertEquals(1, classSubject.allMethods().size());
- assertTrue(classSubject.init().isPresent());
+ assertEquals(0, classSubject.allMethods().size());
});
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnStaticFinalFieldTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnStaticFinalFieldTest.java
index 63d5746..824863c 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnStaticFinalFieldTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnStaticFinalFieldTest.java
@@ -50,7 +50,7 @@
"-keep class " + A.class.getTypeName())
.addKeepRules(
"-if class " + StaticNonFinalField.class.getTypeName() + " { int f; }",
- "-keep class " + B.class.getTypeName())
+ "-keep class " + B.class.getTypeName() + " { void <init>(); }")
.setMinApi(parameters)
.allowDiagnosticMessages()
.compileWithExpectedDiagnostics(
@@ -70,7 +70,9 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
- .addKeepRules("-if class * { int f; } -keep class " + B.class.getTypeName())
+ .addKeepRules(
+ "-if class * { int f; }",
+ "-keep class " + B.class.getTypeName() + " { void <init>(); }")
.setMinApi(parameters)
.allowDiagnosticMessages()
.compileWithExpectedDiagnostics(
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithFieldValuePropagationTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithFieldValuePropagationTest.java
index 79ae86f..9fa36b4 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithFieldValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithFieldValuePropagationTest.java
@@ -35,11 +35,8 @@
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class, R.class, Layout.class)
.addKeepMainRule(TestClass.class)
- .addKeepRules(
- "-if class " + R.class.getTypeName() + " {",
- " static int ID;",
- "}",
- "-keep class " + Layout.class.getTypeName())
+ .addKeepRules("-if class " + R.class.getTypeName() + " {", " static int ID;", "}")
+ .addKeepClassAndDefaultConstructor(Layout.class)
.addLibraryClasses(Library.class)
.addLibraryFiles(parameters.getDefaultRuntimeLibrary())
.setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithMethodValuePropagationTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithMethodValuePropagationTest.java
index 270a837..e2b98e8 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithMethodValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/membervaluepropagation/IfWithMethodValuePropagationTest.java
@@ -35,11 +35,8 @@
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class, R.class, Layout.class)
.addKeepMainRule(TestClass.class)
- .addKeepRules(
- "-if class " + R.class.getTypeName() + " {",
- " static int id();",
- "}",
- "-keep class " + Layout.class.getTypeName())
+ .addKeepRules("-if class " + R.class.getTypeName() + " {", " static int id();", "}")
+ .addKeepClassAndDefaultConstructor(Layout.class)
.addLibraryClasses(Library.class)
.addDefaultRuntimeLibrary(parameters)
.setMinApi(parameters)
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java
index 0258428..3187639 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/DefaultInterfaceMethodsTest.java
@@ -78,7 +78,7 @@
.addClasspathClasses(I.class, J.class)
.setMinApi(parameters)
.addKeepMainRule(Main.class)
- .addKeepClassRules(ImplJ.class)
+ .addKeepClassAndDefaultConstructor(ImplJ.class)
.addRunClasspathFiles(compileResult.writeToZip())
.run(parameters.getRuntime(), Main.class, ImplJ.class.getTypeName(), "foo")
.assertFailureWithErrorThatMatches(
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/ImplementingMethodInSubclassTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/ImplementingMethodInSubclassTest.java
index 9357d07..7d43997 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/ImplementingMethodInSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/ImplementingMethodInSubclassTest.java
@@ -38,7 +38,7 @@
.addProgramClasses(I.class, A.class, B.class)
.setMinApi(parameters)
.addKeepMethodRules(A.class, "void foo()")
- .addKeepClassRules(B.class)
+ .addKeepClassAndDefaultConstructor(B.class)
.compile();
testForRuntime(parameters)
.addProgramClasses(Main.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceMethodKeepResolutionTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceMethodKeepResolutionTest.java
index a2fe6b9..f850ee5 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceMethodKeepResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/InterfaceMethodKeepResolutionTest.java
@@ -74,7 +74,7 @@
.setMinApi(parameters)
.addKeepMethodRules(libraryClassWithMethod, "void foo()");
if (!libraryClassWithMethod.isInterface()) {
- libraryBuilder.addKeepClassRules(libraryClassWithMethod);
+ libraryBuilder.addKeepClassAndDefaultConstructor(libraryClassWithMethod);
}
testForRuntime(parameters)
.addProgramClasses(programClasses)
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/SubTypeOverridesInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/SubTypeOverridesInterfaceMethodTest.java
index b8095e1..3cdcb56 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/interfaces/SubTypeOverridesInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/interfaces/SubTypeOverridesInterfaceMethodTest.java
@@ -45,7 +45,7 @@
.setMinApi(parameters)
.addKeepMainRule(Main.class)
.addKeepMethodRules(A.class, "void <init>()", "void foo()")
- .addKeepClassRules(B.class)
+ .addKeepClassAndDefaultConstructor(B.class)
.run(parameters.getRuntime(), Main.class, B.class.getTypeName(), "foo")
.assertSuccessWithOutputLines("Hello World!")
.inspect(
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestBuilder.java
index 32a40c0..201d674 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBuilder.java
@@ -42,7 +42,7 @@
return fn.applyWithRuntimeException(self());
}
- public T apply(ThrowableConsumer<T> fn) {
+ public T apply(ThrowableConsumer<? super T> fn) {
if (fn != null) {
fn.acceptWithRuntimeException(self());
}
@@ -85,6 +85,14 @@
return self;
}
+ public T applyIfR8(ThrowableConsumer<? super R8TestBuilder<?>> consumer) {
+ T self = self();
+ if (this instanceof R8TestBuilder<?>) {
+ consumer.acceptWithRuntimeException((R8TestBuilder<?>) self);
+ }
+ return self;
+ }
+
@Deprecated
public RR run(String mainClass)
throws CompilationFailedException, ExecutionException, IOException {
diff --git a/src/test/testbase/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java b/src/test/testbase/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
index 1d8821e..8ce018e 100644
--- a/src/test/testbase/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
@@ -140,7 +140,7 @@
.addInliningAnnotations()
.setMinApi(parameters)
.addKeepMainRule(SplitRunner.class)
- .addKeepClassRules(toRun)
+ .addKeepClassAndDefaultConstructor(toRun)
.apply(r8TestConfigurator)
.compile()
.apply(compileResultConsumer);