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) {