Merge "Proposed minimal DiagnosticsHandler API."
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) {
diff --git a/src/main/java/com/android/tools/r8/CompilationException.java b/src/main/java/com/android/tools/r8/CompilationException.java
index 8e1e56c..c7477b6 100644
--- a/src/main/java/com/android/tools/r8/CompilationException.java
+++ b/src/main/java/com/android/tools/r8/CompilationException.java
@@ -9,7 +9,7 @@
* This is always an expected error and considered a user input issue.
* A user-understandable message must be provided.
*/
-public class CompilationException extends Exception {
+public class CompilationException extends Exception implements Diagnostic {
private static final long serialVersionUID = 1L;
/**
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 9b79616..19f478a 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -60,18 +60,26 @@
/**
* Main API entry for the D8 dexer.
*
+ * <p>If the D8Command contains a DiagnosticsHandler that does not throw a CompilationException
+ * on error this method returns null if the run fails.
+ *
* @param command D8 command.
* @return the compilation result.
*/
public static D8Output run(D8Command command) throws IOException, CompilationException {
InternalOptions options = command.getInternalOptions();
- CompilationResult result = runForTesting(command.getInputApp(), options);
- assert result != null;
- D8Output output = new D8Output(result.androidApp, command.getOutputMode());
- if (command.getOutputPath() != null) {
- output.write(command.getOutputPath());
+ try {
+ CompilationResult result = runForTesting(command.getInputApp(), options);
+ assert result != null;
+ D8Output output = new D8Output(result.androidApp, command.getOutputMode());
+ if (command.getOutputPath() != null) {
+ output.write(command.getOutputPath());
+ }
+ return output;
+ } catch (CompilationException e) {
+ options.diagnosticsHandler.error(e);
+ return null;
}
- return output;
}
/**
@@ -80,21 +88,29 @@
* <p>The D8 dexer API is intentionally limited and should "do the right thing" given a set of
* inputs. If the API does not suffice please contact the R8 team.
*
+ * <p>If the D8Command contains a DiagnosticsHandler that does not throw a CompilationException
+ * on error this method returns null if the run fails.
+ *
* @param command D8 command.
* @param executor executor service from which to get threads for multi-threaded processing.
- * @return the compilation result.
+ * @return the compilation result
*/
public static D8Output run(D8Command command, ExecutorService executor)
throws IOException, CompilationException {
InternalOptions options = command.getInternalOptions();
- CompilationResult result = runForTesting(
- command.getInputApp(), options, executor);
- assert result != null;
- D8Output output = new D8Output(result.androidApp, command.getOutputMode());
- if (command.getOutputPath() != null) {
- output.write(command.getOutputPath());
+ try {
+ CompilationResult result = runForTesting(
+ command.getInputApp(), options, executor);
+ assert result != null;
+ D8Output output = new D8Output(result.androidApp, command.getOutputMode());
+ if (command.getOutputPath() != null) {
+ output.write(command.getOutputPath());
+ }
+ return output;
+ } catch (CompilationException e) {
+ options.diagnosticsHandler.error(e);
+ return null;
}
- return output;
}
private static void run(String[] args) throws IOException, CompilationException {
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index f2aebc7..ac86781 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.OffOrAuto;
import com.android.tools.r8.utils.OutputMode;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
@@ -99,6 +98,7 @@
getOutputMode(),
getMode(),
getMinApiLevel(),
+ getDiagnosticsHandler(),
intermediate);
}
}
@@ -195,8 +195,9 @@
OutputMode outputMode,
CompilationMode mode,
int minApiLevel,
+ DiagnosticsHandler diagnosticsHandler,
boolean intermediate) {
- super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ super(inputApp, outputPath, outputMode, mode, minApiLevel, diagnosticsHandler);
this.intermediate = intermediate;
}
@@ -224,6 +225,7 @@
assert internal.outline.enabled;
internal.outline.enabled = false;
internal.outputMode = getOutputMode();
+ internal.diagnosticsHandler = getDiagnosticsHandler();
return internal;
}
}
diff --git a/src/main/java/com/android/tools/r8/Diagnostic.java b/src/main/java/com/android/tools/r8/Diagnostic.java
new file mode 100644
index 0000000..6be2748
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/Diagnostic.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 com.android.tools.r8;
+
+/**
+ * Interface for all diagnostic message produced by D8 and R8.
+ */
+public interface Diagnostic {
+ String toString();
+}
diff --git a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
new file mode 100644
index 0000000..4a89c6f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
@@ -0,0 +1,42 @@
+// 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 com.android.tools.r8;
+
+/**
+ * A DiagnosticsHandler can be provided to customize handling of diagnostics information.
+ *
+ * <p>During compilation the error, warning and info methods will be called.
+ */
+public interface DiagnosticsHandler {
+
+ /**
+ * Handle error diagnostics.
+ *
+ * <p>By default this throws the exception.
+ *
+ * @param error CompilationException containing error information.
+ * @throws CompilationException
+ */
+ default void error(CompilationException error) throws CompilationException {
+ throw error;
+ }
+
+ /**
+ * Handle warning diagnostics.
+ *
+ * @param warning Diagnostic containing warning information.
+ */
+ default void warning(Diagnostic warning) {
+ System.err.println(warning.toString());
+ }
+
+ /**
+ * Handle info diagnostics.
+ *
+ * @param info Diagnostic containing the information.
+ */
+ default void info(Diagnostic info) {
+ System.out.println(info.toString());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 45af2b3..899a194 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -57,7 +57,6 @@
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -396,12 +395,15 @@
* <p>The R8 API is intentionally limited and should "do the right thing" given a command. If this
* API does not suffice please contact the R8 team.
*
+ * <p>If the R8Command contains a DiagnosticsHandler that does not throw a CompilationException
+ * on error this method returns null if the run fails.
+ *
* @param command R8 command.
* @return the compilation result.
*/
- public static AndroidApp run(R8Command command)
- throws IOException, CompilationException {
- ExecutorService executorService = ThreadUtils.getExecutorService(command.getInternalOptions());
+ public static AndroidApp run(R8Command command) throws IOException, CompilationException {
+ InternalOptions options = command.getInternalOptions();
+ ExecutorService executorService = ThreadUtils.getExecutorService(options);
try {
return run(command, executorService);
} finally {
@@ -476,6 +478,9 @@
* <p>The R8 API is intentionally limited and should "do the right thing" given a command. If this
* API does not suffice please contact the R8 team.
*
+ * <p>If the R8Command contains a DiagnosticsHandler that does not throw a CompilationException
+ * on error this method returns null if the run fails.
+ *
* @param command R8 command.
* @param executor executor service from which to get threads for multi-threaded processing.
* @return the compilation result.
@@ -483,10 +488,15 @@
public static AndroidApp run(R8Command command, ExecutorService executor)
throws IOException, CompilationException {
InternalOptions options = command.getInternalOptions();
- AndroidApp outputApp =
- runForTesting(command.getInputApp(), options, executor).androidApp;
- writeOutputs(command, options, outputApp);
- return outputApp;
+ try {
+ AndroidApp outputApp =
+ runForTesting(command.getInputApp(), options, executor).androidApp;
+ writeOutputs(command, options, outputApp);
+ return outputApp;
+ } catch (CompilationException e) {
+ options.diagnosticsHandler.error(e);
+ return null;
+ }
}
private static void run(String[] args)
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 5e0b7d4..a6a1c33 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -237,6 +237,7 @@
configuration,
getMode(),
getMinApiLevel(),
+ getDiagnosticsHandler(),
useTreeShaking,
useDiscardedChecker,
useMinification,
@@ -392,12 +393,13 @@
ProguardConfiguration proguardConfiguration,
CompilationMode mode,
int minApiLevel,
+ DiagnosticsHandler diagnosticsHandler,
boolean useTreeShaking,
boolean useDiscardedChecker,
boolean useMinification,
boolean ignoreMissingClasses,
Path proguardMapOutput) {
- super(inputApp, outputPath, outputMode, mode, minApiLevel);
+ super(inputApp, outputPath, outputMode, mode, minApiLevel, diagnosticsHandler);
assert proguardConfiguration != null;
assert mainDexKeepRules != null;
assert getOutputMode() == OutputMode.Indexed : "Only regular mode is supported in R8";
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 2ba4421..4405ef4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -101,7 +101,7 @@
this.lambdaRewriter = enableDesugaring ? new LambdaRewriter(this) : null;
this.interfaceMethodRewriter =
(enableDesugaring && enableInterfaceMethodDesugaring())
- ? new InterfaceMethodRewriter(this) : null;
+ ? new InterfaceMethodRewriter(this, options) : null;
if (enableWholeProgramOptimizations) {
assert appInfo.hasSubtyping();
this.inliner = new Inliner(appInfo.withSubtyping(), graphLense, options);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 99417c3..c5545f5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.ApiLevelException;
import com.android.tools.r8.Resource;
-import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
@@ -26,7 +25,8 @@
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeSuper;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.ListIterator;
@@ -65,6 +65,7 @@
private static final String DEFAULT_METHOD_PREFIX = "$default$";
private final IRConverter converter;
+ private final InternalOptions options;
final DexItemFactory factory;
// All forwarding methods generated during desugaring. We don't synchronize access
@@ -84,10 +85,11 @@
ExcludeDexResources
}
- public InterfaceMethodRewriter(IRConverter converter) {
+ public InterfaceMethodRewriter(IRConverter converter, InternalOptions options) {
assert converter != null;
this.converter = converter;
- this.factory = converter.application.dexItemFactory;
+ this.options = options;
+ this.factory = options.itemFactory;
}
// Rewrites the references to static and default interface methods.
@@ -298,7 +300,7 @@
// TODO replace by a proper warning mechanic (see b/65154707).
// TODO think about using a common deduplicating mechanic with Enqueuer
if (reportedMissing.add(missing)) {
- System.err.println(message);
+ options.diagnosticsHandler.warning(new StringDiagnostic(message));
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java b/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.java
new file mode 100644
index 0000000..68c2840
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/DefaultDiagnosticsHandler.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 com.android.tools.r8.utils;
+
+import com.android.tools.r8.DiagnosticsHandler;
+
+public class DefaultDiagnosticsHandler implements DiagnosticsHandler {
+}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index f497ce5..a72d356 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InvalidDebugInfoException;
@@ -126,6 +126,8 @@
public Path proguardMapOutput = null;
+ public DiagnosticsHandler diagnosticsHandler = new DefaultDiagnosticsHandler();
+
public void warningInvalidDebugInfo(DexEncodedMethod method, InvalidDebugInfoException e) {
warningInvalidDebugInfoCount++;
}
diff --git a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
new file mode 100644
index 0000000..0606be2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
@@ -0,0 +1,19 @@
+// 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 com.android.tools.r8.utils;
+
+import com.android.tools.r8.Diagnostic;
+
+public class StringDiagnostic implements Diagnostic {
+ private final String message;
+
+ public StringDiagnostic(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ return message;
+ }
+}