Make it possible to change the level of the checkdiscard diagnostic
Bug: 166258805
Change-Id: Ide046a46493e9963ca574dc60660b7dc74509662
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index f873d6a..9bed6c3 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -1091,7 +1091,8 @@
new StringDiagnostic(
"Item " + definition.toSourceString() + " was not discarded.\n" + baos.toString()));
}
- throw new CompilationError("Discard checks failed.");
+ options.reporter.error(new StringDiagnostic("Discard checks failed."));
+ options.reporter.failIfPendingErrors();
}
private static boolean verifyNoJarApplicationReaders(Collection<DexProgramClass> classes) {
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 230e5ca..ec4e675 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -171,6 +171,10 @@
public boolean isTracingMainDex() {
return this == MAIN_DEX_TRACING;
}
+
+ public boolean isWhyAreYouKeeping() {
+ return this == WHY_ARE_YOU_KEEPING;
+ }
}
private final boolean forceProguardCompatibility;
@@ -2735,6 +2739,11 @@
finalizeLibraryMethodOverrideInformation();
analyses.forEach(analyses -> analyses.done(this));
assert verifyKeptGraph();
+ if (mode.isWhyAreYouKeeping()) {
+ // For why are you keeping the information is reported through the kept graph callbacks and
+ // no AppInfo is returned.
+ return null;
+ }
AppInfoWithLiveness appInfoWithLiveness = createAppInfo(appInfo);
if (options.testing.enqueuerInspector != null) {
options.testing.enqueuerInspector.accept(appInfoWithLiveness, mode);
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java
new file mode 100644
index 0000000..dd7757c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardModifyDiagnosticsLevelTest.java
@@ -0,0 +1,110 @@
+// 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.checkdiscarded;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.DiagnosticsLevel;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.checkdiscarded.testclasses.Main;
+import com.android.tools.r8.checkdiscarded.testclasses.UnusedClass;
+import com.android.tools.r8.checkdiscarded.testclasses.UsedClass;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class CheckDiscardModifyDiagnosticsLevelTest extends TestBase {
+
+ @Parameters(name = "{0}, {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withNoneRuntime().build(), DiagnosticsLevel.values());
+ }
+
+ private final DiagnosticsLevel mappedLevel;
+
+ public CheckDiscardModifyDiagnosticsLevelTest(TestParameters parameters, DiagnosticsLevel level) {
+ parameters.assertNoneRuntime();
+ this.mappedLevel = level;
+ }
+
+ private void noInlining(InternalOptions options) {
+ options.enableInlining = false;
+ }
+
+ private Matcher<Diagnostic> discardCheckFailedMatcher() {
+ return diagnosticMessage(startsWith("Discard checks failed"));
+ }
+
+ private Collection<Matcher<Diagnostic>> errorMatchers() {
+ return mappedLevel == DiagnosticsLevel.ERROR
+ ? ImmutableList.of(discardCheckFailedMatcher())
+ : ImmutableList.of();
+ }
+
+ private Collection<Matcher<Diagnostic>> warningMatchers() {
+ return mappedLevel == DiagnosticsLevel.WARNING
+ ? ImmutableList.of(discardCheckFailedMatcher())
+ : ImmutableList.of();
+ }
+
+ private Collection<Matcher<Diagnostic>> infoMatchers() {
+ List<Matcher<Diagnostic>> matchers = new ArrayList();
+ matchers.add(
+ allOf(
+ diagnosticMessage(containsString("UsedClass was not discarded")),
+ diagnosticMessage(containsString("is instantiated in"))));
+ if (mappedLevel == DiagnosticsLevel.INFO) {
+ matchers.add(discardCheckFailedMatcher());
+ }
+ return matchers;
+ }
+
+ @Test
+ public void dontFailCompilationOnCheckDiscardedFailure() {
+ try {
+ testForR8(Backend.DEX)
+ .addProgramClasses(UnusedClass.class, UsedClass.class, Main.class)
+ .addKeepMainRule(Main.class)
+ .addKeepRules("-checkdiscard class " + UsedClass.class.getTypeName())
+ .addOptionsModification(this::noInlining)
+ .setDiagnosticsLevelModifier(
+ (level, diagnostic) -> {
+ if (diagnostic instanceof StringDiagnostic
+ && diagnostic.getDiagnosticMessage().equals("Discard checks failed.")) {
+ return mappedLevel;
+ } else {
+ return level;
+ }
+ })
+ .allowDiagnosticMessages()
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics
+ .assertErrorsMatch(errorMatchers())
+ .assertWarningsMatch(warningMatchers())
+ .assertInfosMatch(infoMatchers()));
+ assertTrue(mappedLevel == DiagnosticsLevel.INFO || mappedLevel == DiagnosticsLevel.WARNING);
+ } catch (CompilationFailedException e) {
+ assertEquals(mappedLevel, DiagnosticsLevel.ERROR);
+ }
+ }
+}