Proposed minimal DiagnosticsHandler API.

Add a method to D8Command and R8Command to supply a
Diagnostics handler that will be used for all diagnostic information
from the compilers.

This is currently only used for CompilationException and the warnings
generated in connection with default interface method desugaring.
Once we agree on the interface, we should make sure that we use this
instead of stdout and stderr for all warning and info diagnostic.

The current default implementation of the API keeps the behavior of
the current code. However, the API allows us to extend the Diagnostic
messages with more information over time. Also, with errors passed
to the DiagnosticsHandler we can consider making certain errors
non-fatal and keep on trucking to get more errors reported in one
compilation.

R=benoitlamarche@google.com, gavra@google.com, zerny@google.com

Change-Id: Iedd0b7d71460c14a78c13c09b340e491071c2fae
Bug: 67087703
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index e659231..72cfbab 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -3,9 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
-import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.OutputMode;
 import java.nio.file.Path;
@@ -21,14 +21,15 @@
   private final OutputMode outputMode;
   private final CompilationMode mode;
   private final int minApiLevel;
+  private final DiagnosticsHandler diagnosticsHandler;
 
   BaseCompilerCommand(boolean printHelp, boolean printVersion) {
     super(printHelp, printVersion);
-
-    this.outputPath = null;
-    this.outputMode = OutputMode.Indexed;
-    this.mode = null;
-    this.minApiLevel = 0;
+    outputPath = null;
+    outputMode = OutputMode.Indexed;
+    mode = null;
+    minApiLevel = 0;
+    diagnosticsHandler = new DefaultDiagnosticsHandler();
   }
 
   BaseCompilerCommand(
@@ -36,7 +37,8 @@
       Path outputPath,
       OutputMode outputMode,
       CompilationMode mode,
-      int minApiLevel) {
+      int minApiLevel,
+      DiagnosticsHandler diagnosticsHandler) {
     super(app);
     assert mode != null;
     assert minApiLevel > 0;
@@ -44,6 +46,7 @@
     this.outputMode = outputMode;
     this.mode = mode;
     this.minApiLevel = minApiLevel;
+    this.diagnosticsHandler = diagnosticsHandler;
   }
 
   public Path getOutputPath() {
@@ -62,6 +65,10 @@
     return outputMode;
   }
 
+  public DiagnosticsHandler getDiagnosticsHandler() {
+    return diagnosticsHandler;
+  }
+
   abstract public static class Builder<C extends BaseCompilerCommand, B extends Builder<C, B>>
       extends BaseCommand.Builder<C, B> {
 
@@ -69,6 +76,7 @@
     private OutputMode outputMode = OutputMode.Indexed;
     private CompilationMode mode;
     private int minApiLevel = AndroidApiLevel.getDefault().getLevel();
+    private DiagnosticsHandler diagnosticsHandler = new DefaultDiagnosticsHandler();
 
     protected Builder(CompilationMode mode) {
       this(AndroidApp.builder(), mode, false);
@@ -135,6 +143,15 @@
       return self();
     }
 
+    public DiagnosticsHandler getDiagnosticsHandler() {
+      return diagnosticsHandler;
+    }
+
+    public B setDiagnosticsHandler(DiagnosticsHandler diagnosticsHandler) {
+      this.diagnosticsHandler = diagnosticsHandler;
+      return self();
+    }
+
     protected void validate() throws CompilationException {
       super.validate();
       if (getAppBuilder().hasMainDexList() && outputMode == OutputMode.FilePerInputClass) {