Trace kotlin.Metadata annotations in trace references

Fixes: b/409260720
Change-Id: I60f4c126007494a4361451625dae9a330a438d97
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index 018c084..09f0679 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.utils.StringDiagnostic;
 import java.util.IdentityHashMap;
 import java.util.Map;
+import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 import kotlin.Metadata;
@@ -39,7 +40,7 @@
       AppView<?> appView,
       DexClass clazz,
       Consumer<DexEncodedMethod> keepByteCode,
-      Supplier<Boolean> reportUnknownMetadata) {
+      BooleanSupplier reportUnknownMetadata) {
     DexAnnotation meta =
         clazz.annotations().getFirstMatching(appView.dexItemFactory().kotlinMetadataType);
     if (meta == null) {
@@ -53,11 +54,11 @@
       DexClass clazz,
       DexAnnotation meta,
       Consumer<DexEncodedMethod> keepByteCode,
-      Supplier<Boolean> reportUnknownMetadata) {
+      BooleanSupplier reportUnknownMetadata) {
     try {
       return getKotlinInfo(appView, clazz, keepByteCode, meta);
     } catch (KotlinMetadataException e) {
-      if (reportUnknownMetadata.get()) {
+      if (reportUnknownMetadata.getAsBoolean()) {
         appView.reporter().warning(KotlinMetadataDiagnostic.unknownMetadataVersion());
       }
       appView
@@ -70,7 +71,7 @@
                       + e.getMessage()));
       return getInvalidKotlinInfo();
     } catch (Throwable e) {
-      if (reportUnknownMetadata.get()) {
+      if (reportUnknownMetadata.getAsBoolean()) {
         appView.reporter().warning(KotlinMetadataDiagnostic.unknownMetadataVersion());
       }
       appView
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index ae75ef0..874e219 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -176,13 +176,17 @@
     if (metadata == null) {
       return;
     }
+    // In D8 of R8 partial the kotlin.Metadata annotations have already been read during trace
+    // references.
     KotlinClassLevelInfo kotlinInfo =
-        KotlinClassMetadataReader.getKotlinInfoFromAnnotation(
-            appView,
-            clazz,
-            metadata,
-            ConsumerUtils.emptyConsumer(),
-            reportedUnknownMetadataVersion::getAndSet);
+        appView.options().partialSubCompilationConfiguration != null
+            ? clazz.getKotlinInfo()
+            : KotlinClassMetadataReader.getKotlinInfoFromAnnotation(
+                appView,
+                clazz,
+                metadata,
+                ConsumerUtils.emptyConsumer(),
+                reportedUnknownMetadataVersion::getAndSet);
     if (kotlinInfo == getNoKotlinInfo()) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
index 257ff73..0a4f712 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.tracereferences;
 
+import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
+
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.diagnostic.DefinitionContext;
 import com.android.tools.r8.diagnostic.internal.DefinitionContextUtils;
@@ -38,6 +40,9 @@
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.graph.lens.MethodLookupResult;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
+import com.android.tools.r8.kotlin.KotlinClassMetadataReader;
+import com.android.tools.r8.kotlin.KotlinMetadataUseRegistry;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
@@ -53,6 +58,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -106,6 +112,28 @@
     for (DexAnnotation annotation : clazz.annotations().getAnnotations()) {
       registerAnnotation(annotation, clazz, classContext);
     }
+    traceKotlinMetadata(clazz, classContext);
+  }
+
+  private void traceKotlinMetadata(DexProgramClass clazz, DefinitionContext classContext) {
+    if (parseKotlinMetadata(clazz)) {
+      KotlinMetadataUseRegistry registry = type -> addType(type, classContext);
+      clazz.getKotlinInfo().trace(registry);
+      clazz.forEachProgramMember(member -> member.getDefinition().getKotlinInfo().trace(registry));
+    }
+  }
+
+  private boolean parseKotlinMetadata(DexProgramClass clazz) {
+    DexAnnotation metadata = clazz.annotations().getFirstMatching(factory.kotlinMetadataType);
+    if (metadata == null) {
+      return false;
+    }
+    BooleanSupplier reportUnknownMetadata = () -> false;
+    KotlinClassLevelInfo kotlinInfo =
+        KotlinClassMetadataReader.getKotlinInfoFromAnnotation(
+            appView, clazz, metadata, emptyConsumer(), reportUnknownMetadata);
+    clazz.setKotlinInfo(kotlinInfo);
+    return true;
   }
 
   protected void notifyPresentClass(DexClass clazz, DefinitionContext referencedFrom) {
diff --git a/src/test/java/com/android/tools/r8/partial/kotlin/PartialCompilationKotlinMetadataTest.java b/src/test/java/com/android/tools/r8/partial/kotlin/PartialCompilationKotlinMetadataTest.java
index 356ff33..272905c 100644
--- a/src/test/java/com/android/tools/r8/partial/kotlin/PartialCompilationKotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/partial/kotlin/PartialCompilationKotlinMetadataTest.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.partial.kotlin;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -88,7 +87,7 @@
     assertThat(message1Class, isPresent());
 
     ClassSubject message2Class = inspector.clazz(MESSAGE2_NAME);
-    assertThat(message2Class, isAbsent());
+    assertThat(message2Class, isPresent());
 
     ClassSubject greetingClass = inspector.clazz(GREETING_NAME);
     assertThat(greetingClass, isPresent());
@@ -96,11 +95,11 @@
     assertNotNull(kotlinClassMetadata);
     String metadata = KotlinMetadataWriter.kotlinMetadataToString("", kotlinClassMetadata);
     assertThat(metadata, containsString(greetingClass.getFinalBinaryName()));
-    // TODO(b/409260720): Message2 should be referenced.
     assertThat(metadata, containsString(message1Class.getFinalBinaryName()));
+    assertThat(metadata, containsString(message2Class.getFinalBinaryName()));
   }
 
-  private static KotlinCompileMemoizer compiledJars =
+  private static final KotlinCompileMemoizer compiledJars =
       getCompileMemoizer(
           Paths.get(
               ToolHelper.TESTS_DIR,