Always create KmType for library types.

Also, for better inspection of R8-processed @Metadata, this CL expands
inspector subjects to KmPackage. Since KmPackage is just another
abstraction of KmDeclarationContainer, which is a super type of both
KmPackage (file-level container) and KmClass (obviously, class-level
container), many utils can be shared, e.g., retrieving class subjects
that appear at extension definitions. This CL also includes refactoring
about KmDeclarationContainer subject.

Bug: 147402444, 70169921
Change-Id: I539b09394c31bd90905fa07e8e0a0b0b3b434a7e
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
index 5f7843f..ef9419c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -55,10 +55,6 @@
       kmType.visitClass(descriptorToInternalName(convertedType.toDescriptorString()));
       return kmType;
     }
-    DexClass clazz = appView.definitionFor(type);
-    if (clazz == null) {
-      return null;
-    }
     // For library or classpath class, synthesize @Metadata always.
     // For a program class, make sure it is live.
     if (!appView.appInfo().isNonProgramTypeOrLiveProgramType(type)) {
@@ -66,7 +62,8 @@
     }
     DexType renamedType = lens.lookupType(type, appView.dexItemFactory());
     // For library or classpath class, we should not have renamed it.
-    assert clazz.isProgramClass() || renamedType == type
+    DexClass clazz = appView.definitionFor(type);
+    assert clazz == null || clazz.isProgramClass() || renamedType == type
         : type.toSourceString() + " -> " + renamedType.toSourceString();
     // TODO(b/70169921): Mysterious, why attempts to properly set flags bothers kotlinc?
     //   and/or why wiping out flags works for KmType but not KmFunction?!
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index e53fdce..9012ca4 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -94,6 +94,9 @@
       if (!enableTreeShaking) {
         command.add("-dontshrink");
       }
+      if (!enableOptimization) {
+        command.add("-dontoptimize");
+      }
       if (!enableMinification) {
         command.add("-dontobfuscate");
       }
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 84fc2ee..19c6edd 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -21,8 +21,9 @@
         T extends TestShrinkerBuilder<C, B, CR, RR, T>>
     extends TestCompilerBuilder<C, B, CR, RR, T> {
 
-  protected boolean enableMinification = true;
   protected boolean enableTreeShaking = true;
+  protected boolean enableOptimization = true;
+  protected boolean enableMinification = true;
 
   TestShrinkerBuilder(TestState state, B builder, Backend backend) {
     super(state, builder, backend);
@@ -37,6 +38,15 @@
     return treeShaking(false);
   }
 
+  public T optimization(boolean enable) {
+    enableOptimization = enable;
+    return self();
+  }
+
+  public T noOptimization() {
+    return optimization(false);
+  }
+
   public T minification(boolean enable) {
     enableMinification = enable;
     return self();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInLibraryTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInLibraryTypeTest.java
new file mode 100644
index 0000000..603dd6e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInLibraryTypeTest.java
@@ -0,0 +1,111 @@
+// 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmPackageSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MetadataRenameInLibraryTypeTest extends KotlinMetadataTestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataRenameInLibraryTypeTest(
+      TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Path baseLibJar;
+  private static Path extLibJar;
+  private static Path appJar;
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    String baseLibFolder = PKG_PREFIX + "/libtype_lib_base";
+    baseLibJar =
+        kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addSourceFiles(getKotlinFileInTest(baseLibFolder, "base"))
+            .compile();
+    String extLibFolder = PKG_PREFIX + "/libtype_lib_ext";
+    extLibJar =
+        kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addClasspathFiles(baseLibJar)
+            .addSourceFiles(getKotlinFileInTest(extLibFolder, "ext"))
+            .compile();
+    String appFolder = PKG_PREFIX + "/libtype_app";
+    appJar =
+        kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+            .addClasspathFiles(baseLibJar)
+            .addClasspathFiles(extLibJar)
+            .addSourceFiles(getKotlinFileInTest(appFolder, "main"))
+            .compile();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    String pkg = getClass().getPackage().getName();
+    String main = pkg + ".libtype_app.MainKt";
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            // Intentionally not providing basLibJar as lib file nor classpath file.
+            .addProgramFiles(extLibJar, appJar)
+            // Keep Ext extension method which requires metadata to be called with Kotlin syntax
+            // from other kotlin code.
+            .addKeepRules("-keep class **.ExtKt { <methods>; }")
+            // Keep the main entry.
+            .addKeepMainRule(main)
+            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .addOptionsModification(InternalOptions::enableKotlinMetadataRewriting)
+            // -dontoptimize so that basic code structure is kept.
+            .noOptimization()
+            .compile();
+    final String extClassName = pkg + ".libtype_lib_ext.ExtKt";
+    compileResult.inspect(inspector -> {
+      ClassSubject ext = inspector.clazz(extClassName);
+      assertThat(ext, isPresent());
+      assertThat(ext, not(isRenamed()));
+      // API entry is kept, hence the presence of Metadata.
+      KmPackageSubject kmPackage = ext.getKmPackage();
+      assertThat(kmPackage, isPresent());
+      // Type appearance of library type, Base, should be kept, even if it's not provided.
+      // Note that the resulting ClassSubject for Base is an absent one as we don't provide it, and
+      // thus we can't use `getReturnTypesInFunctions`, which filters out absent class subject.
+      assertTrue(kmPackage.getReturnTypeDescriptorsInFunctions().stream().anyMatch(
+          returnType -> returnType.contains("Base")));
+    });
+
+    Path out = compileResult.writeToZip();
+    testForJvm()
+        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), baseLibJar)
+        .addClasspath(out)
+        .run(parameters.getRuntime(), main)
+        .assertSuccessWithOutputLines("Sub::foo", "Sub::boo", "true");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_app/main.kt
new file mode 100644
index 0000000..a2d204a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_app/main.kt
@@ -0,0 +1,14 @@
+// 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.kotlin.metadata.libtype_app
+
+import com.android.tools.r8.kotlin.metadata.libtype_lib_base.Sub
+import com.android.tools.r8.kotlin.metadata.libtype_lib_ext.boo
+
+fun main() {
+  val s = Sub()
+  s.foo()
+  val b = s.boo()
+  println(s == b)
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_lib_base/base.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_lib_base/base.kt
new file mode 100644
index 0000000..0348987
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_lib_base/base.kt
@@ -0,0 +1,16 @@
+// 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.kotlin.metadata.libtype_lib_base
+
+open class Base {
+  open fun foo() {
+    println("Base::foo")
+  }
+}
+
+class Sub : Base() {
+  override fun foo() {
+    println("Sub::foo")
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_lib_ext/ext.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_lib_ext/ext.kt
new file mode 100644
index 0000000..81c924b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/libtype_lib_ext/ext.kt
@@ -0,0 +1,12 @@
+// 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.kotlin.metadata.libtype_lib_ext
+
+import com.android.tools.r8.kotlin.metadata.libtype_lib_base.Base
+import com.android.tools.r8.kotlin.metadata.libtype_lib_base.Sub
+
+fun Sub.boo(): Base {
+  println("Sub::boo")
+  return this
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index e665dcf..a471b18 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -142,4 +142,9 @@
   public KmClassSubject getKmClass() {
     return null;
   }
+
+  @Override
+  public KmPackageSubject getKmPackage() {
+    return null;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
index 201f644..2704774 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
@@ -4,8 +4,7 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.kotlin.Kotlin;
-import kotlinx.metadata.KmClass;
+import java.util.List;
 
 public class AbsentKmClassSubject extends KmClassSubject {
 
@@ -15,11 +14,6 @@
   }
 
   @Override
-  public KmClass getKmClass(Kotlin kotlin) {
-    return null;
-  }
-
-  @Override
   public boolean isPresent() {
     return false;
   }
@@ -33,4 +27,44 @@
   public boolean isSynthetic() {
     return false;
   }
+
+  @Override
+  public List<String> getParameterTypeDescriptorsInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<String> getReturnTypeDescriptorsInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<String> getReturnTypeDescriptorsInProperties() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getParameterTypesInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getReturnTypesInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getReturnTypesInProperties() {
+    return null;
+  }
+
+  @Override
+  public List<String> getSuperTypeDescriptors() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getSuperTypes() {
+    return null;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
new file mode 100644
index 0000000..6ea407a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
@@ -0,0 +1,54 @@
+// 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.utils.codeinspector;
+
+import java.util.List;
+
+public class AbsentKmPackageSubject extends KmPackageSubject {
+
+  @Override
+  public boolean isPresent() {
+    return false;
+  }
+
+  @Override
+  public boolean isRenamed() {
+    return false;
+  }
+
+  @Override
+  public boolean isSynthetic() {
+    return false;
+  }
+
+  @Override
+  public List<String> getParameterTypeDescriptorsInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<String> getReturnTypeDescriptorsInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<String> getReturnTypeDescriptorsInProperties() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getParameterTypesInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getReturnTypesInFunctions() {
+    return null;
+  }
+
+  @Override
+  public List<ClassSubject> getReturnTypesInProperties() {
+    return null;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index d7f09cb..d72d1a8 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -172,4 +172,6 @@
   public abstract String getFinalSignatureAttribute();
 
   public abstract KmClassSubject getKmClass();
+
+  public abstract KmPackageSubject getKmPackage();
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index adc0dbd..3e83c5d 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -345,4 +345,18 @@
     KotlinClassMetadata.Class kClass = (KotlinClassMetadata.Class) metadata;
     return new FoundKmClassSubject(codeInspector, getDexClass(), kClass.toKmClass());
   }
+
+  @Override
+  public KmPackageSubject getKmPackage() {
+    AnnotationSubject annotationSubject = annotation(METADATA_TYPE);
+    if (!annotationSubject.isPresent()) {
+      return new AbsentKmPackageSubject();
+    }
+    KotlinClassMetadata metadata =
+        KotlinClassMetadataReader.toKotlinClassMetadata(
+            codeInspector.getFactory().kotlin, annotationSubject.getAnnotation());
+    assertTrue(metadata instanceof KotlinClassMetadata.FileFacade);
+    KotlinClassMetadata.FileFacade kFile = (KotlinClassMetadata.FileFacade) metadata;
+    return new FoundKmPackageSubject(codeInspector, getDexClass(), kFile.toKmPackage());
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
index e4ce45d..e60f9f3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
@@ -3,20 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromKotlinClassifier;
-
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.Box;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 import kotlinx.metadata.KmClass;
-import kotlinx.metadata.KmType;
-import kotlinx.metadata.KmTypeVisitor;
+import kotlinx.metadata.KmDeclarationContainer;
 
-public class FoundKmClassSubject extends KmClassSubject {
+public class FoundKmClassSubject extends KmClassSubject
+    implements FoundKmDeclarationContainerSubject {
   private final CodeInspector codeInspector;
   private final DexClass clazz;
   private final KmClass kmClass;
@@ -33,7 +28,12 @@
   }
 
   @Override
-  public KmClass getKmClass(Kotlin kotlin) {
+  public CodeInspector codeInspector() {
+    return codeInspector;
+  }
+
+  @Override
+  public KmDeclarationContainer getKmDeclarationContainer() {
     return kmClass;
   }
 
@@ -54,26 +54,6 @@
     return false;
   }
 
-  // TODO(b/145824437): This is a dup of DescriptorUtils#getDescriptorFromKmType
-  private String getDescriptorFromKmType(KmType kmType) {
-    if (kmType == null) {
-      return null;
-    }
-    Box<String> descriptor = new Box<>(null);
-    kmType.accept(new KmTypeVisitor() {
-      @Override
-      public void visitClass(String name) {
-        descriptor.set(getDescriptorFromKotlinClassifier(name));
-      }
-
-      @Override
-      public void visitTypeAlias(String name) {
-        descriptor.set(getDescriptorFromKotlinClassifier(name));
-      }
-    });
-    return descriptor.get();
-  }
-
   @Override
   public List<String> getSuperTypeDescriptors() {
     return kmClass.getSupertypes().stream()
@@ -83,70 +63,10 @@
   }
 
   @Override
-  public List<String> getParameterTypeDescriptorsInFunctions() {
-    return kmClass.getFunctions().stream()
-        .flatMap(kmFunction ->
-            kmFunction.getValueParameters().stream()
-                .map(kmValueParameter -> getDescriptorFromKmType(kmValueParameter.getType()))
-                .filter(Objects::nonNull))
-        .collect(Collectors.toList());
-  }
-
-  @Override
-  public List<String> getReturnTypeDescriptorsInFunctions() {
-    return kmClass.getFunctions().stream()
-        .map(kmFunction -> getDescriptorFromKmType(kmFunction.getReturnType()))
-        .filter(Objects::nonNull)
-        .collect(Collectors.toList());
-  }
-
-  @Override
-  public List<String> getReturnTypeDescriptorsInProperties() {
-    return kmClass.getProperties().stream()
-        .map(kmProperty -> getDescriptorFromKmType(kmProperty.getReturnType()))
-        .filter(Objects::nonNull)
-        .collect(Collectors.toList());
-  }
-
-  private ClassSubject getClassSubjectFromKmType(KmType kmType) {
-    String descriptor = getDescriptorFromKmType(kmType);
-    if (descriptor == null) {
-      return new AbsentClassSubject();
-    }
-    return codeInspector.clazz(Reference.classFromDescriptor(descriptor));
-  }
-
-  @Override
   public List<ClassSubject> getSuperTypes() {
     return kmClass.getSupertypes().stream()
         .map(this::getClassSubjectFromKmType)
         .filter(ClassSubject::isPresent)
         .collect(Collectors.toList());
   }
-
-  @Override
-  public List<ClassSubject> getParameterTypesInFunctions() {
-    return kmClass.getFunctions().stream()
-        .flatMap(kmFunction ->
-            kmFunction.getValueParameters().stream()
-                .map(kmValueParameter -> getClassSubjectFromKmType(kmValueParameter.getType()))
-                .filter(ClassSubject::isPresent))
-        .collect(Collectors.toList());
-  }
-
-  @Override
-  public List<ClassSubject> getReturnTypesInFunctions() {
-    return kmClass.getFunctions().stream()
-        .map(kmFunction -> getClassSubjectFromKmType(kmFunction.getReturnType()))
-        .filter(ClassSubject::isPresent)
-        .collect(Collectors.toList());
-  }
-
-  @Override
-  public List<ClassSubject> getReturnTypesInProperties() {
-    return kmClass.getProperties().stream()
-        .map(kmProperty -> getClassSubjectFromKmType(kmProperty.getReturnType()))
-        .filter(ClassSubject::isPresent)
-        .collect(Collectors.toList());
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
new file mode 100644
index 0000000..45607ed
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
@@ -0,0 +1,101 @@
+// 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.utils.codeinspector;
+
+import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromKotlinClassifier;
+
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.Box;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import kotlinx.metadata.KmDeclarationContainer;
+import kotlinx.metadata.KmType;
+import kotlinx.metadata.KmTypeVisitor;
+
+public interface FoundKmDeclarationContainerSubject extends KmDeclarationContainerSubject {
+
+  CodeInspector codeInspector();
+  KmDeclarationContainer getKmDeclarationContainer();
+
+  // TODO(b/145824437): This is a dup of DescriptorUtils#getDescriptorFromKmType
+  default String getDescriptorFromKmType(KmType kmType) {
+    if (kmType == null) {
+      return null;
+    }
+    Box<String> descriptor = new Box<>(null);
+    kmType.accept(new KmTypeVisitor() {
+      @Override
+      public void visitClass(String name) {
+        descriptor.set(getDescriptorFromKotlinClassifier(name));
+      }
+
+      @Override
+      public void visitTypeAlias(String name) {
+        descriptor.set(getDescriptorFromKotlinClassifier(name));
+      }
+    });
+    return descriptor.get();
+  }
+
+  @Override
+  default List<String> getParameterTypeDescriptorsInFunctions() {
+    return getKmDeclarationContainer().getFunctions().stream()
+        .flatMap(kmFunction ->
+            kmFunction.getValueParameters().stream()
+                .map(kmValueParameter -> getDescriptorFromKmType(kmValueParameter.getType()))
+                .filter(Objects::nonNull))
+        .collect(Collectors.toList());
+  }
+
+  @Override
+  default List<String> getReturnTypeDescriptorsInFunctions() {
+    return getKmDeclarationContainer().getFunctions().stream()
+        .map(kmFunction -> getDescriptorFromKmType(kmFunction.getReturnType()))
+        .filter(Objects::nonNull)
+        .collect(Collectors.toList());
+  }
+
+  @Override
+  default List<String> getReturnTypeDescriptorsInProperties() {
+    return getKmDeclarationContainer().getProperties().stream()
+        .map(kmProperty -> getDescriptorFromKmType(kmProperty.getReturnType()))
+        .filter(Objects::nonNull)
+        .collect(Collectors.toList());
+  }
+
+  default ClassSubject getClassSubjectFromKmType(KmType kmType) {
+    String descriptor = getDescriptorFromKmType(kmType);
+    if (descriptor == null) {
+      return new AbsentClassSubject();
+    }
+    return codeInspector().clazz(Reference.classFromDescriptor(descriptor));
+  }
+
+  @Override
+  default List<ClassSubject> getParameterTypesInFunctions() {
+    return getKmDeclarationContainer().getFunctions().stream()
+        .flatMap(kmFunction ->
+            kmFunction.getValueParameters().stream()
+                .map(kmValueParameter -> getClassSubjectFromKmType(kmValueParameter.getType()))
+                .filter(ClassSubject::isPresent))
+        .collect(Collectors.toList());
+  }
+
+  @Override
+  default List<ClassSubject> getReturnTypesInFunctions() {
+    return getKmDeclarationContainer().getFunctions().stream()
+        .map(kmFunction -> getClassSubjectFromKmType(kmFunction.getReturnType()))
+        .filter(ClassSubject::isPresent)
+        .collect(Collectors.toList());
+  }
+
+  @Override
+  default List<ClassSubject> getReturnTypesInProperties() {
+    return getKmDeclarationContainer().getProperties().stream()
+        .map(kmProperty -> getClassSubjectFromKmType(kmProperty.getReturnType()))
+        .filter(ClassSubject::isPresent)
+        .collect(Collectors.toList());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPackageSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPackageSubject.java
new file mode 100644
index 0000000..8bc9459
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmPackageSubject.java
@@ -0,0 +1,48 @@
+// 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.utils.codeinspector;
+
+import com.android.tools.r8.graph.DexClass;
+import kotlinx.metadata.KmDeclarationContainer;
+import kotlinx.metadata.KmPackage;
+
+public class FoundKmPackageSubject extends KmPackageSubject
+    implements FoundKmDeclarationContainerSubject {
+  private final CodeInspector codeInspector;
+  private final DexClass clazz;
+  private final KmPackage kmPackage;
+
+  FoundKmPackageSubject(CodeInspector codeInspector, DexClass clazz, KmPackage kmPackage) {
+    this.codeInspector = codeInspector;
+    this.clazz = clazz;
+    this.kmPackage = kmPackage;
+  }
+
+  @Override
+  public CodeInspector codeInspector() {
+    return codeInspector;
+  }
+
+  @Override
+  public KmDeclarationContainer getKmDeclarationContainer() {
+    return kmPackage;
+  }
+
+  @Override
+  public boolean isPresent() {
+    return true;
+  }
+
+  @Override
+  public boolean isRenamed() {
+    return false;
+  }
+
+  @Override
+  public boolean isSynthetic() {
+    // TODO(b/70169921): This should return `true` conditionally if we start synthesizing @Metadata
+    //   from scratch.
+    return false;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
index aac5196..d36f233 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
@@ -4,43 +4,12 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.kotlin.Kotlin;
 import java.util.List;
-import kotlinx.metadata.KmClass;
 
-public abstract class KmClassSubject extends Subject {
+public abstract class KmClassSubject extends Subject implements KmDeclarationContainerSubject {
   public abstract DexClass getDexClass();
-  public abstract KmClass getKmClass(Kotlin kotlin);
 
-  public List<String> getSuperTypeDescriptors() {
-    return null;
-  }
+  public abstract List<String> getSuperTypeDescriptors();
 
-  public List<String> getParameterTypeDescriptorsInFunctions() {
-    return null;
-  }
-
-  public List<String> getReturnTypeDescriptorsInFunctions() {
-    return null;
-  }
-
-  public List<String> getReturnTypeDescriptorsInProperties() {
-    return null;
-  }
-
-  public List<ClassSubject> getSuperTypes() {
-    return null;
-  }
-
-  public List<ClassSubject> getParameterTypesInFunctions() {
-    return null;
-  }
-
-  public List<ClassSubject> getReturnTypesInFunctions() {
-    return null;
-  }
-
-  public List<ClassSubject> getReturnTypesInProperties() {
-    return null;
-  }
+  public abstract List<ClassSubject> getSuperTypes();
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
new file mode 100644
index 0000000..d553228
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
@@ -0,0 +1,20 @@
+// 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.utils.codeinspector;
+
+import java.util.List;
+
+public interface KmDeclarationContainerSubject {
+  List<String> getParameterTypeDescriptorsInFunctions();
+
+  List<String> getReturnTypeDescriptorsInFunctions();
+
+  List<String> getReturnTypeDescriptorsInProperties();
+
+  List<ClassSubject> getParameterTypesInFunctions();
+
+  List<ClassSubject> getReturnTypesInFunctions();
+
+  List<ClassSubject> getReturnTypesInProperties();
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmPackageSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmPackageSubject.java
new file mode 100644
index 0000000..8e00ce3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmPackageSubject.java
@@ -0,0 +1,7 @@
+// 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.utils.codeinspector;
+
+public abstract class KmPackageSubject extends Subject implements KmDeclarationContainerSubject {
+}