Merge "Properly dedup synthetic $r8$twr$utility classes."
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
index 15f1535..7d6dd7b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -125,7 +125,7 @@
             twrCloseResourceMethod.holder,
             null,
             new SynthesizedOrigin("twr utility class", getClass()),
-            ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC),
+            ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC),
             factory.objectType,
             DexTypeList.empty(),
             null,
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index f136486..3b2b878 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -69,6 +69,6 @@
   private static boolean assumeClassesAreEqual(DexProgramClass a) {
     return LambdaRewriter.hasLambdaClassPrefix(a.type)
         || InterfaceMethodRewriter.hasDispatchClassSuffix(a.type)
-        || a.type.toString().equals(TwrCloseResourceRewriter.UTILITY_CLASS_DESCRIPTOR);
+        || a.type.descriptor.toString().equals(TwrCloseResourceRewriter.UTILITY_CLASS_DESCRIPTOR);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesJava9Test.java
new file mode 100644
index 0000000..c126083
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesJava9Test.java
@@ -0,0 +1,110 @@
+// Copyright (c) 2018, 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 com.android.tools.r8;
+
+import com.android.tools.r8.D8Command.Builder;
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+
+public class D8IncrementalRunExamplesJava9Test extends RunExamplesJava9Test<D8Command.Builder> {
+
+  class D8TestRunner extends TestRunner<D8TestRunner> {
+
+    D8TestRunner(String testName, String packageName, String mainClass) {
+      super(testName, packageName, mainClass);
+    }
+
+    @Override
+    D8TestRunner withMinApiLevel(int minApiLevel) {
+      return withBuilderTransformation(builder -> builder.setMinApiLevel(minApiLevel));
+    }
+
+    @Override
+    void build(Path inputFile, Path out) throws Throwable {
+      List<String> dexFiles = compileIncremental(inputFile);
+      assert !dexFiles.isEmpty();
+      mergeDexFiles(dexFiles, out);
+    }
+
+    private List<String> compileIncremental(Path inputFile) throws Throwable {
+      Builder builder = D8Command.builder();
+      for (UnaryOperator<Builder> transformation : builderTransformations) {
+        builder = transformation.apply(builder);
+      }
+      // Root to incremental output
+      Path incrementalOutput = temp.getRoot().toPath().resolve("incremental");
+      builder
+          .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+          .addProgramFiles(inputFile)
+          .setOutput(incrementalOutput, OutputMode.DexFilePerClassFile);
+      ToolHelper.runD8(builder, this::combinedOptionConsumer);
+      return collectDexFiles(incrementalOutput);
+    }
+
+    private void mergeDexFiles(List<String> dexFiles, Path out) throws Throwable {
+      Builder builder = D8Command.builder();
+      builder.addProgramFiles(
+          dexFiles.stream().map(str -> Paths.get(str)).collect(Collectors.toList()));
+      for (UnaryOperator<Builder> transformation : builderTransformations) {
+        builder = transformation.apply(builder);
+      }
+      builder.setOutput(out, OutputMode.DexIndexed);
+      try {
+        AndroidApp app = ToolHelper.runD8(builder, this::combinedOptionConsumer);
+        assert app.getDexProgramResourcesForTesting().size() == 1;
+      } catch (Unimplemented | CompilationError | InternalCompilerError re) {
+        throw re;
+      } catch (RuntimeException re) {
+        throw re.getCause() == null ? re : re.getCause();
+      }
+    }
+
+    private List<String> collectDexFiles(Path incrementalOutput) {
+      List<String> result = new ArrayList<>();
+      collectDexFiles(incrementalOutput, result);
+      Collections.sort(result);
+      return result;
+    }
+
+    private void collectDexFiles(Path dir, List<String> result) {
+      if (Files.exists(dir)) {
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+          for (Path entry : stream) {
+            if (Files.isDirectory(entry)) {
+              collectDexFiles(entry, result);
+            } else {
+              result.add(entry.toString());
+            }
+          }
+        } catch (IOException x) {
+          throw new AssertionError(x);
+        }
+      }
+    }
+
+    @Override
+    D8TestRunner self() {
+      return this;
+    }
+  }
+
+  @Override
+  D8TestRunner test(String testName, String packageName, String mainClass) {
+    return new D8TestRunner(testName, packageName, mainClass);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/D8RunExamplesJava9Test.java
index ece7f31..7924656 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesJava9Test.java
@@ -4,9 +4,6 @@
 
 package com.android.tools.r8;
 
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.InternalCompilerError;
-import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.nio.file.Path;
 import java.util.function.UnaryOperator;
@@ -24,11 +21,6 @@
       return withBuilderTransformation(builder -> builder.setMinApiLevel(minApiLevel));
     }
 
-    D8TestRunner withClasspath(Path... classpath) {
-      return withBuilderTransformation(b -> b.addClasspathFiles(classpath));
-    }
-
-
     @Override
     void build(Path inputFile, Path out) throws Throwable {
       D8Command.Builder builder = D8Command.builder();
@@ -40,17 +32,7 @@
           .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
           .addProgramFiles(inputFile)
           .setOutput(out, OutputMode.DexIndexed);
-      try {
-        ToolHelper.runD8(builder, this::combinedOptionConsumer);
-      } catch (Unimplemented | CompilationError | InternalCompilerError re) {
-        throw re;
-      } catch (RuntimeException re) {
-        throw re.getCause() == null ? re : re.getCause();
-      }
-    }
-
-    D8TestRunner withIntermediate(boolean intermediate) {
-      return withBuilderTransformation(builder -> builder.setIntermediate(intermediate));
+      ToolHelper.runD8(builder, this::combinedOptionConsumer);
     }
 
     @Override