Merge "Compiler specific compilation result"
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 21a5e0e..4897701 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -5,19 +5,19 @@
 
 import com.android.tools.r8.D8Command.Builder;
 import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 
-public class D8TestBuilder extends TestCompilerBuilder<D8Command, Builder, D8TestBuilder> {
+public class D8TestBuilder
+    extends TestCompilerBuilder<D8Command, Builder, D8TestCompileResult, D8TestBuilder> {
 
-  private final D8Command.Builder builder;
-
-  private D8TestBuilder(TestState state, D8Command.Builder builder) {
+  private D8TestBuilder(TestState state, Builder builder) {
     super(state, builder, Backend.DEX);
-    this.builder = builder;
   }
 
   public static D8TestBuilder create(TestState state) {
@@ -30,9 +30,11 @@
   }
 
   @Override
-  void internalCompile(Builder builder, Consumer<InternalOptions> optionsConsumer)
+  D8TestCompileResult internalCompile(
+      Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
     ToolHelper.runD8(builder, optionsConsumer);
+    return new D8TestCompileResult(getState(), app.get());
   }
 
   public D8TestBuilder addClasspathClasses(Class<?>... classes) {
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
new file mode 100644
index 0000000..482a611
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -0,0 +1,18 @@
+// 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.TestBase.Backend;
+import com.android.tools.r8.utils.AndroidApp;
+
+public class D8TestCompileResult extends TestCompileResult {
+  D8TestCompileResult(TestState state, AndroidApp app) {
+    super(state, app);
+  }
+
+  @Override
+  public Backend getBackend() {
+    return Backend.DEX;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 74b40b0..3b01a71 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
 import java.util.ArrayList;
@@ -13,14 +14,13 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 
-public class R8TestBuilder extends TestCompilerBuilder<R8Command, Builder, R8TestBuilder> {
-
-  private final R8Command.Builder builder;
+public class R8TestBuilder
+    extends TestCompilerBuilder<R8Command, Builder, R8TestCompileResult, R8TestBuilder> {
 
   private R8TestBuilder(TestState state, Builder builder, Backend backend) {
     super(state, builder, backend);
-    this.builder = builder;
   }
 
   public static R8TestBuilder create(TestState state, Backend backend) {
@@ -35,12 +35,16 @@
   }
 
   @Override
-  void internalCompile(Builder builder, Consumer<InternalOptions> optionsConsumer)
+  R8TestCompileResult internalCompile(
+      Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
     if (enableInliningAnnotations) {
       ToolHelper.allowTestProguardOptions(builder);
     }
+    StringBuilder proguardMapBuilder = new StringBuilder();
+    builder.setProguardMapConsumer((string, ignore) -> proguardMapBuilder.append(string));
     ToolHelper.runR8WithoutResult(builder.build(), optionsConsumer);
+    return new R8TestCompileResult(getState(), backend, app.get(), proguardMapBuilder.toString());
   }
 
   public R8TestBuilder addDataResources(List<DataEntryResource> resources) {
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
new file mode 100644
index 0000000..45fb31c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -0,0 +1,32 @@
+// 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.TestBase.Backend;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+public class R8TestCompileResult extends TestCompileResult {
+
+  private final Backend backend;
+  private final String proguardMap;
+
+  R8TestCompileResult(TestState state, Backend backend, AndroidApp app, String proguardMap) {
+    super(state, app);
+    this.backend = backend;
+    this.proguardMap = proguardMap;
+  }
+
+  @Override
+  public Backend getBackend() {
+    return backend;
+  }
+
+  @Override
+  public CodeInspector inspector() throws IOException, ExecutionException {
+    return new CodeInspector(app, proguardMap);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 4e7cf37..7505a83 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -12,19 +12,23 @@
 import java.nio.file.Path;
 import java.util.concurrent.ExecutionException;
 
-public class TestCompileResult {
-  private final TestState state;
-  private final Backend backend;
-  private final AndroidApp app;
+public abstract class TestCompileResult {
+  final TestState state;
+  final AndroidApp app;
 
-  public TestCompileResult(TestState state, Backend backend, AndroidApp app) {
+  TestCompileResult(TestState state, AndroidApp app) {
     this.state = state;
-    this.backend = backend;
     this.app = app;
   }
 
+  public abstract Backend getBackend();
+
+  public TestRunResult run(Class<?> mainClass) throws IOException {
+    return run(mainClass.getTypeName());
+  }
+
   public TestRunResult run(String mainClass) throws IOException {
-    switch (backend) {
+    switch (getBackend()) {
       case DEX:
         return runArt(mainClass);
       case CF:
@@ -34,6 +38,12 @@
     }
   }
 
+  public TestCompileResult writeToZip(Path file) throws IOException {
+    app.writeToZip(
+        file, getBackend() == Backend.DEX ? OutputMode.DexIndexed : OutputMode.ClassFile);
+    return this;
+  }
+
   public CodeInspector inspector() throws IOException, ExecutionException {
     return new CodeInspector(app);
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index db25352..4706125 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -5,17 +5,21 @@
 
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidAppConsumers;
 import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.base.Suppliers;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 public abstract class TestCompilerBuilder<
         C extends BaseCompilerCommand,
         B extends BaseCompilerCommand.Builder<C, B>,
-        T extends TestCompilerBuilder<C, B, T>>
+        R extends TestCompileResult,
+        T extends TestCompilerBuilder<C, B, R, T>>
     extends TestBuilder<T> {
 
   public static final Consumer<InternalOptions> DEFAULT_OPTIONS =
@@ -24,8 +28,8 @@
         public void accept(InternalOptions options) {}
       };
 
-  private final B builder;
-  private final Backend backend;
+  final B builder;
+  final Backend backend;
 
   // Default initialized setup. Can be overwritten if needed.
   private Path defaultLibrary;
@@ -43,7 +47,8 @@
 
   abstract T self();
 
-  abstract void internalCompile(B builder, Consumer<InternalOptions> optionsConsumer)
+  abstract R internalCompile(
+      B builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException;
 
   public T addOptionsModification(Consumer<InternalOptions> optionsConsumer) {
@@ -51,7 +56,7 @@
     return self();
   }
 
-  public TestCompileResult compile() throws CompilationFailedException {
+  public R compile() throws CompilationFailedException {
     AndroidAppConsumers sink = new AndroidAppConsumers();
     builder.setProgramConsumer(sink.wrapProgramConsumer(programConsumer));
     if (defaultLibrary != null) {
@@ -60,8 +65,7 @@
     if (backend == Backend.DEX && defaultMinApiLevel != null) {
       builder.setMinApiLevel(defaultMinApiLevel.getLevel());
     }
-    internalCompile(builder, optionsConsumer);
-    return new TestCompileResult(getState(), backend, sink.build());
+    return internalCompile(builder, optionsConsumer, Suppliers.memoize(sink::build));
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 28404f0..660156a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.signature.GenericSignatureAction;
 import com.android.tools.r8.naming.signature.GenericSignatureParser;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
@@ -111,10 +112,18 @@
     return internalOptions;
   }
 
-  public CodeInspector(AndroidApp app, Path proguardMap) throws IOException, ExecutionException {
+  public CodeInspector(AndroidApp app, Path proguardMapFile)
+      throws IOException, ExecutionException {
     this(
         new ApplicationReader(app, runOptionsConsumer(null), new Timing("CodeInspector"))
-            .read(StringResource.fromFile(proguardMap)));
+            .read(StringResource.fromFile(proguardMapFile)));
+  }
+
+  public CodeInspector(AndroidApp app, String proguardMapContent)
+      throws IOException, ExecutionException {
+    this(
+        new ApplicationReader(app, runOptionsConsumer(null), new Timing("CodeInspector"))
+            .read(StringResource.fromString(proguardMapContent, Origin.unknown())));
   }
 
   public CodeInspector(DexApplication application) {