Handle default methods properly during tree shaking.
When tracking methods that are reachable but not yet live, we did not
handle default methods. Instead of recording them as a reachable method
that will be picked up when a subtype becomes instantiated, we just
dropped them.
This also reverts commit d9cfbd7b2d01c4895327f48cfc7c78bf811e006d, which
introduced an additional fix point. See also
https://r8-review.googlesource.com/c/r8/+/9780
Bug: 68696348
Change-Id: I05d6db4739308ee1bc869f1a6b7bbb2f493e576a
diff --git a/src/test/examplesAndroidN/shaking/InterfaceWithDefault.java b/src/test/examplesAndroidN/shaking/InterfaceWithDefault.java
new file mode 100644
index 0000000..f32a754
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/InterfaceWithDefault.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package shaking;
+
+public interface InterfaceWithDefault {
+
+ default void foo() {
+ System.out.println("Default method foo");
+ }
+}
diff --git a/src/test/examplesAndroidN/shaking/OtherInterface.java b/src/test/examplesAndroidN/shaking/OtherInterface.java
new file mode 100644
index 0000000..8831a1d
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/OtherInterface.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package shaking;
+
+public interface OtherInterface {
+
+ void bar();
+}
diff --git a/src/test/examplesAndroidN/shaking/OtherInterfaceWithDefault.java b/src/test/examplesAndroidN/shaking/OtherInterfaceWithDefault.java
new file mode 100644
index 0000000..8d4dec6
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/OtherInterfaceWithDefault.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package shaking;
+
+public interface OtherInterfaceWithDefault extends OtherInterface {
+
+ @Override
+ default void bar() {
+ System.out.println("bar from OtherInterfaceWithDefault");
+ }
+}
diff --git a/src/test/examplesAndroidN/shaking/Shaking.java b/src/test/examplesAndroidN/shaking/Shaking.java
new file mode 100644
index 0000000..353e9b4
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/Shaking.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package shaking;
+
+public class Shaking {
+
+ public static void main(String... args) {
+ SubClassOne anInstance = new SubClassOne();
+ invokeFooOnInterface(anInstance);
+ }
+
+ private static void invokeFooOnInterface(InterfaceWithDefault anInstance) {
+ anInstance.foo();
+ }
+}
diff --git a/src/test/examplesAndroidN/shaking/SubClassOne.java b/src/test/examplesAndroidN/shaking/SubClassOne.java
new file mode 100644
index 0000000..7dfcf8d
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/SubClassOne.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package shaking;
+
+public class SubClassOne implements InterfaceWithDefault, OtherInterfaceWithDefault {
+
+ @Override
+ public void foo() {
+ System.out.println("Method foo from SubClassOne");
+ makeSubClassTwoLive().foo();
+ asOtherInterface().bar();
+ }
+
+ private OtherInterface asOtherInterface() {
+ return new SubClassTwo();
+ }
+
+ @Override
+ public void bar() {
+ System.out.println("Method bar from SubClassOne");
+ }
+
+ private InterfaceWithDefault makeSubClassTwoLive() {
+ // Once we see this method, SubClassTwo will be live. This should also make the default method
+ // in the interface live, as SubClassTwo does not override it.
+ return new SubClassTwo();
+ }
+}
diff --git a/src/test/examplesAndroidN/shaking/SubClassTwo.java b/src/test/examplesAndroidN/shaking/SubClassTwo.java
new file mode 100644
index 0000000..95b2492
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/SubClassTwo.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package shaking;
+
+public class SubClassTwo implements InterfaceWithDefault, OtherInterfaceWithDefault {
+ // Intentionally left empty.
+}
diff --git a/src/test/examplesAndroidN/shaking/keep-rules.txt b/src/test/examplesAndroidN/shaking/keep-rules.txt
new file mode 100644
index 0000000..791cebf
--- /dev/null
+++ b/src/test/examplesAndroidN/shaking/keep-rules.txt
@@ -0,0 +1,9 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Keep the application entry point. Get rid of everything that is not
+# reachable from there.
+-keep public class shaking.Shaking {
+ public static void main(...);
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 5753d84..54750e5 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -58,15 +58,17 @@
public class ToolHelper {
public static final String BUILD_DIR = "build/";
- public static final String EXAMPLES_DIR = "src/test/examples/";
- public static final String EXAMPLES_ANDROID_O_DIR = "src/test/examplesAndroidO/";
- public static final String EXAMPLES_ANDROID_P_DIR = "src/test/examplesAndroidP/";
- public static final String EXAMPLES_BUILD_DIR = BUILD_DIR + "test/examples/";
- public static final String EXAMPLES_ANDROID_N_BUILD_DIR = BUILD_DIR + "test/examplesAndroidN/";
- public static final String EXAMPLES_ANDROID_O_BUILD_DIR = BUILD_DIR + "test/examplesAndroidO/";
- public static final String EXAMPLES_ANDROID_P_BUILD_DIR = BUILD_DIR + "test/examplesAndroidP/";
- public static final String EXAMPLES_JAVA9_BUILD_DIR = BUILD_DIR + "test/examplesJava9/";
- public static final String SMALI_BUILD_DIR = BUILD_DIR + "test/smali/";
+ public static final String TESTS_DIR = "src/test/";
+ public static final String EXAMPLES_DIR = TESTS_DIR + "examples/";
+ public static final String EXAMPLES_ANDROID_O_DIR = TESTS_DIR + "examplesAndroidO/";
+ public static final String EXAMPLES_ANDROID_P_DIR = TESTS_DIR + "examplesAndroidP/";
+ public static final String TESTS_BUILD_DIR = BUILD_DIR + "test/";
+ public static final String EXAMPLES_BUILD_DIR = TESTS_BUILD_DIR + "examples/";
+ public static final String EXAMPLES_ANDROID_N_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidN/";
+ public static final String EXAMPLES_ANDROID_O_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidO/";
+ public static final String EXAMPLES_ANDROID_P_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidP/";
+ public static final String EXAMPLES_JAVA9_BUILD_DIR = TESTS_BUILD_DIR + "examplesJava9/";
+ public static final String SMALI_BUILD_DIR = TESTS_BUILD_DIR + "smali/";
public static final String LINE_SEPARATOR = StringUtils.LINE_SEPARATOR;
public final static String PATH_SEPARATOR = File.pathSeparator;
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
index 756c93c..081b083 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingTest.java
@@ -29,6 +29,7 @@
import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -61,27 +62,31 @@
.of(ANDROID_JAR, ToolHelper.EXAMPLES_BUILD_DIR + "shakinglib.jar"), Paths::get);
private static final String EMPTY_FLAGS = "src/test/proguard/valid/empty.flags";
private static final Set<String> IGNORED_FLAGS = ImmutableSet.of(
- "minification:conflict-mapping.txt",
- "minification:keep-rules-apply-conflict-mapping.txt"
+ "examples/minification:conflict-mapping.txt",
+ "examples/minification:keep-rules-apply-conflict-mapping.txt"
);
private static final Set<String> IGNORED = ImmutableSet.of(
// there's no point in running those without obfuscation
- "shaking1:keep-rules-repackaging.txt:DEX:NONE",
- "shaking1:keep-rules-repackaging.txt:JAR:NONE",
- "shaking16:keep-rules-1.txt:DEX:NONE",
- "shaking16:keep-rules-1.txt:JAR:NONE",
- "shaking16:keep-rules-2.txt:DEX:NONE",
- "shaking16:keep-rules-2.txt:JAR:NONE",
- "shaking15:keep-rules.txt:DEX:NONE",
- "shaking15:keep-rules.txt:JAR:NONE",
- "minifygeneric:keep-rules.txt:DEX:NONE",
- "minifygeneric:keep-rules.txt:JAR:NONE",
- "minifygenericwithinner:keep-rules.txt:DEX:NONE",
- "minifygenericwithinner:keep-rules.txt:JAR:NONE"
+ "examples/shaking1:keep-rules-repackaging.txt:DEX:NONE",
+ "examples/shaking1:keep-rules-repackaging.txt:JAR:NONE",
+ "examples/shaking16:keep-rules-1.txt:DEX:NONE",
+ "examples/shaking16:keep-rules-1.txt:JAR:NONE",
+ "examples/shaking16:keep-rules-2.txt:DEX:NONE",
+ "examples/shaking16:keep-rules-2.txt:JAR:NONE",
+ "examples/shaking15:keep-rules.txt:DEX:NONE",
+ "examples/shaking15:keep-rules.txt:JAR:NONE",
+ "examples/minifygeneric:keep-rules.txt:DEX:NONE",
+ "examples/minifygeneric:keep-rules.txt:JAR:NONE",
+ "examples/minifygenericwithinner:keep-rules.txt:DEX:NONE",
+ "examples/minifygenericwithinner:keep-rules.txt:JAR:NONE",
+ // No prebuild DEX files for AndroidN
+ "examplesAndroidN/shaking:keep-rules.txt:DEX:NONE",
+ "examplesAndroidN/shaking:keep-rules.txt:DEX:JAVA",
+ "examplesAndroidN/shaking:keep-rules.txt:DEX:AGGRESSIVE"
);
// TODO(65355452): Reenable or remove inlining tests.
- private static Set<String> SKIPPED = ImmutableSet.of("inlining");
+ private static Set<String> SKIPPED = ImmutableSet.of("examples/inlining");
private final MinifyMode minify;
@@ -107,11 +112,11 @@
BiConsumer<String, String> outputComparator,
BiConsumer<DexInspector, DexInspector> dexComparator) {
this.kind = kind;
- originalDex = ToolHelper.EXAMPLES_BUILD_DIR + test + "/classes.dex";
+ originalDex = ToolHelper.TESTS_BUILD_DIR + test + "/classes.dex";
if (kind == Frontend.DEX) {
this.programFile = originalDex;
} else {
- this.programFile = ToolHelper.EXAMPLES_BUILD_DIR + test + ".jar";
+ this.programFile = ToolHelper.TESTS_BUILD_DIR + test + ".jar";
}
this.mainClass = mainClass;
this.keepRulesFiles = keepRulesFiles;
@@ -622,160 +627,166 @@
public static Collection<Object[]> data() {
List<String> tests = Arrays
.asList(
- "shaking1",
- "shaking2",
- "shaking3",
- "shaking4",
- "shaking5",
- "shaking6",
- "shaking7",
- "shaking8",
- "shaking9",
- "shaking10",
- "shaking11",
- "shaking12",
- "shaking13",
- "shaking14",
- "shaking15",
- "shaking16",
- "shaking17",
- "minification",
- "minifygeneric",
- "minifygenericwithinner",
- "assumenosideeffects1",
- "assumenosideeffects2",
- "assumenosideeffects3",
- "assumenosideeffects4",
- "assumenosideeffects5",
- "assumevalues1",
- "assumevalues2",
- "assumevalues3",
- "assumevalues4",
- "assumevalues5",
- "annotationremoval",
- "memberrebinding2",
- "memberrebinding3",
- "simpleproto1",
- "simpleproto2",
- "simpleproto3",
- "nestedproto1",
- "nestedproto2",
- "enumproto",
- "repeatedproto",
- "oneofproto");
+ "examples/shaking1",
+ "examples/shaking2",
+ "examples/shaking3",
+ "examples/shaking4",
+ "examples/shaking5",
+ "examples/shaking6",
+ "examples/shaking7",
+ "examples/shaking8",
+ "examples/shaking9",
+ "examples/shaking10",
+ "examples/shaking11",
+ "examples/shaking12",
+ "examples/shaking13",
+ "examples/shaking14",
+ "examples/shaking15",
+ "examples/shaking16",
+ "examples/shaking17",
+ "examples/minification",
+ "examples/minifygeneric",
+ "examples/minifygenericwithinner",
+ "examples/assumenosideeffects1",
+ "examples/assumenosideeffects2",
+ "examples/assumenosideeffects3",
+ "examples/assumenosideeffects4",
+ "examples/assumenosideeffects5",
+ "examples/assumevalues1",
+ "examples/assumevalues2",
+ "examples/assumevalues3",
+ "examples/assumevalues4",
+ "examples/assumevalues5",
+ "examples/annotationremoval",
+ "examples/memberrebinding2",
+ "examples/memberrebinding3",
+ "examples/simpleproto1",
+ "examples/simpleproto2",
+ "examples/simpleproto3",
+ "examples/nestedproto1",
+ "examples/nestedproto2",
+ "examples/enumproto",
+ "examples/repeatedproto",
+ "examples/oneofproto",
+ "examplesAndroidN/shaking");
// Keys can be the name of the test or the name of the test followed by a colon and the name
// of the keep file.
Map<String, Consumer<DexInspector>> inspections = new HashMap<>();
- inspections.put("shaking1:keep-rules.txt", TreeShakingTest::shaking1HasNoClassUnused);
+ inspections.put("examples/shaking1:keep-rules.txt", TreeShakingTest::shaking1HasNoClassUnused);
+ inspections.put("examples/shaking1:keep-rules-repackaging.txt",
+ TreeShakingTest::shaking1IsCorrectlyRepackaged);
inspections
- .put("shaking1:keep-rules-repackaging.txt", TreeShakingTest::shaking1IsCorrectlyRepackaged);
- inspections.put("shaking2:keep-rules.txt", TreeShakingTest::shaking2SuperClassIsAbstract);
- inspections.put("shaking3:keep-by-tag.txt", TreeShakingTest::shaking3HasNoClassB);
- inspections.put("shaking3:keep-by-tag-default.txt", TreeShakingTest::shaking3HasNoClassB);
- inspections.put("shaking3:keep-by-tag-with-pattern.txt", TreeShakingTest::shaking3HasNoClassB);
- inspections.put("shaking3:keep-by-tag-via-interface.txt", TreeShakingTest::shaking3HasNoClassB);
- inspections.put("shaking3:keep-by-tag-on-method.txt", TreeShakingTest::shaking3HasNoClassB);
+ .put("examples/shaking2:keep-rules.txt", TreeShakingTest::shaking2SuperClassIsAbstract);
+ inspections.put("examples/shaking3:keep-by-tag.txt", TreeShakingTest::shaking3HasNoClassB);
inspections
- .put("shaking3:keep-no-abstract-classes.txt", TreeShakingTest::shaking3HasNoPrivateClass);
- inspections.put("shaking5", TreeShakingTest::shaking5Inspection);
- inspections.put("shaking6:keep-public.txt", TreeShakingTest::hasNoPrivateMethods);
- inspections.put("shaking6:keep-non-public.txt", TreeShakingTest::hasNoPublicMethodsButPrivate);
+ .put("examples/shaking3:keep-by-tag-default.txt", TreeShakingTest::shaking3HasNoClassB);
+ inspections.put("examples/shaking3:keep-by-tag-with-pattern.txt",
+ TreeShakingTest::shaking3HasNoClassB);
+ inspections.put("examples/shaking3:keep-by-tag-via-interface.txt",
+ TreeShakingTest::shaking3HasNoClassB);
inspections
- .put("shaking6:keep-justAMethod-public.txt", TreeShakingTest::hasNoPrivateJustAMethod);
- inspections.put("shaking6:keep-justAMethod-OnInt.txt", TreeShakingTest::hasOnlyIntJustAMethod);
+ .put("examples/shaking3:keep-by-tag-on-method.txt", TreeShakingTest::shaking3HasNoClassB);
+ inspections.put("examples/shaking3:keep-no-abstract-classes.txt",
+ TreeShakingTest::shaking3HasNoPrivateClass);
+ inspections.put("examples/shaking5", TreeShakingTest::shaking5Inspection);
+ inspections.put("examples/shaking6:keep-public.txt", TreeShakingTest::hasNoPrivateMethods);
+ inspections.put("examples/shaking6:keep-non-public.txt",
+ TreeShakingTest::hasNoPublicMethodsButPrivate);
+ inspections.put("examples/shaking6:keep-justAMethod-public.txt",
+ TreeShakingTest::hasNoPrivateJustAMethod);
+ inspections.put("examples/shaking6:keep-justAMethod-OnInt.txt",
+ TreeShakingTest::hasOnlyIntJustAMethod);
+ inspections.put("examples/shaking7:keep-public-fields.txt",
+ TreeShakingTest::shaking7HasOnlyPublicFields);
+ inspections.put("examples/shaking7:keep-double-fields.txt",
+ TreeShakingTest::shaking7HasOnlyDoubleFields);
+ inspections.put("examples/shaking7:keep-public-theDoubleField-fields.txt",
+ TreeShakingTest::shaking7HasOnlyPublicFieldsNamedTheDoubleField);
+ inspections.put("examples/shaking7:keep-public-theIntField-fields.txt",
+ TreeShakingTest::shaking7HasOnlyPublicFieldsNamedTheIntField);
+ inspections.put("examples/shaking8:keep-rules.txt",
+ TreeShakingTest::shaking8ThingClassIsAbstractAndEmpty);
inspections
- .put("shaking7:keep-public-fields.txt", TreeShakingTest::shaking7HasOnlyPublicFields);
+ .put("examples/shaking9:keep-rules.txt", TreeShakingTest::shaking9OnlySuperMethodsKept);
inspections
- .put("shaking7:keep-double-fields.txt", TreeShakingTest::shaking7HasOnlyDoubleFields);
- inspections
- .put("shaking7:keep-public-theDoubleField-fields.txt",
- TreeShakingTest::shaking7HasOnlyPublicFieldsNamedTheDoubleField);
- inspections
- .put("shaking7:keep-public-theIntField-fields.txt",
- TreeShakingTest::shaking7HasOnlyPublicFieldsNamedTheIntField);
- inspections
- .put("shaking8:keep-rules.txt", TreeShakingTest::shaking8ThingClassIsAbstractAndEmpty);
- inspections
- .put("shaking9:keep-rules.txt", TreeShakingTest::shaking9OnlySuperMethodsKept);
- inspections
- .put("shaking11:keep-rules.txt", TreeShakingTest::shaking11OnlyOneClassKept);
- inspections
- .put("shaking11:keep-rules-keep-method.txt", TreeShakingTest::shaking11BothMethodsKept);
- inspections.put("shaking12:keep-rules.txt",
+ .put("examples/shaking11:keep-rules.txt", TreeShakingTest::shaking11OnlyOneClassKept);
+ inspections.put("examples/shaking11:keep-rules-keep-method.txt",
+ TreeShakingTest::shaking11BothMethodsKept);
+ inspections.put("examples/shaking12:keep-rules.txt",
TreeShakingTest::shaking12OnlyInstantiatedClassesHaveConstructors);
- inspections.put("shaking13:keep-rules.txt",
+ inspections.put("examples/shaking13:keep-rules.txt",
TreeShakingTest::shaking13EnsureFieldWritesCorrect);
- inspections.put("shaking14:keep-rules.txt",
+ inspections.put("examples/shaking14:keep-rules.txt",
TreeShakingTest::shaking14EnsureRightStaticMethodsLive);
- inspections.put("shaking15:keep-rules.txt", TreeShakingTest::shaking15testDictionary);
- inspections.put("shaking17:keep-rules.txt", TreeShakingTest::abstractMethodRemains);
- inspections.put("annotationremoval:keep-rules.txt",
+ inspections.put("examples/shaking15:keep-rules.txt", TreeShakingTest::shaking15testDictionary);
+ inspections.put("examples/shaking17:keep-rules.txt", TreeShakingTest::abstractMethodRemains);
+ inspections.put("examples/annotationremoval:keep-rules.txt",
TreeShakingTest::annotationRemovalHasNoInnerClassAnnotations);
- inspections.put("annotationremoval:keep-rules-keep-innerannotation.txt",
+ inspections.put("examples/annotationremoval:keep-rules-keep-innerannotation.txt",
TreeShakingTest::annotationRemovalHasAllInnerClassAnnotations);
+ inspections.put("examples/simpleproto1:keep-rules.txt",
+ TreeShakingTest::simpleproto1UnusedFieldIsGone);
+ inspections.put("examples/simpleproto2:keep-rules.txt",
+ TreeShakingTest::simpleproto2UnusedFieldsAreGone);
+ inspections.put("examples/nestedproto1:keep-rules.txt",
+ TreeShakingTest::nestedproto1UnusedFieldsAreGone);
+ inspections.put("examples/nestedproto2:keep-rules.txt",
+ TreeShakingTest::nestedproto2UnusedFieldsAreGone);
inspections
- .put("simpleproto1:keep-rules.txt", TreeShakingTest::simpleproto1UnusedFieldIsGone);
+ .put("examples/enumproto:keep-rules.txt", TreeShakingTest::enumprotoUnusedFieldsAreGone);
inspections
- .put("simpleproto2:keep-rules.txt", TreeShakingTest::simpleproto2UnusedFieldsAreGone);
+ .put("examples/repeatedproto:keep-rules.txt", TreeShakingTest::repeatedUnusedFieldsAreGone);
inspections
- .put("nestedproto1:keep-rules.txt", TreeShakingTest::nestedproto1UnusedFieldsAreGone);
- inspections
- .put("nestedproto2:keep-rules.txt", TreeShakingTest::nestedproto2UnusedFieldsAreGone);
- inspections
- .put("enumproto:keep-rules.txt", TreeShakingTest::enumprotoUnusedFieldsAreGone);
- inspections
- .put("repeatedproto:keep-rules.txt", TreeShakingTest::repeatedUnusedFieldsAreGone);
- inspections
- .put("oneofproto:keep-rules.txt", TreeShakingTest::oneofprotoUnusedFieldsAreGone);
+ .put("examples/oneofproto:keep-rules.txt", TreeShakingTest::oneofprotoUnusedFieldsAreGone);
// Keys can be the name of the test or the name of the test followed by a colon and the name
// of the keep file.
Map<String, Collection<List<String>>> optionalRules = new HashMap<>();
- optionalRules.put("shaking1", ImmutableList.of(
+ optionalRules.put("examples/shaking1", ImmutableList.of(
Collections.singletonList(EMPTY_FLAGS),
Lists.newArrayList(EMPTY_FLAGS, EMPTY_FLAGS)));
List<Object[]> testCases = new ArrayList<>();
Map<String, BiConsumer<String, String>> outputComparators = new HashMap<>();
outputComparators
- .put("assumenosideeffects1",
+ .put("examples/assumenosideeffects1",
TreeShakingTest::assumenosideeffects1CheckOutput);
outputComparators
- .put("assumenosideeffects2",
+ .put("examples/assumenosideeffects2",
TreeShakingTest::assumenosideeffects2CheckOutput);
outputComparators
- .put("assumenosideeffects3",
+ .put("examples/assumenosideeffects3",
TreeShakingTest::assumenosideeffects3CheckOutput);
outputComparators
- .put("assumenosideeffects4",
+ .put("examples/assumenosideeffects4",
TreeShakingTest::assumenosideeffects4CheckOutput);
outputComparators
- .put("assumenosideeffects5",
+ .put("examples/assumenosideeffects5",
TreeShakingTest::assumenosideeffects5CheckOutput);
outputComparators
- .put("assumevalues1",
+ .put("examples/assumevalues1",
TreeShakingTest::assumevalues1CheckOutput);
outputComparators
- .put("assumevalues2",
+ .put("examples/assumevalues2",
TreeShakingTest::assumevalues2CheckOutput);
outputComparators
- .put("assumevalues3",
+ .put("examples/assumevalues3",
TreeShakingTest::assumevalues3CheckOutput);
outputComparators
- .put("assumevalues4",
+ .put("examples/assumevalues4",
TreeShakingTest::assumevalues4CheckOutput);
outputComparators
- .put("assumevalues5",
+ .put("examples/assumevalues5",
TreeShakingTest::assumevalues5CheckOutput);
Map<String, BiConsumer<DexInspector, DexInspector>> dexComparators = new HashMap<>();
dexComparators
- .put("shaking1:keep-rules-dont-shrink.txt", TreeShakingTest::checkSameStructure);
+ .put("examples/shaking1:keep-rules-dont-shrink.txt", TreeShakingTest::checkSameStructure);
dexComparators
- .put("shaking2:keep-rules-dont-shrink.txt", TreeShakingTest::checkSameStructure);
+ .put("examples/shaking2:keep-rules-dont-shrink.txt", TreeShakingTest::checkSameStructure);
dexComparators
- .put("shaking4:keep-rules-dont-shrink.txt", TreeShakingTest::checkSameStructure);
+ .put("examples/shaking4:keep-rules-dont-shrink.txt", TreeShakingTest::checkSameStructure);
Set<String> usedInspections = new HashSet<>();
Set<String> usedOptionalRules = new HashSet<>();
@@ -784,7 +795,7 @@
for (String test : tests) {
String mainClass = deriveMainClass(test);
- File[] keepFiles = new File(ToolHelper.EXAMPLES_DIR + "/" + test)
+ File[] keepFiles = new File(ToolHelper.TESTS_DIR + test)
.listFiles(file -> file.isFile() && file.getName().endsWith(".txt"));
for (File keepFile : keepFiles) {
String keepName = keepFile.getName();
@@ -863,12 +874,13 @@
}
private static String deriveMainClass(String testName) {
+ String testBaseName = testName.substring(testName.lastIndexOf('/') + 1);
StringBuilder mainClass = new StringBuilder(testName.length() * 2 + 1);
- mainClass.append(testName);
+ mainClass.append(testBaseName);
mainClass.append('.');
- mainClass.append(Character.toUpperCase(testName.charAt(0)));
- for (int i = 1; i < testName.length(); i++) {
- char next = testName.charAt(i);
+ mainClass.append(Character.toUpperCase(testBaseName.charAt(0)));
+ for (int i = 1; i < testBaseName.length(); i++) {
+ char next = testBaseName.charAt(i);
if (!Character.isAlphabetic(next)) {
break;
}
@@ -888,24 +900,32 @@
builder.appendClasspath(ToolHelper.EXAMPLES_BUILD_DIR + "shakinglib/classes.dex");
};
- if (outputComparator != null) {
- String output1 = ToolHelper.runArtNoVerificationErrors(
- Collections.singletonList(originalDex), mainClass, extraArtArgs, null);
- String output2 = ToolHelper.runArtNoVerificationErrors(
- Collections.singletonList(generated.toString()), mainClass, extraArtArgs, null);
- outputComparator.accept(output1, output2);
- } else {
- String output = ToolHelper.checkArtOutputIdentical(Collections.singletonList(originalDex),
- Collections.singletonList(generated.toString()), mainClass,
- extraArtArgs, null);
- }
+ if (Files.exists(Paths.get(originalDex))) {
+ if (outputComparator != null) {
+ String output1 = ToolHelper.runArtNoVerificationErrors(
+ Collections.singletonList(originalDex), mainClass, extraArtArgs, null);
+ String output2 = ToolHelper.runArtNoVerificationErrors(
+ Collections.singletonList(generated.toString()), mainClass, extraArtArgs, null);
+ outputComparator.accept(output1, output2);
+ } else {
+ ToolHelper.checkArtOutputIdentical(Collections.singletonList(originalDex),
+ Collections.singletonList(generated.toString()), mainClass,
+ extraArtArgs, null);
+ }
- if (dexComparator != null) {
- DexInspector ref = new DexInspector(Paths.get(originalDex));
- DexInspector inspector = new DexInspector(generated,
- minify.isMinify() ? temp.getRoot().toPath().resolve(DEFAULT_PROGUARD_MAP_FILE).toString()
- : null);
- dexComparator.accept(ref, inspector);
+ if (dexComparator != null) {
+ DexInspector ref = new DexInspector(Paths.get(originalDex));
+ DexInspector inspector = new DexInspector(generated,
+ minify.isMinify() ? temp.getRoot().toPath().resolve(DEFAULT_PROGUARD_MAP_FILE)
+ .toString()
+ : null);
+ dexComparator.accept(ref, inspector);
+ }
+ } else {
+ Assert.assertNull(outputComparator);
+ Assert.assertNull(dexComparator);
+ ToolHelper.runArtNoVerificationErrors(
+ Collections.singletonList(generated.toString()), mainClass, extraArtArgs, null);
}
if (inspection != null) {