Add support for inspecting Kotlin metadata.
Bug: 70169921, 145824437
Change-Id: I5a94c4e4783bb47a58614f229481ec759025ca69
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 88c8181..c05b48f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueArray;
@@ -30,7 +31,7 @@
DexAnnotation meta = clazz.annotations.getFirstMatching(kotlin.metadata.kotlinMetadataType);
if (meta != null) {
try {
- return createKotlinInfo(kotlin, clazz, meta);
+ return createKotlinInfo(kotlin, clazz, meta.annotation);
} catch (ClassCastException | InconsistentKotlinMetadataException | MetadataError e) {
reporter.info(
new StringDiagnostic("Class " + clazz.type.toSourceString()
@@ -44,12 +45,10 @@
return null;
}
- private static KotlinInfo createKotlinInfo(
- Kotlin kotlin,
- DexClass clazz,
- DexAnnotation meta) {
+ private static KotlinClassMetadata toKotlinClassMetadata(
+ Kotlin kotlin, DexEncodedAnnotation metadataAnnotation) {
Map<DexString, DexAnnotationElement> elementMap = new IdentityHashMap<>();
- for (DexAnnotationElement element : meta.annotation.elements) {
+ for (DexAnnotationElement element : metadataAnnotation.elements) {
elementMap.put(element.name, element);
}
@@ -74,7 +73,12 @@
Integer xi = extraInt == null ? null : (Integer) extraInt.value.getBoxedValue();
KotlinClassHeader header = new KotlinClassHeader(k, mv, bv, d1, d2, xs, pn, xi);
- KotlinClassMetadata kMetadata = KotlinClassMetadata.read(header);
+ return KotlinClassMetadata.read(header);
+ }
+
+ private static KotlinInfo createKotlinInfo(
+ Kotlin kotlin, DexClass clazz, DexEncodedAnnotation metadataAnnotation) {
+ KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, metadataAnnotation);
if (kMetadata instanceof KotlinClassMetadata.Class) {
return KotlinClass.fromKotlinClassMetadata(kMetadata, clazz);
@@ -87,7 +91,7 @@
} else if (kMetadata instanceof KotlinClassMetadata.SyntheticClass) {
return KotlinSyntheticClass.fromKotlinClassMetadata(kMetadata, kotlin, clazz);
} else {
- throw new MetadataError("unsupported 'k' value: " + k);
+ throw new MetadataError("unsupported 'k' value: " + kMetadata.getHeader().getKind());
}
}
@@ -129,5 +133,4 @@
super(cause);
}
}
-
}
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index 87f946c..a470bb3 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -4,8 +4,7 @@
package com.android.tools.r8;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.graph.DexAnnotation;
-import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -17,7 +16,9 @@
+ "java.lang.Object, java.lang.String)";
protected static final String throwParameterIsNotNullExceptionSignature =
"void kotlin.jvm.internal.Intrinsics.throwParameterIsNullException(java.lang.String)";
- protected static final String METADATA_DESCRIPTOR = "Lkotlin/Metadata;";
+ public static final String METADATA_DESCRIPTOR = "Lkotlin/Metadata;";
+ public static final String METADATA_TYPE =
+ DescriptorUtils.descriptorToJavaType(METADATA_DESCRIPTOR);
private static final String RSRC = "kotlinR8TestResources";
@@ -48,13 +49,4 @@
protected Path getMappingfile(String folder, String mappingFileName) {
return Paths.get(ToolHelper.TESTS_DIR, RSRC, folder, mappingFileName);
}
-
- protected DexAnnotation retrieveMetadata(DexClass dexClass) {
- for (DexAnnotation annotation : dexClass.annotations.annotations) {
- if (annotation.annotation.type.toDescriptorString().equals(METADATA_DESCRIPTOR)) {
- return annotation;
- }
- }
- return null;
- }
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index b561f2f..00d991a 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -219,6 +219,11 @@
return KotlinCompilerTool.create(jdk, temp, kotlinCompiler, kotlinTargetVersion);
}
+ public static KotlinCompilerTool kotlinc(
+ KotlinCompiler kotlinCompiler, KotlinTargetVersion kotlinTargetVersion) {
+ return kotlinc(TestRuntime.getCheckedInJdk9(), staticTemp, kotlinCompiler, kotlinTargetVersion);
+ }
+
public KotlinCompilerTool kotlinc(
CfRuntime jdk, KotlinCompiler kotlinCompiler, KotlinTargetVersion kotlinTargetVersion) {
return KotlinCompilerTool.create(jdk, temp, kotlinCompiler, kotlinTargetVersion);
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index a3ec1a2..880eac4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -62,6 +62,11 @@
return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
}
+ // Some tests defined in subclasses, e.g., Metadata tests, don't care about access relaxation.
+ protected AbstractR8KotlinTestBase(KotlinTargetVersion kotlinTargetVersion) {
+ this(kotlinTargetVersion, false);
+ }
+
protected AbstractR8KotlinTestBase(
KotlinTargetVersion kotlinTargetVersion, boolean allowAccessModification) {
super(kotlinTargetVersion);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
index cdb5538..d866cca 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
@@ -3,11 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.DescriptorUtils;
-abstract class KotlinMetadataTestBase extends KotlinTestBase {
+abstract class KotlinMetadataTestBase extends AbstractR8KotlinTestBase {
KotlinMetadataTestBase(KotlinTargetVersion targetVersion) {
super(targetVersion);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInExtensionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInExtensionTest.java
index e256e37..640b18b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInExtensionTest.java
@@ -9,20 +9,20 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
+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.ToolHelper.ProcessResult;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,15 +50,10 @@
@BeforeClass
public static void createLibJar() throws Exception {
String extLibFolder = PKG_PREFIX + "/extension_lib";
- extLibJar = getStaticTemp().newFile("ext_lib.jar").toPath();
- ProcessResult processResult =
- ToolHelper.runKotlinc(
- null,
- extLibJar,
- null,
- getKotlinFileInTest(extLibFolder, "B")
- );
- assertEquals(0, processResult.exitCode);
+ extLibJar =
+ kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addSourceFiles(getKotlinFileInTest(extLibFolder, "B"))
+ .compile();
}
@Test
@@ -85,18 +80,19 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
- assertThat(metadata.toString(), not(containsString("Super")));
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Super")));
});
- Path r8ProcessedLibZip = temp.newFile("r8-lib.zip").toPath();
- compileResult.writeToZip(r8ProcessedLibZip);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/extension_app";
ProcessResult kotlinTestCompileResult =
kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
- .addClasspathFiles(r8ProcessedLibZip)
+ .addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(appFolder, "main"))
.setOutputPath(temp.newFolder().toPath())
// TODO(b/143687784): update to just .compile() once fixed.
@@ -133,13 +129,16 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
- assertThat(metadata.toString(), not(containsString("Super")));
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Super")));
+ assertTrue(superTypes.stream().anyMatch(
+ supertype -> supertype.getFinalDescriptor().equals(sup.getFinalDescriptor())));
});
- Path libJar = temp.newFile("lib.jar").toPath();
- compileResult.writeToZip(libJar);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/extension_app";
Path output =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInParametertypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInParameterTypeTest.java
similarity index 71%
rename from src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInParametertypeTest.java
rename to src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInParameterTypeTest.java
index 1030339..3fedef1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInParametertypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInParameterTypeTest.java
@@ -9,27 +9,26 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
+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.ToolHelper.ProcessResult;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class MetadataRenameInParametertypeTest extends KotlinMetadataTestBase {
+public class MetadataRenameInParameterTypeTest extends KotlinMetadataTestBase {
private final TestParameters parameters;
@@ -39,33 +38,28 @@
getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
}
- public MetadataRenameInParametertypeTest(
+ public MetadataRenameInParameterTypeTest(
TestParameters parameters, KotlinTargetVersion targetVersion) {
super(targetVersion);
this.parameters = parameters;
}
- private static Path parameterLibJar;
+ private static Path parameterTypeLibJar;
@BeforeClass
public static void createLibJar() throws Exception {
- String paramLibFolder = PKG_PREFIX + "/parametertype_lib";
- parameterLibJar = getStaticTemp().newFile("param_lib.jar").toPath();
- ProcessResult processResult =
- ToolHelper.runKotlinc(
- null,
- parameterLibJar,
- null,
- getKotlinFileInTest(paramLibFolder, "lib")
- );
- assertEquals(0, processResult.exitCode);
+ String parameterTypeLibFolder = PKG_PREFIX + "/parametertype_lib";
+ parameterTypeLibJar =
+ kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addSourceFiles(getKotlinFileInTest(parameterTypeLibFolder, "lib"))
+ .compile();
}
@Test
- public void testMetadataInParameter_renamed() throws Exception {
+ public void testMetadataInParameterType_renamed() throws Exception {
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(parameterLibJar)
+ .addProgramFiles(parameterTypeLibJar)
// Keep non-private members of Impl
.addKeepRules("-keep public class **.Impl { !private *; }")
// Keep Itf, but allow minification.
@@ -84,14 +78,20 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Itf")));
+ assertTrue(superTypes.stream().anyMatch(
+ supertype -> supertype.getFinalDescriptor().equals(itf.getFinalDescriptor())));
// TODO(b/70169921): should not refer to Itf
- assertThat(metadata.toString(), containsString("Itf"));
+ List<ClassSubject> parameterTypes = kmClass.getParameterTypesInFunctions();
+ assertTrue(parameterTypes.stream().anyMatch(
+ parameterType -> parameterType.getOriginalDescriptor().contains("Itf")));
});
- Path libJar = temp.newFile("lib.jar").toPath();
- compileResult.writeToZip(libJar);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/parametertype_app";
ProcessResult processResult =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInPropertyTypeTest.java
similarity index 71%
rename from src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInPropertyTest.java
rename to src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInPropertyTypeTest.java
index fe815d0..2e92333 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInPropertyTypeTest.java
@@ -9,27 +9,26 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
+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.ToolHelper.ProcessResult;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class MetadataRenameInPropertyTest extends KotlinMetadataTestBase {
+public class MetadataRenameInPropertyTypeTest extends KotlinMetadataTestBase {
private final TestParameters parameters;
@@ -39,33 +38,28 @@
getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
}
- public MetadataRenameInPropertyTest(
+ public MetadataRenameInPropertyTypeTest(
TestParameters parameters, KotlinTargetVersion targetVersion) {
super(targetVersion);
this.parameters = parameters;
}
- private static Path propertyLibJar;
+ private static Path propertyTypeLibJar;
@BeforeClass
public static void createLibJar() throws Exception {
- String propertyLibFolder = PKG_PREFIX + "/propertytype_lib";
- propertyLibJar = getStaticTemp().newFile("property_lib.jar").toPath();
- ProcessResult processResult =
- ToolHelper.runKotlinc(
- null,
- propertyLibJar,
- null,
- getKotlinFileInTest(propertyLibFolder, "lib")
- );
- assertEquals(0, processResult.exitCode);
+ String propertyTypeLibFolder = PKG_PREFIX + "/propertytype_lib";
+ propertyTypeLibJar =
+ kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addSourceFiles(getKotlinFileInTest(propertyTypeLibFolder, "lib"))
+ .compile();
}
@Test
public void testMetadataInProperty_renamed() throws Exception {
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(propertyLibJar)
+ .addProgramFiles(propertyTypeLibJar)
// Keep non-private members of Impl
.addKeepRules("-keep public class **.Impl { !private *; }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
@@ -82,14 +76,20 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Itf")));
+ assertTrue(superTypes.stream().anyMatch(
+ supertype -> supertype.getFinalDescriptor().equals(itf.getFinalDescriptor())));
// TODO(b/70169921): should not refer to Itf
- assertThat(metadata.toString(), containsString("Itf"));
+ List<ClassSubject> propertyReturnTypes = kmClass.getReturnTypesInProperties();
+ assertTrue(propertyReturnTypes.stream().anyMatch(
+ propertyType -> propertyType.getOriginalDescriptor().contains("Itf")));
});
- Path libJar = temp.newFile("lib.jar").toPath();
- compileResult.writeToZip(libJar);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/propertytype_app";
ProcessResult processResult =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInReturntypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInReturnTypeTest.java
similarity index 72%
rename from src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInReturntypeTest.java
rename to src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInReturnTypeTest.java
index da6bf76..e7efcae 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInReturntypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInReturnTypeTest.java
@@ -9,27 +9,26 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
+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.ToolHelper.ProcessResult;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class MetadataRenameInReturntypeTest extends KotlinMetadataTestBase {
+public class MetadataRenameInReturnTypeTest extends KotlinMetadataTestBase {
private final TestParameters parameters;
@Parameterized.Parameters(name = "{0} target: {1}")
@@ -38,33 +37,28 @@
getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
}
- public MetadataRenameInReturntypeTest(
+ public MetadataRenameInReturnTypeTest(
TestParameters parameters, KotlinTargetVersion targetVersion) {
super(targetVersion);
this.parameters = parameters;
}
- private static Path returntypeLibJar;
+ private static Path returnTypeLibJar;
@BeforeClass
public static void createLibJar() throws Exception {
- String returntypeLibFolder = PKG_PREFIX + "/returntype_lib";
- returntypeLibJar = getStaticTemp().newFile("returntype_lib.jar").toPath();
- ProcessResult processResult =
- ToolHelper.runKotlinc(
- null,
- returntypeLibJar,
- null,
- getKotlinFileInTest(returntypeLibFolder, "lib")
- );
- assertEquals(0, processResult.exitCode);
+ String returnTypeLibFolder = PKG_PREFIX + "/returntype_lib";
+ returnTypeLibJar =
+ kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addSourceFiles(getKotlinFileInTest(returnTypeLibFolder, "lib"))
+ .compile();
}
@Test
- public void testmetadataInReturnType_renamed() throws Exception {
+ public void testMetadataInReturnType_renamed() throws Exception {
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(returntypeLibJar)
+ .addProgramFiles(returnTypeLibJar)
// Keep non-private members of Impl
.addKeepRules("-keep public class **.Impl { !private *; }")
// Keep Itf, but allow minification.
@@ -83,14 +77,20 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Itf")));
+ assertTrue(superTypes.stream().anyMatch(
+ supertype -> supertype.getFinalDescriptor().equals(itf.getFinalDescriptor())));
// TODO(b/70169921): should not refer to Itf
- assertThat(metadata.toString(), containsString("Itf"));
+ List<ClassSubject> functionReturnTypes = kmClass.getReturnTypesInFunctions();
+ assertTrue(functionReturnTypes.stream().anyMatch(
+ returnType -> returnType.getOriginalDescriptor().contains("Itf")));
});
- Path libJar = temp.newFile("lib.jar").toPath();
- compileResult.writeToZip(libJar);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/returntype_app";
ProcessResult processResult =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInSupertypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInSuperTypeTest.java
similarity index 72%
rename from src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInSupertypeTest.java
rename to src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInSuperTypeTest.java
index dc29f2c..4ad8e97 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInSupertypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRenameInSuperTypeTest.java
@@ -6,29 +6,27 @@
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.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+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.ToolHelper.ProcessResult;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class MetadataRenameInSupertypeTest extends KotlinMetadataTestBase {
+public class MetadataRenameInSuperTypeTest extends KotlinMetadataTestBase {
private final TestParameters parameters;
@@ -38,34 +36,30 @@
getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
}
- public MetadataRenameInSupertypeTest(
+ public MetadataRenameInSuperTypeTest(
TestParameters parameters, KotlinTargetVersion targetVersion) {
super(targetVersion);
this.parameters = parameters;
}
- private static Path supertypeLibJar;
+ private static Path superTypeLibJar;
@BeforeClass
public static void createLibJar() throws Exception {
- String supertypeLibFolder = PKG_PREFIX + "/supertype_lib";
- supertypeLibJar = getStaticTemp().newFile("supertype_lib.jar").toPath();
- ProcessResult processResult =
- ToolHelper.runKotlinc(
- null,
- supertypeLibJar,
- null,
- getKotlinFileInTest(supertypeLibFolder, "impl"),
- getKotlinFileInTest(supertypeLibFolder + "/internal", "itf")
- );
- assertEquals(0, processResult.exitCode);
+ String superTypeLibFolder = PKG_PREFIX + "/supertype_lib";
+ superTypeLibJar =
+ kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
+ .addSourceFiles(
+ getKotlinFileInTest(superTypeLibFolder, "impl"),
+ getKotlinFileInTest(superTypeLibFolder + "/internal", "itf"))
+ .compile();
}
@Test
public void b143687784_merged() throws Exception {
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(supertypeLibJar)
+ .addProgramFiles(superTypeLibJar)
// Keep non-private members except for ones in `internal` definitions.
.addKeepRules("-keep public class !**.internal.**, * { !private *; }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
@@ -81,25 +75,27 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
- assertThat(metadata.toString(), not(containsString("internal")));
- assertThat(metadata.toString(), not(containsString("Itf")));
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("internal")));
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Itf")));
});
- Path r8ProcessedLibZip = temp.newFile("r8-lib.zip").toPath();
- compileResult.writeToZip(r8ProcessedLibZip);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/supertype_app";
Path output =
kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
- .addClasspathFiles(r8ProcessedLibZip)
+ .addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(appFolder, "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), r8ProcessedLibZip)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), pkg + ".supertype_app.MainKt")
.assertSuccessWithOutputLines("Impl::foo", "Program::foo");
@@ -109,7 +105,7 @@
public void b143687784_renamed() throws Exception {
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(supertypeLibJar)
+ .addProgramFiles(superTypeLibJar)
// Keep non-private members except for ones in `internal` definitions.
.addKeepRules("-keep public class !**.internal.**, * { !private *; }")
// Keep `internal` definitions, but allow minification.
@@ -128,15 +124,18 @@
assertThat(impl, isPresent());
assertThat(impl, not(isRenamed()));
// API entry is kept, hence the presence of Metadata.
- DexAnnotation metadata = retrieveMetadata(impl.getDexClass());
- assertNotNull(metadata);
- assertThat(metadata.toString(), not(containsString("internal")));
- assertThat(metadata.toString(), not(containsString("Itf")));
- assertThat(metadata.toString(), containsString("a/a"));
+ KmClassSubject kmClass = impl.getKmClass();
+ assertThat(kmClass, isPresent());
+ List<ClassSubject> superTypes = kmClass.getSuperTypes();
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("internal")));
+ assertTrue(superTypes.stream().noneMatch(
+ supertype -> supertype.getFinalDescriptor().contains("Itf")));
+ assertTrue(superTypes.stream().anyMatch(
+ supertype -> supertype.getFinalDescriptor().equals(itf.getFinalDescriptor())));
});
- Path libJar = temp.newFile("lib.jar").toPath();
- compileResult.writeToZip(libJar);
+ Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/supertype_app";
Path output =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index 00b5606..35dd597 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -7,8 +7,6 @@
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.assertNotNull;
-import static org.junit.Assert.assertNull;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.R8TestRunResult;
@@ -16,6 +14,7 @@
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.codeinspector.AnnotationSubject;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.util.Collection;
@@ -61,11 +60,12 @@
assertThat(clazz, isPresent());
assertThat(clazz, not(isRenamed()));
// Main class is kept, hence the presence of Metadata.
- assertNotNull(retrieveMetadata(clazz.getDexClass()));
+ AnnotationSubject annotationSubject = clazz.annotation(METADATA_TYPE);
+ assertThat(annotationSubject, isPresent());
ClassSubject impl1 = inspector.clazz(implementer1ClassName);
assertThat(impl1, isPresent());
assertThat(impl1, isRenamed());
// All other classes can be renamed, hence the absence of Metadata;
- assertNull(retrieveMetadata(impl1.getDexClass()));
+ assertThat(impl1.annotation(METADATA_TYPE), not(isPresent()));
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/extension_lib/B.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/extension_lib/B.kt
index a6fe9ab..df51d42 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/extension_lib/B.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/extension_lib/B.kt
@@ -13,7 +13,7 @@
}
}
-class B : Super() { }
+class B : Super()
fun B.extension() {
doStuff()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/supertype_lib/internal/itf.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/supertype_lib/internal/itf.kt
index 50e18d4..7fff074 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/supertype_lib/internal/itf.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/supertype_lib/internal/itf.kt
@@ -4,5 +4,5 @@
package com.android.tools.r8.kotlin.metadata.supertype_lib.internal
interface Itf {
- fun foo();
+ fun foo()
}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
index f62e21b..f618e93 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesTest.java
@@ -97,7 +97,7 @@
localVariableTable.get(0),
0,
"this",
- classSubject.asFoundClassSubject().asTypeSybject(),
+ classSubject.asFoundClassSubject().asTypeSubject(),
null);
checkLocalVariable(
localVariableTable.get(1), 1, "parameter1", inspector.getTypeSubject("int"), null);
@@ -121,7 +121,7 @@
localVariableTable.get(0),
0,
"this",
- classSubject.asFoundClassSubject().asTypeSybject(),
+ classSubject.asFoundClassSubject().asTypeSubject(),
null);
checkLocalVariable(
localVariableTable.get(1), 1, "parameter1", inspector.getTypeSubject("long"), null);
@@ -141,7 +141,7 @@
localVariableTable.get(0),
0,
"this",
- classSubject.asFoundClassSubject().asTypeSybject(),
+ classSubject.asFoundClassSubject().asTypeSubject(),
null);
checkLocalVariable(
localVariableTable.get(1),
diff --git a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesUnsortedLocalVariablesTableTest.java b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesUnsortedLocalVariablesTableTest.java
index d858322..c92d7e7 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesUnsortedLocalVariablesTableTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepparameternames/KeepParameterNamesUnsortedLocalVariablesTableTest.java
@@ -73,7 +73,7 @@
localVariableTable.get(0),
0,
"this",
- classSubject.asFoundClassSubject().asTypeSybject(),
+ classSubject.asFoundClassSubject().asTypeSubject(),
null);
checkLocalVariable(
localVariableTable.get(1), 1, "parameter1", inspector.getTypeSubject("int"), null);
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 8e2f554..e665dcf 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
@@ -137,4 +137,9 @@
public String getFinalSignatureAttribute() {
return null;
}
+
+ @Override
+ public KmClassSubject getKmClass() {
+ 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
new file mode 100644
index 0000000..201f644
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmClassSubject.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.kotlin.Kotlin;
+import kotlinx.metadata.KmClass;
+
+public class AbsentKmClassSubject extends KmClassSubject {
+
+ @Override
+ public DexClass getDexClass() {
+ return null;
+ }
+
+ @Override
+ public KmClass getKmClass(Kotlin kotlin) {
+ return null;
+ }
+
+ @Override
+ public boolean isPresent() {
+ return false;
+ }
+
+ @Override
+ public boolean isRenamed() {
+ return false;
+ }
+
+ @Override
+ public boolean isSynthetic() {
+ return false;
+ }
+}
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 8b8f519..705337c 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
@@ -166,4 +166,6 @@
public abstract String getOriginalSignatureAttribute();
public abstract String getFinalSignatureAttribute();
+
+ public abstract KmClassSubject getKmClass();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
index 0a53c91..a97f040 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
@@ -12,7 +12,7 @@
private final DexAnnotation annotation;
- public FoundAnnotationSubject(DexAnnotation annotation) {
+ FoundAnnotationSubject(DexAnnotation annotation) {
this.annotation = annotation;
}
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 45276f4..adc0dbd 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
@@ -4,6 +4,9 @@
package com.android.tools.r8.utils.codeinspector;
+import static com.android.tools.r8.KotlinTestBase.METADATA_TYPE;
+import static org.junit.Assert.assertTrue;
+
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
@@ -23,6 +26,7 @@
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import java.util.function.Consumer;
+import kotlinx.metadata.jvm.KotlinClassMetadata;
public class FoundClassSubject extends ClassSubject {
@@ -324,7 +328,21 @@
return dexClass.toSourceString();
}
- public TypeSubject asTypeSybject() {
+ public TypeSubject asTypeSubject() {
return new TypeSubject(codeInspector, getDexClass().type);
}
+
+ @Override
+ public KmClassSubject getKmClass() {
+ AnnotationSubject annotationSubject = annotation(METADATA_TYPE);
+ if (!annotationSubject.isPresent()) {
+ return new AbsentKmClassSubject();
+ }
+ KotlinClassMetadata metadata =
+ KotlinClassMetadataReader.toKotlinClassMetadata(
+ codeInspector.getFactory().kotlin, annotationSubject.getAnnotation());
+ assertTrue(metadata instanceof KotlinClassMetadata.Class);
+ KotlinClassMetadata.Class kClass = (KotlinClassMetadata.Class) metadata;
+ return new FoundKmClassSubject(codeInspector, getDexClass(), kClass.toKmClass());
+ }
}
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
new file mode 100644
index 0000000..358a016
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmClassSubject.java
@@ -0,0 +1,145 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.kotlin.Kotlin;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.Box;
+import com.android.tools.r8.utils.DescriptorUtils;
+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;
+
+public class FoundKmClassSubject extends KmClassSubject {
+ private final CodeInspector codeInspector;
+ private final DexClass clazz;
+ private final KmClass kmClass;
+
+ FoundKmClassSubject(CodeInspector codeInspector, DexClass clazz, KmClass kmClass) {
+ this.codeInspector = codeInspector;
+ this.clazz = clazz;
+ this.kmClass = kmClass;
+ }
+
+ @Override
+ public DexClass getDexClass() {
+ return clazz;
+ }
+
+ @Override
+ public KmClass getKmClass(Kotlin kotlin) {
+ return kmClass;
+ }
+
+ @Override
+ public boolean isPresent() {
+ return true;
+ }
+
+ @Override
+ public boolean isRenamed() {
+ return !clazz.type.getInternalName().equals(kmClass.name);
+ }
+
+ @Override
+ public boolean isSynthetic() {
+ // TODO(b/70169921): This should return `true` conditionally if we start synthesizing @Metadata
+ // from scratch.
+ return false;
+ }
+
+ 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(DescriptorUtils.getDescriptorFromKotlinClassifier(name));
+ }
+ });
+ return descriptor.get();
+ }
+
+ @Override
+ public List<String> getSuperTypeDescriptors() {
+ return kmClass.getSupertypes().stream()
+ .map(this::getDescriptorFromKmType)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ @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/KmClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
new file mode 100644
index 0000000..aac5196
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassSubject.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.kotlin.Kotlin;
+import java.util.List;
+import kotlinx.metadata.KmClass;
+
+public abstract class KmClassSubject extends Subject {
+ public abstract DexClass getDexClass();
+ public abstract KmClass getKmClass(Kotlin kotlin);
+
+ public List<String> getSuperTypeDescriptors() {
+ return null;
+ }
+
+ 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;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KotlinClassMetadataReader.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KotlinClassMetadataReader.java
new file mode 100644
index 0000000..b3a0143
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KotlinClassMetadataReader.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, 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.DexAnnotationElement;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexValueArray;
+import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.kotlin.Kotlin;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import kotlinx.metadata.jvm.KotlinClassHeader;
+import kotlinx.metadata.jvm.KotlinClassMetadata;
+
+// TODO(b/145824437): This is a dup of the same class in source to avoid the error while building
+// keep rules for r8lib. Should be able to avoid this redundancy at build configuration level or
+// change -printusage to apply mappings regarding relocated deps.
+class KotlinClassMetadataReader {
+ static KotlinClassMetadata toKotlinClassMetadata(
+ Kotlin kotlin, DexEncodedAnnotation metadataAnnotation) {
+ Map<DexString, DexAnnotationElement> elementMap = new IdentityHashMap<>();
+ for (DexAnnotationElement element : metadataAnnotation.elements) {
+ elementMap.put(element.name, element);
+ }
+
+ DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
+ if (kind == null) {
+ throw new MetadataError("element 'k' is missing.");
+ }
+ Integer k = (Integer) kind.value.getBoxedValue();
+ DexAnnotationElement metadataVersion = elementMap.get(kotlin.metadata.metadataVersion);
+ int[] mv = metadataVersion == null ? null : getUnboxedIntArray(metadataVersion.value, "mv");
+ DexAnnotationElement bytecodeVersion = elementMap.get(kotlin.metadata.bytecodeVersion);
+ int[] bv = bytecodeVersion == null ? null : getUnboxedIntArray(bytecodeVersion.value, "bv");
+ DexAnnotationElement data1 = elementMap.get(kotlin.metadata.data1);
+ String[] d1 = data1 == null ? null : getUnboxedStringArray(data1.value, "d1");
+ DexAnnotationElement data2 = elementMap.get(kotlin.metadata.data2);
+ String[] d2 = data2 == null ? null : getUnboxedStringArray(data2.value, "d2");
+ DexAnnotationElement extraString = elementMap.get(kotlin.metadata.extraString);
+ String xs = extraString == null ? null : getUnboxedString(extraString.value, "xs");
+ DexAnnotationElement packageName = elementMap.get(kotlin.metadata.packageName);
+ String pn = packageName == null ? null : getUnboxedString(packageName.value, "pn");
+ DexAnnotationElement extraInt = elementMap.get(kotlin.metadata.extraInt);
+ Integer xi = extraInt == null ? null : (Integer) extraInt.value.getBoxedValue();
+
+ KotlinClassHeader header = new KotlinClassHeader(k, mv, bv, d1, d2, xs, pn, xi);
+ return KotlinClassMetadata.read(header);
+ }
+
+ private static int[] getUnboxedIntArray(DexValue v, String elementName) {
+ if (!(v instanceof DexValueArray)) {
+ throw new MetadataError("invalid '" + elementName + "' value: " + v.toSourceString());
+ }
+ DexValueArray intArrayValue = (DexValueArray) v;
+ DexValue[] values = intArrayValue.getValues();
+ int[] result = new int [values.length];
+ for (int i = 0; i < values.length; i++) {
+ result[i] = (Integer) values[i].getBoxedValue();
+ }
+ return result;
+ }
+
+ private static String[] getUnboxedStringArray(DexValue v, String elementName) {
+ if (!(v instanceof DexValueArray)) {
+ throw new MetadataError("invalid '" + elementName + "' value: " + v.toSourceString());
+ }
+ DexValueArray stringArrayValue = (DexValueArray) v;
+ DexValue[] values = stringArrayValue.getValues();
+ String[] result = new String [values.length];
+ for (int i = 0; i < values.length; i++) {
+ result[i] = getUnboxedString(values[i], elementName + "[" + i + "]");
+ }
+ return result;
+ }
+
+ private static String getUnboxedString(DexValue v, String elementName) {
+ if (!(v instanceof DexValueString)) {
+ throw new MetadataError("invalid '" + elementName + "' value: " + v.toSourceString());
+ }
+ return ((DexValueString) v).getValue().toString();
+ }
+
+ private static class MetadataError extends RuntimeException {
+ MetadataError(String cause) {
+ super(cause);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
index 1fd4abe..d9f11d6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -57,6 +57,10 @@
type = "method";
} else if (subject instanceof FieldSubject) {
type = "field";
+ } else if (subject instanceof AnnotationSubject) {
+ type = "annotation";
+ } else if (subject instanceof KmClassSubject) {
+ type = "@Metadata.KmClass";
}
return type;
}
@@ -69,6 +73,10 @@
name = ((MethodSubject) subject).getOriginalName();
} else if (subject instanceof FieldSubject) {
name = ((FieldSubject) subject).getOriginalName();
+ } else if (subject instanceof AnnotationSubject) {
+ name = ((AnnotationSubject) subject).getAnnotation().type.toSourceString();
+ } else if (subject instanceof KmClassSubject) {
+ name = ((KmClassSubject) subject).getDexClass().toSourceString();
}
return name;
}