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));
+    }
+  }
+}