Towards synthesizing Kotlin @Metadata: functions.
Test: tools/test.py
Test: tools/run_on_as_app.py --app rover-android --shrinker r8
Test: tools/run_on_as_app.py --app tivi --shrinker r8
Test: tools/run_on_as_app.py --app Simple-Calendar --shrinker r8
Bug: 70169921
Change-Id: I51fd23357c288e77266cf57f037e6a68fc1fca3d
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index 98760b6..61def68 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -3,14 +3,20 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
import com.android.tools.r8.dex.Constants;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
+import kotlinx.metadata.Flag;
/** Access flags common to classes, methods and fields. */
public abstract class AccessFlags<T extends AccessFlags<T>> {
+ protected Flag[] EMPTY_FLAG = {};
+
protected static final int BASE_FLAGS
= Constants.ACC_PUBLIC
| Constants.ACC_PRIVATE
@@ -65,6 +71,26 @@
public abstract int getAsDexAccessFlags();
+ public int getAsKotlinFlags() {
+ List<Flag> flags = new ArrayList<>();
+ if (isPrivate()) {
+ flags.add(Flag.IS_PRIVATE);
+ }
+ if (isProtected()) {
+ flags.add(Flag.IS_PROTECTED);
+ }
+ if (isPublic()) {
+ flags.add(Flag.IS_PUBLIC);
+ }
+ if (isFinal()) {
+ flags.add(Flag.IS_FINAL);
+ }
+ if (isOpen()) {
+ flags.add(Flag.IS_OPEN);
+ }
+ return flagsOf(flags.toArray(EMPTY_FLAG));
+ }
+
public final int getOriginalAccessFlags() {
return originalFlags;
}
@@ -171,6 +197,10 @@
set(Constants.ACC_STATIC);
}
+ public boolean isOpen() {
+ return !isFinal();
+ }
+
public boolean isFinal() {
return isSet(Constants.ACC_FINAL);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
index 0c96120..030497d 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
@@ -3,10 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
import com.android.tools.r8.dex.Constants;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
+import kotlinx.metadata.Flag;
public class ClassAccessFlags extends AccessFlags<ClassAccessFlags> {
@@ -83,6 +87,11 @@
}
@Override
+ public int getAsCfAccessFlags() {
+ return materialize();
+ }
+
+ @Override
public int getAsDexAccessFlags() {
// We unset the super flag here, as it is meaningless in DEX. Furthermore, we add missing
// abstract to interfaces to work around a javac bug when generating package-info classes.
@@ -94,8 +103,25 @@
}
@Override
- public int getAsCfAccessFlags() {
- return materialize();
+ public int getAsKotlinFlags() {
+ int flag = super.getAsKotlinFlags();
+ List<Flag> flags = new ArrayList<>();
+ if (isAbstract()) {
+ flags.add(Flag.IS_ABSTRACT);
+ }
+ if (isClass()) {
+ flags.add(Flag.Class.IS_CLASS);
+ }
+ if (isInterface()) {
+ flags.add(Flag.Class.IS_INTERFACE);
+ }
+ if (isAnnotation()) {
+ flags.add(Flag.Class.IS_ANNOTATION_CLASS);
+ }
+ if (isEnum()) {
+ flags.add(Flag.Class.IS_ENUM_CLASS);
+ }
+ return flag | flagsOf(flags.toArray(EMPTY_FLAG));
}
/**
@@ -121,6 +147,10 @@
}
}
+ private boolean isClass() {
+ return !isInterface() && !isAnnotation() && !isEnum();
+ }
+
public boolean isInterface() {
return isSet(Constants.ACC_INTERFACE);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 358af04..2a87607 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -16,6 +16,7 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -26,6 +27,7 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import kotlinx.metadata.KmProperty;
public abstract class DexClass extends DexDefinition {
@@ -208,6 +210,16 @@
return Arrays.asList(virtualMethods);
}
+ public List<DexEncodedMethod> kotlinFunctions(List<KmProperty> kmProperties) {
+ List<DexEncodedMethod> functions = new ArrayList<>();
+ for (DexEncodedMethod method : virtualMethods) {
+ if (method.isKotlinFunction(kmProperties)) {
+ functions.add(method);
+ }
+ }
+ return functions;
+ }
+
public void appendVirtualMethod(DexEncodedMethod method) {
DexEncodedMethod[] newMethods = new DexEncodedMethod[virtualMethods.length + 1];
System.arraycopy(virtualMethods, 0, newMethods, 0, virtualMethods.length);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 7fe4555..b276b8b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -73,6 +73,7 @@
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.IntPredicate;
+import kotlinx.metadata.KmProperty;
import org.objectweb.asm.Opcodes;
public class DexEncodedMethod extends KeyedDexItem<DexMethod> {
@@ -348,6 +349,41 @@
return accessFlags.isSynthetic();
}
+ boolean isKotlinFunction(List<KmProperty> properties) {
+ return !isStaticMember() && !isKotlinProperty(properties);
+ }
+
+ // E.g., property `prop: T` is mapped to `getProp()T`, `setProp(T)V`, `prop$annotations()V`.
+ // TODO(b/70169921): Handle different name patterns via @JvmName.
+ boolean isKotlinProperty(List<KmProperty> properties) {
+ // TODO(b/70169921): Avoid decoding.
+ String methodName = method.name.toString();
+ if (!methodName.startsWith("get")
+ && !methodName.startsWith("set")
+ && !methodName.endsWith("$annotations")) {
+ return false;
+ }
+ for (KmProperty property : properties) {
+ String propertyName = property.getName();
+ assert propertyName.length() > 0;
+ String annotations = propertyName + "$annotations";
+ if (methodName.equals(annotations)) {
+ return true;
+ }
+ String capitalized =
+ Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
+ String getter = "get" + capitalized;
+ if (methodName.equals(getter)) {
+ return true;
+ }
+ String setter = "set" + capitalized;
+ if (methodName.equals(setter)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public boolean isOnlyInlinedIntoNestMembers() {
return compilationState == PROCESSED_INLINING_CANDIDATE_SAME_NEST;
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
index bb39765..ca16abe 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.errors.Unreachable;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.BooleanSupplier;
@@ -77,6 +78,11 @@
return materialize();
}
+ @Override
+ public int getAsKotlinFlags() {
+ throw new Unreachable("Kotlin property is not directly mapped to JVM field.");
+ }
+
public boolean isVolatile() {
return isSet(Constants.ACC_VOLATILE);
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
index 2173ed0..1b8e3a0 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
@@ -3,10 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
import com.android.tools.r8.dex.Constants;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
+import kotlinx.metadata.Flag;
public class MethodAccessFlags extends AccessFlags<MethodAccessFlags> {
@@ -92,6 +96,11 @@
}
@Override
+ public int getAsCfAccessFlags() {
+ return materialize() & ~Constants.ACC_CONSTRUCTOR;
+ }
+
+ @Override
public int getAsDexAccessFlags() {
MethodAccessFlags copy = copy();
if (copy.isSynchronized() && !copy.isNative()) {
@@ -102,8 +111,13 @@
}
@Override
- public int getAsCfAccessFlags() {
- return materialize() & ~Constants.ACC_CONSTRUCTOR;
+ public int getAsKotlinFlags() {
+ int flag = super.getAsKotlinFlags();
+ List<Flag> flags = new ArrayList<>();
+ if (isAbstract()) {
+ flags.add(Flag.IS_ABSTRACT);
+ }
+ return flag | flagsOf(flags.toArray(EMPTY_FLAG));
}
public boolean isSynchronized() {
diff --git a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
index 73ab96a..1b34adf 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -11,8 +11,10 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -37,12 +39,30 @@
public final Intrinsics intrinsics;
public final Metadata metadata;
+ final Map<DexType, DexType> knownTypeConversion;
+
public Kotlin(DexItemFactory factory) {
this.factory = factory;
this.functional = new Functional();
this.intrinsics = new Intrinsics();
this.metadata = new Metadata();
+
+ this.knownTypeConversion =
+ ImmutableMap.<DexType, DexType>builder()
+ // https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/index.html
+ .put(factory.booleanType, factory.createType(addKotlinPrefix("Boolean;")))
+ .put(factory.byteType, factory.createType(addKotlinPrefix("Byte;")))
+ .put(factory.charType, factory.createType(addKotlinPrefix("Character;")))
+ .put(factory.shortType, factory.createType(addKotlinPrefix("Short;")))
+ .put(factory.intType, factory.createType(addKotlinPrefix("Int;")))
+ .put(factory.longType, factory.createType(addKotlinPrefix("Long;")))
+ .put(factory.floatType, factory.createType(addKotlinPrefix("Float;")))
+ .put(factory.doubleType, factory.createType(addKotlinPrefix("Double;")))
+ .put(factory.voidType, factory.createType(addKotlinPrefix("Unit;")))
+ .put(factory.stringType, factory.createType(addKotlinPrefix("String;")))
+ // TODO(b/70169921): Collections?
+ .build();
}
public final class Functional {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
index 9f77f7a..e76bbcf 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
@@ -4,15 +4,21 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.kotlin.Kotlin.addKotlinPrefix;
+import static com.android.tools.r8.kotlin.KotlinMetadataSynthesizer.toKmType;
+import static com.android.tools.r8.kotlin.KotlinMetadataSynthesizer.toRenamedKmFunction;
import static com.android.tools.r8.kotlin.KotlinMetadataSynthesizer.toRenamedKmType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.List;
import kotlinx.metadata.KmClass;
+import kotlinx.metadata.KmFunction;
+import kotlinx.metadata.KmProperty;
import kotlinx.metadata.KmType;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata;
@@ -50,9 +56,23 @@
}
}
assert clazz.superType != null;
- KmType kmTypeForSupertype = toRenamedKmType(clazz.superType, appView, lens);
- if (kmTypeForSupertype != null) {
- superTypes.add(kmTypeForSupertype);
+ if (clazz.superType != appView.dexItemFactory().objectType) {
+ KmType kmTypeForSupertype = toRenamedKmType(clazz.superType, appView, lens);
+ if (kmTypeForSupertype != null) {
+ superTypes.add(kmTypeForSupertype);
+ }
+ } else if (clazz.isInterface()) {
+ superTypes.add(toKmType(addKotlinPrefix("Any;")));
+ }
+
+ List<KmFunction> functions = kmClass.getFunctions();
+ functions.clear();
+ List<KmProperty> properties = kmClass.getProperties();
+ for (DexEncodedMethod method : clazz.kotlinFunctions(properties)) {
+ KmFunction kmFunction = toRenamedKmFunction(method.method, appView, lens);
+ if (kmFunction != null) {
+ functions.add(kmFunction);
+ }
}
}
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 4400273..0e195e7 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -3,17 +3,44 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.kotlin.Kotlin.addKotlinPrefix;
+import static com.android.tools.r8.utils.DescriptorUtils.descriptorToInternalName;
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.DescriptorUtils;
+import java.util.List;
+import kotlinx.metadata.KmFunction;
import kotlinx.metadata.KmType;
+import kotlinx.metadata.KmValueParameter;
class KotlinMetadataSynthesizer {
+ static KmType toKmType(String descriptor) {
+ KmType kmType = new KmType(flagsOf());
+ kmType.visitClass(descriptorToInternalName(descriptor));
+ return kmType;
+ }
+
static KmType toRenamedKmType(
DexType type, AppView<AppInfoWithLiveness> appView, NamingLens lens) {
+ // E.g., [Ljava/lang/String; -> Lkotlin/Array;
+ if (type.isArrayType()) {
+ return toKmType(addKotlinPrefix("Array;"));
+ }
+ // E.g., void -> Lkotlin/Unit;
+ if (appView.dexItemFactory().kotlin.knownTypeConversion.containsKey(type)) {
+ KmType kmType = new KmType(flagsOf());
+ DexType convertedType = appView.dexItemFactory().kotlin.knownTypeConversion.get(type);
+ assert convertedType != null;
+ kmType.visitClass(descriptorToInternalName(convertedType.toDescriptorString()));
+ return kmType;
+ }
DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
return null;
@@ -27,9 +54,48 @@
// For library or classpath class, we should not have renamed it.
assert clazz.isProgramClass() || renamedType == type
: type.toSourceString() + " -> " + renamedType.toSourceString();
- // TODO(b/70169921): Consult kotlinx.metadata.Flag for kotlin-specific flags (e.g., sealed).
- KmType kmType = new KmType(clazz.accessFlags.getAsCfAccessFlags());
- kmType.visitClass(DescriptorUtils.descriptorToInternalName(renamedType.toDescriptorString()));
+ // TODO(b/70169921): Mysterious, why attempts to properly set flags bothers kotlinc?
+ // and/or why wiping out flags works for KmType but not KmFunction?!
+ KmType kmType = new KmType(flagsOf());
+ kmType.visitClass(descriptorToInternalName(renamedType.toDescriptorString()));
return kmType;
}
+
+ static KmFunction toRenamedKmFunction(
+ DexMethod method, AppView<AppInfoWithLiveness> appView, NamingLens lens) {
+ DexEncodedMethod encodedMethod = appView.definitionFor(method);
+ if (encodedMethod == null) {
+ return null;
+ }
+ // For library overrides, synthesize @Metadata always.
+ // For regular methods, make sure it is live.
+ if (!encodedMethod.isLibraryMethodOverride().isTrue()
+ && !appView.appInfo().liveMethods.contains(method)) {
+ return null;
+ }
+ DexMethod renamedMethod = lens.lookupMethod(method, appView.dexItemFactory());
+ // For a library method override, we should not have renamed it.
+ assert !encodedMethod.isLibraryMethodOverride().isTrue() || renamedMethod == method
+ : method.toSourceString() + " -> " + renamedMethod.toSourceString();
+ // TODO(b/70169921): Consult kotlinx.metadata.Flag.Function for kind (e.g., suspend).
+ KmFunction kmFunction =
+ new KmFunction(encodedMethod.accessFlags.getAsKotlinFlags(), renamedMethod.name.toString());
+ KmType kmReturnType = toRenamedKmType(method.proto.returnType, appView, lens);
+ assert kmReturnType != null;
+ kmFunction.setReturnType(kmReturnType);
+ List<KmValueParameter> parameters = kmFunction.getValueParameters();
+ for (int i = 0; i < method.proto.parameters.values.length; i++) {
+ DexType paramType = method.proto.parameters.values[i];
+ DebugLocalInfo debugLocalInfo = encodedMethod.getParameterInfo().get(i);
+ String parameterName =
+ debugLocalInfo != null ? debugLocalInfo.name.toString() : ("p" + i);
+ // TODO(b/70169921): Consult kotlinx.metadata.Flag.ValueParameter.
+ KmValueParameter kmValueParameter = new KmValueParameter(flagsOf(), parameterName);
+ KmType kmParamType = toRenamedKmType(paramType, appView, lens);
+ assert kmParamType != null;
+ kmValueParameter.setType(kmParamType);
+ parameters.add(kmValueParameter);
+ }
+ return kmFunction;
+ }
}
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
index 3fedef1..b470bb6 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
@@ -6,16 +6,14 @@
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.assertNotEquals;
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.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
@@ -85,26 +83,25 @@
supertype -> supertype.getFinalDescriptor().contains("Itf")));
assertTrue(superTypes.stream().anyMatch(
supertype -> supertype.getFinalDescriptor().equals(itf.getFinalDescriptor())));
- // TODO(b/70169921): should not refer to Itf
List<ClassSubject> parameterTypes = kmClass.getParameterTypesInFunctions();
assertTrue(parameterTypes.stream().anyMatch(
- parameterType -> parameterType.getOriginalDescriptor().contains("Itf")));
+ parameterType -> parameterType.getFinalDescriptor().equals(itf.getFinalDescriptor())));
});
Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/parametertype_app";
- ProcessResult processResult =
+ Path output =
kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(appFolder, "main"))
.setOutputPath(temp.newFolder().toPath())
- // TODO(b/70169921): update to just .compile() once fixed.
- .compileRaw();
- // TODO(b/70169921): should be able to compile!
- assertNotEquals(0, processResult.exitCode);
- assertThat(
- processResult.stderr,
- containsString("cannot access class '" + pkg + ".parametertype_lib.Itf'"));
+ .compile();
+
+ testForJvm()
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addClasspath(output)
+ .run(parameters.getRuntime(), pkg + ".parametertype_app.MainKt")
+ .assertSuccessWithOutputLines("Impl::bar", "Program::bar");
}
}
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
index e7efcae..bcf2181 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
@@ -6,16 +6,14 @@
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.assertNotEquals;
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.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
@@ -84,27 +82,26 @@
supertype -> supertype.getFinalDescriptor().contains("Itf")));
assertTrue(superTypes.stream().anyMatch(
supertype -> supertype.getFinalDescriptor().equals(itf.getFinalDescriptor())));
- // TODO(b/70169921): should not refer to Itf
List<ClassSubject> functionReturnTypes = kmClass.getReturnTypesInFunctions();
assertTrue(functionReturnTypes.stream().anyMatch(
- returnType -> returnType.getOriginalDescriptor().contains("Itf")));
+ returnType -> returnType.getFinalDescriptor().equals(itf.getFinalDescriptor())));
});
Path libJar = compileResult.writeToZip();
String appFolder = PKG_PREFIX + "/returntype_app";
- ProcessResult processResult =
+ Path output =
kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(appFolder, "main"))
.setOutputPath(temp.newFolder().toPath())
- // TODO(b/70169921): update to just .compile() once fixed.
- .compileRaw();
- // TODO(b/70169921): should be able to compile!
- assertNotEquals(0, processResult.exitCode);
- assertThat(
- processResult.stderr,
- containsString("cannot access class '" + pkg + ".returntype_lib.Itf'"));
+ .compile();
+
+ testForJvm()
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addClasspath(output)
+ .run(parameters.getRuntime(), pkg + ".returntype_app.MainKt")
+ .assertSuccessWithOutputLines("Impl::foo", "Program::foo", "true");
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_app/main.kt
index 3c1585a..83caed2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_app/main.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_app/main.kt
@@ -4,8 +4,8 @@
package com.android.tools.r8.kotlin.metadata.classpath_app
import com.android.tools.r8.kotlin.metadata.classpath_lib_ext.Extra
-import com.android.tools.r8.kotlin.metadata.classpath_lib_ext.extension
+import com.android.tools.r8.kotlin.metadata.classpath_lib_ext.fooExt
fun main() {
- Extra().extension()
-}
\ No newline at end of file
+ Extra().fooExt()
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_lib_ext/impl.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_lib_ext/impl.kt
index 975865b..501c583 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_lib_ext/impl.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/classpath_lib_ext/impl.kt
@@ -13,6 +13,6 @@
class Extra : Impl()
-fun Extra.extension() {
+fun Extra.fooExt() {
foo()
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/returntype_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/returntype_app/main.kt
index 37d446e..fd4ce90 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/returntype_app/main.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/returntype_app/main.kt
@@ -4,10 +4,9 @@
package com.android.tools.r8.kotlin.metadata.returntype_app
import com.android.tools.r8.kotlin.metadata.returntype_lib.Impl
-import com.android.tools.r8.kotlin.metadata.returntype_lib.Itf
class ProgramClass : Impl() {
- override fun foo(): Itf {
+ override fun foo(): Impl {
super.foo()
println("Program::foo")
return this