Version 2.1.45
Cherry-pick: Test markers in the desugared library
CL: https://r8-review.googlesource.com/c/r8/+/52290
Bug: 159565356
Change-Id: I9915b13d9e6316952b7fc933172d35728dc1fea1
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 951b795..80f8371 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -100,6 +100,7 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
@@ -110,7 +111,6 @@
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -209,6 +209,10 @@
try {
Marker marker = options.getMarker(Tool.R8);
assert marker != null;
+ // Get the markers from the input which are different from the one created for this
+ // compilation
+ Set<Marker> markers = new HashSet<>(options.itemFactory.extractMarkers());
+ markers.remove(marker);
if (options.isGeneratingClassFiles()) {
new CfApplicationWriter(
application, appView, options, marker, graphLense, namingLens, proguardMapSupplier)
@@ -218,7 +222,8 @@
application,
appView,
options,
- Collections.singletonList(marker),
+ // Ensure that the marker for this compilation is the first in the list.
+ ImmutableList.<Marker>builder().add(marker).addAll(markers).build(),
graphLense,
initClassLens,
namingLens,
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 84eb5f4..d2eebf1 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "2.1.44";
+ public static final String LABEL = "2.1.45";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 8ee86f3..6a54ac6 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -235,8 +235,8 @@
proguardMapId = proguardMapSupplier.writeProguardMap();
}
- // If we do have a map then we're called from R8. In that case we have exactly one marker.
- assert proguardMapId == null || (markers != null && markers.size() == 1);
+ // If we do have a map then we're called from R8. In that case we have at least one marker.
+ assert proguardMapId == null || (markers != null && markers.size() >= 1);
if (markers != null && !markers.isEmpty()) {
if (proguardMapId != null) {
diff --git a/src/test/java/com/android/tools/r8/MarkerMatcher.java b/src/test/java/com/android/tools/r8/MarkerMatcher.java
new file mode 100644
index 0000000..90aec54
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/MarkerMatcher.java
@@ -0,0 +1,181 @@
+// Copyright (c) 2020, 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public abstract class MarkerMatcher extends TypeSafeMatcher<Marker> {
+
+ public static void assertMarkersMatch(
+ Iterable<Marker> markers, Collection<Matcher<Marker>> matchers) {
+ // Match is unordered, but we make no attempts to find the maximum match.
+ int markerCount = 0;
+ Set<Marker> matchedMarkers = new HashSet<>();
+ Set<Matcher<Marker>> matchedMatchers = new HashSet<>();
+ for (Marker marker : markers) {
+ markerCount++;
+ for (Matcher<Marker> matcher : matchers) {
+ if (matchedMatchers.contains(matcher)) {
+ continue;
+ }
+ if (matcher.matches(marker)) {
+ matchedMarkers.add(marker);
+ matchedMatchers.add(matcher);
+ break;
+ }
+ }
+ }
+ StringBuilder builder = new StringBuilder();
+ boolean failedMatching = false;
+ if (matchedMarkers.size() < markerCount) {
+ failedMatching = true;
+ builder.append("\nUnmatched markers:");
+ for (Marker marker : markers) {
+ if (!matchedMarkers.contains(marker)) {
+ builder.append("\n - ").append(marker);
+ }
+ }
+ }
+ if (matchedMatchers.size() < matchers.size()) {
+ failedMatching = true;
+ builder.append("\nUnmatched matchers:");
+ for (Matcher<Marker> matcher : matchers) {
+ if (!matchedMatchers.contains(matcher)) {
+ builder.append("\n - ").append(matcher);
+ }
+ }
+ }
+ if (failedMatching) {
+ builder.append("\nAll markers:");
+ for (Marker marker : markers) {
+ builder.append("\n - ").append(marker);
+ }
+ builder.append("\nAll matchers:");
+ for (Matcher<Marker> matcher : matchers) {
+ builder.append("\n - ").append(matcher);
+ }
+ fail(builder.toString());
+ }
+ // Double check consistency.
+ assertEquals(matchers.size(), markerCount);
+ assertEquals(markerCount, matchedMarkers.size());
+ assertEquals(markerCount, matchedMatchers.size());
+ }
+
+ public static Matcher<Marker> markerTool(Tool tool) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getTool() == tool;
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText("tool ").appendText(tool.name());
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerCompilationMode(CompilationMode compilationMode) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getCompilationMode().equals(compilationMode.name().toLowerCase());
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.COMPILATION_MODE + " ").appendText(compilationMode.name());
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerMinApi(AndroidApiLevel level) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getMinApi() == level.getLevel();
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.MIN_API + " ").appendText(level.toString());
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerHasChecksums(boolean value) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getHasChecksums() == value;
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.HAS_CHECKSUMS + " ").appendText(Boolean.toString(value));
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerR8Mode(String r8Mode) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getR8Mode().equals(r8Mode);
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.R8_MODE + " ").appendText(r8Mode);
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerDesugaredLibraryIdentifier(
+ String desugaredLibraryIdentifier) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ if (marker.getDesugaredLibraryIdentifiers().length != 1) {
+ return false;
+ }
+ return marker.getDesugaredLibraryIdentifiers()[0].equals(desugaredLibraryIdentifier);
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description
+ .appendText(Marker.DESUGARED_LIBRARY_IDENTIFIERS + " ")
+ .appendText(desugaredLibraryIdentifier);
+ }
+ };
+ }
+
+ @Override
+ protected boolean matchesSafely(Marker marker) {
+ return eval(marker);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ explain(description.appendText("a marker "));
+ }
+
+ protected abstract boolean eval(Marker diagnostic);
+
+ protected abstract void explain(Description description);
+}
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
new file mode 100644
index 0000000..4fa3dd6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -0,0 +1,88 @@
+// Copyright (c) 2020, 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 static com.android.tools.r8.MarkerMatcher.assertMarkersMatch;
+import static com.android.tools.r8.MarkerMatcher.markerCompilationMode;
+import static com.android.tools.r8.MarkerMatcher.markerDesugaredLibraryIdentifier;
+import static com.android.tools.r8.MarkerMatcher.markerHasChecksums;
+import static com.android.tools.r8.MarkerMatcher.markerMinApi;
+import static com.android.tools.r8.MarkerMatcher.markerR8Mode;
+import static com.android.tools.r8.MarkerMatcher.markerTool;
+import static org.hamcrest.CoreMatchers.allOf;
+
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MarkersTest extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}, compilationMode {1}, shrinkDesugaredLibrary {2}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withNoneRuntime().build(),
+ CompilationMode.values(),
+ BooleanUtils.values());
+ }
+
+ private final TestParameters parameters;
+ private final CompilationMode compilationMode;
+ private final boolean shrinkDesugaredLibrary;
+
+ public MarkersTest(
+ TestParameters parameters, CompilationMode compilationMode, boolean shrinkDesugaredLibrary) {
+ this.parameters = parameters;
+ this.compilationMode = compilationMode;
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ }
+
+ @Test
+ public void testL8Marker() throws Throwable {
+ AndroidApiLevel apiLevel = AndroidApiLevel.L;
+ Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
+ L8Command.Builder builder =
+ L8Command.builder()
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+ .setMinApiLevel(apiLevel.getLevel())
+ .setMode(compilationMode)
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+ .setOutput(output, OutputMode.DexIndexed);
+ if (shrinkDesugaredLibrary) {
+ builder.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown());
+ }
+ L8.run(builder.build());
+ Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
+ Matcher<Marker> l8Matcher =
+ allOf(
+ markerTool(Tool.L8),
+ markerCompilationMode(compilationMode),
+ markerDesugaredLibraryIdentifier("com.tools.android:desugar_jdk_libs:1.0.9"),
+ markerHasChecksums(false));
+ Matcher<Marker> d8Matcher =
+ allOf(
+ markerTool(Tool.R8),
+ markerCompilationMode(compilationMode),
+ markerMinApi(apiLevel),
+ markerR8Mode("compatibility"));
+ Matcher<Marker> r8Matcher =
+ allOf(markerTool(Tool.D8), markerCompilationMode(compilationMode), markerMinApi(apiLevel));
+ if (shrinkDesugaredLibrary) {
+ assertMarkersMatch(markers, ImmutableList.of(l8Matcher, d8Matcher));
+ } else {
+ assertMarkersMatch(markers, ImmutableList.of(l8Matcher, r8Matcher));
+ }
+ }
+}