Add support for tests using androidx keep annotations

Bug: b/392865072
Change-Id: I640b6f59b08e2a18cc9e9409562bffc54ec0f1bd
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index 1f3f338..e407d6a 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -1152,3 +1152,11 @@
 fun Project.allInternalDependencies(): List<ThirdPartyDependency> {
   return allDependencies().filter { x -> x.type == DependencyType.X20 }
 }
+
+fun extractClassesPaths(prefix: String, vararg paths: String): String {
+  val result: MutableList<String> = ArrayList()
+  paths.forEach { it ->
+    result.addAll(it.split(File.pathSeparator).filter { it.contains("${prefix}build/classes") })
+  }
+  return result.joinToString(File.pathSeparator)
+}
diff --git a/d8_r8/main/build.gradle.kts b/d8_r8/main/build.gradle.kts
index 989b99a..595726d 100644
--- a/d8_r8/main/build.gradle.kts
+++ b/d8_r8/main/build.gradle.kts
@@ -3,9 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import java.net.URI
-import java.nio.file.Path
 import java.nio.file.Paths
-import kotlin.io.path.exists
 import java.nio.file.Files.readString
 import net.ltgt.gradle.errorprone.errorprone
 import org.gradle.api.artifacts.ModuleVersionIdentifier
@@ -89,8 +87,9 @@
   }
 }
 
-val keepAnnoJarTask = projectTask("keepanno", "jar")
 val assistantJarTask = projectTask("assistant", "jar")
+val keepAnnoJarTask = projectTask("keepanno", "jar")
+val keepAnnoAndroidXAnnotationsJar = projectTask("keepanno", "keepAnnoAndroidXAnnotationsJar")
 val resourceShrinkerJarTask = projectTask("resourceshrinker", "jar")
 val resourceShrinkerDepsTask = projectTask("resourceshrinker", "depsJar")
 
@@ -292,8 +291,10 @@
 val r8WithRelocatedDeps by registering(Exec::class) {
     dependsOn(depsJar)
     dependsOn(swissArmyKnifeWithoutLicense)
-    val swissArmy = swissArmyKnifeWithoutLicense.get().outputs.getFiles().getSingleFile()
-    val deps = depsJar.get().outputs.files.getSingleFile()
+    dependsOn(keepAnnoAndroidXAnnotationsJar)
+    val swissArmy = swissArmyKnifeWithoutLicense.get().outputs.files.singleFile
+    val deps = depsJar.get().outputs.files.singleFile
+    val androidXAnnotationsJar = keepAnnoAndroidXAnnotationsJar.outputs.files.singleFile
     inputs.files(listOf(swissArmy, deps))
     val output = getRoot().resolveAll("build", "libs", "r8.jar")
     outputs.file(output)
@@ -305,6 +306,8 @@
              "$swissArmy",
              "--input",
              "$deps",
+             "--input",
+             "$androidXAnnotationsJar",
              "--output",
              "$output",
              // Add identity mapping to enforce no relocation of things already in package
diff --git a/d8_r8/test/build.gradle.kts b/d8_r8/test/build.gradle.kts
index 3da29df..564d0ea 100644
--- a/d8_r8/test/build.gradle.kts
+++ b/d8_r8/test/build.gradle.kts
@@ -22,6 +22,7 @@
 dependencies { }
 
 val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
+val keepAnnoCompileKotlinTask = projectTask("keepanno", "compileKotlin")
 val keepAnnoSourcesTask = projectTask("keepanno", "sourcesJar")
 val assistantJarTask = projectTask("assistant", "jar")
 val mainDepsJarTask = projectTask("main", "depsJar")
@@ -431,7 +432,10 @@
 
     systemProperty(
       "BUILD_PROP_KEEPANNO_RUNTIME_PATH",
-      keepAnnoCompileTask.getOutputs().getFiles().getAsPath().split(File.pathSeparator)[0])
+      extractClassesPaths(
+        "keepanno/",
+        keepAnnoCompileTask.outputs.files.asPath,
+        keepAnnoCompileKotlinTask.outputs.files.asPath))
     systemProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR",
             getRoot().resolveAll("build", "test", "examplesJava11", "classes"))
     systemProperty("BUILD_PROP_R8_RUNTIME_PATH", r8LibJar)
diff --git a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
index 7b900dc..18e0f2b 100644
--- a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
+++ b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
@@ -33,6 +33,7 @@
 
 val keepAnnoJarTask = projectTask("keepanno", "jar")
 val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
+val keepAnnoCompileKotlinTask = projectTask("keepanno", "compileKotlin")
 val mainR8RelocatedTask = projectTask("main", "r8WithRelocatedDeps")
 val resourceShrinkerJavaCompileTask = projectTask("resourceshrinker", "compileJava")
 val resourceShrinkerKotlinCompileTask = projectTask("resourceshrinker", "compileKotlin")
@@ -80,7 +81,10 @@
                    testbaseJavaCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0])
     systemProperty(
       "BUILD_PROP_KEEPANNO_RUNTIME_PATH",
-      keepAnnoCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0])
+      extractClassesPaths(
+        "keepanno/",
+        keepAnnoCompileTask.outputs.files.asPath,
+        keepAnnoCompileKotlinTask.outputs.files.asPath))
     systemProperty("R8_WITH_RELOCATED_DEPS", mainR8RelocatedTask.outputs.files.singleFile)
     systemProperty("BUILD_PROP_R8_RUNTIME_PATH", mainR8RelocatedTask.outputs.files.singleFile)
   }
diff --git a/d8_r8/test_modules/tests_java_8/build.gradle.kts b/d8_r8/test_modules/tests_java_8/build.gradle.kts
index 4dfd63e..7637a41 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -39,6 +39,7 @@
 val keepAnnoJarTask = projectTask("keepanno", "jar")
 val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
 val assistantCompileTask = projectTask("assistant", "compileJava")
+val keepAnnoCompileKotlinTask = projectTask("keepanno", "compileKotlin")
 val mainCompileTask = projectTask("main", "compileJava")
 val mainDepsJarTask = projectTask("main", "depsJar")
 val resourceShrinkerJavaCompileTask = projectTask("resourceshrinker", "compileJava")
@@ -136,11 +137,13 @@
     systemProperty("TEST_DATA_LOCATION",
                    layout.buildDirectory.dir("classes/java/test").get().toString())
     systemProperty("TESTBASE_DATA_LOCATION",
-                   testbaseJavaCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0])
-
+                   testbaseJavaCompileTask.outputs.files.asPath.split(File.pathSeparator)[0])
     systemProperty(
       "BUILD_PROP_KEEPANNO_RUNTIME_PATH",
-      keepAnnoCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0])
+      extractClassesPaths(
+        "keepanno/",
+        keepAnnoCompileTask.outputs.files.asPath,
+        keepAnnoCompileKotlinTask.outputs.files.asPath))
     // This path is set when compiling examples jar task in DependenciesPlugin.
     systemProperty("EXAMPLES_JAVA_11_JAVAC_BUILD_DIR",
                     getRoot().resolveAll("build", "test", "examplesJava11", "classes"))
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java b/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java
index 3598e51..1c65221 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestBuilder.java
@@ -4,8 +4,11 @@
 
 package com.android.tools.r8.keepanno;
 
+import static com.android.tools.r8.R8TestBuilder.KeepAnnotationLibrary.ANDROIDX;
 
 import com.android.tools.r8.ExternalR8TestBuilder;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
 import com.android.tools.r8.ProguardTestBuilder;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8PartialTestBuilder;
@@ -463,8 +466,15 @@
         TemporaryFolder temp)
         throws IOException {
       super(params);
+      KotlinCompiler kotlinc = new KotlinCompiler(KotlinCompilerVersion.MAX_SUPPORTED_VERSION);
       builder =
           TestBase.testForProguard(KeepAnnoTestUtils.PG_VERSION, temp)
+              .applyIf(
+                  keepAnnotationLibrary == ANDROIDX,
+                  b ->
+                      b.addDefaultRuntimeLibrary(parameters())
+                          .addLibraryFiles(
+                              kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar()))
               .addProgramFiles(KeepAnnoTestUtils.getKeepAnnoLib(temp, keepAnnotationLibrary))
               .setMinApi(parameters());
     }
diff --git a/src/test/testbase/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java b/src/test/testbase/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java
index 2fc4c98..53f0924 100644
--- a/src/test/testbase/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java
+++ b/src/test/testbase/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java
@@ -43,23 +43,25 @@
       TemporaryFolder temp, KeepAnnotationLibrary keepAnnotationLibrary) throws IOException {
     Path archive = temp.newFolder().toPath().resolve("keepanno.jar");
     ArchiveConsumer consumer = new ArchiveConsumer(archive);
+    // TODO(b/397387189): Find a better way to locate the keep annotation classes in tests.
     for (Path root : ToolHelper.getBuildPropKeepAnnoRuntimePath()) {
       String descriptorPrefix =
           (keepAnnotationLibrary == ANDROIDX ? DESCRIPTOR_PREFIX : DESCRIPTOR_LEGACY_PREFIX);
       Path annoDir = root.resolve(descriptorPrefix.substring(1, descriptorPrefix.length() - 1));
       assertTrue(Files.isDirectory(root));
-      assertTrue(Files.isDirectory(annoDir));
-      try (Stream<Path> paths = Files.list(annoDir)) {
-        paths.forEach(
-            p -> {
-              if (FileUtils.isClassFile(p)) {
-                byte[] data = FileUtils.uncheckedReadAllBytes(p);
-                String fileName = p.getFileName().toString();
-                String className = fileName.substring(0, fileName.lastIndexOf('.'));
-                String desc = descriptorPrefix + className + ";";
-                consumer.accept(ByteDataView.of(data), desc, null);
-              }
-            });
+      if (Files.isDirectory(annoDir)) {
+        try (Stream<Path> paths = Files.list(annoDir)) {
+          paths.forEach(
+              p -> {
+                if (FileUtils.isClassFile(p)) {
+                  byte[] data = FileUtils.uncheckedReadAllBytes(p);
+                  String fileName = p.getFileName().toString();
+                  String className = fileName.substring(0, fileName.lastIndexOf('.'));
+                  String desc = descriptorPrefix + className + ";";
+                  consumer.accept(ByteDataView.of(data), desc, null);
+                }
+              });
+        }
       }
     }
     consumer.finished(null);