Rewrite expanded and underlying type for Kotlin type-aliases
Bug: 151194785
Change-Id: I1926288c7a3d9ad3fa4a9d5fd8d26308180a91fd
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
index fa1ce28..3b4d284 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -306,7 +306,6 @@
}
}
-
public static class ClassTypeSignature extends FieldTypeSignature {
static final ClassTypeSignature UNKNOWN_CLASS_TYPE_SIGNATURE =
new ClassTypeSignature(DexItemFactory.nullValueType, ImmutableList.of());
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 2495016..b4308b9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -42,7 +42,7 @@
public static final class ClassClassifiers {
- public static final String arrayDescriptor = NAME + "/Array";
+ public static final String arrayBinaryName = NAME + "/Array";
}
// Mappings from JVM types to Kotlin types (of type DexType)
@@ -62,6 +62,7 @@
// https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/index.html
// Boxed primitives and arrays
.put(factory.booleanType, factory.createType(addKotlinPrefix("Boolean;")))
+ .put(factory.boxedBooleanType, factory.createType(addKotlinPrefix("Boolean;")))
.put(factory.booleanArrayType, factory.createType(addKotlinPrefix("BooleanArray;")))
.put(factory.byteType, factory.createType(addKotlinPrefix("Byte;")))
.put(factory.byteArrayType, factory.createType(addKotlinPrefix("ByteArray;")))
@@ -70,6 +71,7 @@
.put(factory.shortType, factory.createType(addKotlinPrefix("Short;")))
.put(factory.shortArrayType, factory.createType(addKotlinPrefix("ShortArray;")))
.put(factory.intType, factory.createType(addKotlinPrefix("Int;")))
+ .put(factory.boxedIntType, factory.createType(addKotlinPrefix("Int;")))
.put(factory.intArrayType, factory.createType(addKotlinPrefix("IntArray;")))
.put(factory.longType, factory.createType(addKotlinPrefix("Long;")))
.put(factory.longArrayType, factory.createType(addKotlinPrefix("LongArray;")))
@@ -101,13 +103,17 @@
factory.createType(addKotlinPrefix("collections/ListIterator;")))
.put(factory.iterableType, factory.createType(addKotlinPrefix("collections/Iterable;")))
.put(
- factory.mapEntryType,
- factory.createType(addKotlinPrefix("collections/Map$Entry;")))
+ factory.mapEntryType, factory.createType(addKotlinPrefix("collections/Map$Entry;")))
// .../jvm/functions/FunctionN -> .../FunctionN
.putAll(
- IntStream.rangeClosed(0, 22).boxed().collect(Collectors.toMap(
- i -> factory.createType(addKotlinPrefix("jvm/functions/Function" + i + ";")),
- i -> factory.createType(addKotlinPrefix("Function" + i + ";")))))
+ IntStream.rangeClosed(0, 22)
+ .boxed()
+ .collect(
+ Collectors.toMap(
+ i ->
+ factory.createType(
+ addKotlinPrefix("jvm/functions/Function" + i + ";")),
+ i -> factory.createType(addKotlinPrefix("Function" + i + ";")))))
.build();
}
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 f8bd449..db37d8c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClass.java
@@ -147,7 +147,7 @@
if (!method.isInstanceInitializer()) {
continue;
}
- KmConstructor constructor = synthesizer.toRenamedKmConstructor(method);
+ KmConstructor constructor = synthesizer.toRenamedKmConstructor(clazz, method);
if (constructor != null) {
constructors.add(constructor);
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
index ee07b83..e516ff9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinInfo.java
@@ -18,10 +18,12 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Action;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
@@ -146,6 +148,7 @@
KmDeclarationContainer kmDeclarationContainer = getDeclarations();
rewriteFunctions(synthesizer, kmDeclarationContainer.getFunctions());
rewriteProperties(synthesizer, kmDeclarationContainer.getProperties());
+ rewriteTypeAliases(synthesizer, kmDeclarationContainer.getTypeAliases());
}
private void rewriteFunctions(KotlinMetadataSynthesizer synthesizer, List<KmFunction> functions) {
@@ -164,6 +167,37 @@
}
}
+ private void rewriteTypeAliases(
+ KotlinMetadataSynthesizer synthesizer, List<KmTypeAlias> typeAliases) {
+ Iterator<KmTypeAlias> iterator = typeAliases.iterator();
+ while (iterator.hasNext()) {
+ KmTypeAlias typeAlias = iterator.next();
+ KotlinTypeInfo expandedRenamed =
+ KotlinTypeInfo.create(typeAlias.expandedType).toRenamed(synthesizer);
+ if (expandedRenamed == null) {
+ // If the expanded type is pruned, the type-alias is also removed. Type-aliases can refer to
+ // other type-aliases in the underlying type, however, we only remove a type-alias when the
+ // expanded type is removed making it impossible to construct any type that references the
+ // type-alias anyway.
+ // TODO(b/151719926): Add a test for the above.
+ iterator.remove();
+ continue;
+ }
+ typeAlias.setExpandedType(expandedRenamed.asKmType());
+ // Modify the underlying type (right-hand side) of the type-alias.
+ KotlinTypeInfo underlyingRenamed =
+ KotlinTypeInfo.create(typeAlias.underlyingType).toRenamed(synthesizer);
+ if (underlyingRenamed == null) {
+ Reporter reporter = synthesizer.appView.options().reporter;
+ reporter.warning(
+ KotlinMetadataDiagnostic.messageInvalidUnderlyingType(clazz, typeAlias.getName()));
+ iterator.remove();
+ continue;
+ }
+ typeAlias.setUnderlyingType(underlyingRenamed.asKmType());
+ }
+ }
+
private void rewriteProperties(
KotlinMetadataSynthesizer synthesizer, List<KmProperty> properties) {
Map<String, KmPropertyGroup.Builder> propertyGroupBuilderMap = new HashMap<>();
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
new file mode 100644
index 0000000..da33940
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataDiagnostic.java
@@ -0,0 +1,49 @@
+// 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;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+public class KotlinMetadataDiagnostic implements Diagnostic {
+
+ private final Origin origin;
+ private final Position position;
+ private final String message;
+
+ public KotlinMetadataDiagnostic(Origin origin, Position position, String message) {
+ this.origin = origin;
+ this.position = position;
+ this.message = message;
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public Position getPosition() {
+ return position;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ return message;
+ }
+
+ static KotlinMetadataDiagnostic messageInvalidUnderlyingType(DexClass clazz, String typeAlias) {
+ return new KotlinMetadataDiagnostic(
+ clazz.getOrigin(),
+ Position.UNKNOWN,
+ "The type alias "
+ + typeAlias
+ + " in class "
+ + clazz.type.getName()
+ + " has an invalid underlying type. The type-alias is removed from the output.");
+ }
+}
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 81984d1..65d7f7e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizer.java
@@ -28,8 +28,10 @@
import com.android.tools.r8.graph.GenericSignature.FormalTypeParameter;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.GenericSignature.TypeSignature;
+import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.kotlin.KotlinMemberInfo.KotlinFunctionInfo;
import com.android.tools.r8.kotlin.KotlinMemberInfo.KotlinPropertyInfo;
+import com.android.tools.r8.kotlin.KotlinMetadataSynthesizerUtils.AddKotlinAnyType;
import com.android.tools.r8.kotlin.KotlinMetadataSynthesizerUtils.KmVisitorOption;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -37,6 +39,7 @@
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.Consumer;
+import kotlinx.metadata.KmClassifier;
import kotlinx.metadata.KmConstructor;
import kotlinx.metadata.KmFunction;
import kotlinx.metadata.KmProperty;
@@ -49,8 +52,8 @@
class KotlinMetadataSynthesizer {
- private final AppView<AppInfoWithLiveness> appView;
- private final NamingLens lens;
+ final AppView<AppInfoWithLiveness> appView;
+ final NamingLens lens;
private final List<KmTypeParameter> classTypeParameters;
public KotlinMetadataSynthesizer(
@@ -120,7 +123,6 @@
}
private KmType toRenamedKmTypeWithClassifierForFieldSignature(
- DexType type,
KotlinTypeInfo originalTypeInfo,
FieldTypeSignature fieldSignature,
List<KmTypeParameter> typeParameters) {
@@ -135,7 +137,8 @@
return value;
},
typeParameters,
- appView.dexItemFactory());
+ appView.dexItemFactory(),
+ AddKotlinAnyType.ADD);
return kmTypeBox.get();
}
@@ -147,7 +150,7 @@
if (typeSignature != null && typeSignature.isFieldTypeSignature()) {
KmType renamedKmType =
toRenamedKmTypeWithClassifierForFieldSignature(
- type, originalTypeInfo, typeSignature.asFieldTypeSignature(), typeParameters);
+ originalTypeInfo, typeSignature.asFieldTypeSignature(), typeParameters);
if (renamedKmType != null) {
return renamedKmType;
}
@@ -173,7 +176,7 @@
return renamedKmType;
}
- KmConstructor toRenamedKmConstructor(DexEncodedMethod method) {
+ KmConstructor toRenamedKmConstructor(DexClass clazz, DexEncodedMethod method) {
// Make sure it is an instance initializer and live.
if (!method.isInstanceInitializer()
|| !appView.appInfo().liveMethods.contains(method.method)) {
@@ -204,6 +207,52 @@
if (!populateKmValueParameters(method, signature, parameters, typeParameters)) {
return null;
}
+ // For inner, non-static classes, the type-parameter for the receiver should not have a
+ // value-parameter:
+ // val myInner : OuterNestedInner = nested.Inner(1)
+ // Will have value-parameters for the constructor:
+ // # constructors: KmConstructor[
+ // # KmConstructor{
+ // # flags: 6,
+ // # valueParameters: KmValueParameter[
+ // # KmValueParameter{
+ // # flags: 0,
+ // # name: x,
+ // # type: KmType{
+ // # flags: 0,
+ // # classifier: Class(name=kotlin/Int),
+ // # arguments: KmTypeProjection[],
+ // # abbreviatedType: null,
+ // # outerType: null,
+ // # raw: false,
+ // # annotations: KmAnnotion[],
+ // # },
+ // # varargElementType: null,
+ // # }
+ // # ],
+ // # signature: <init>(Lcom/android/tools/r8/kotlin/metadata/typealias_lib/Outer$Nested;I)V,
+ // # }
+ // # ],
+ // A bit weird since the signature obviously have two value-parameters.
+ List<InnerClassAttribute> innerClasses = clazz.getInnerClasses();
+ if (!parameters.isEmpty() && !innerClasses.isEmpty()) {
+ DexType immediateOuterType = null;
+ for (InnerClassAttribute innerClass : innerClasses) {
+ if (innerClass.getInner() == clazz.type) {
+ immediateOuterType = innerClass.getOuter();
+ break;
+ }
+ }
+ if (immediateOuterType != null) {
+ String classifier = toRenamedClassifier(immediateOuterType);
+ KmType potentialReceiver = parameters.get(0).getType();
+ if (potentialReceiver != null
+ && potentialReceiver.classifier instanceof KmClassifier.Class
+ && ((KmClassifier.Class) potentialReceiver.classifier).getName().equals(classifier)) {
+ parameters.remove(0);
+ }
+ }
+ }
return kmConstructor;
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
index c7c118c..67fb7da 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataSynthesizerUtils.java
@@ -33,26 +33,37 @@
VISIT_PARENT
}
+ // The AddKotlinAnyType is carrying around information regarding the need for adding the trivial
+ // type Kotlin/Any. The information is not consistently added, for example, for upper bounds
+ // the trivial bound is not recorded.
+ public enum AddKotlinAnyType {
+ ADD,
+ DISREGARD
+ }
+
static void populateKmTypeFromSignature(
FieldTypeSignature typeSignature,
KotlinTypeInfo originalTypeInfo,
Function<KmVisitorOption, KmTypeVisitor> typeVisitor,
List<KmTypeParameter> allTypeParameters,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ AddKotlinAnyType addAny) {
if (typeSignature.isClassTypeSignature()) {
populateKmTypeFromClassTypeSignature(
typeSignature.asClassTypeSignature(),
originalTypeInfo,
typeVisitor,
allTypeParameters,
- factory);
+ factory,
+ addAny);
} else if (typeSignature.isArrayTypeSignature()) {
populateKmTypeFromArrayTypeSignature(
typeSignature.asArrayTypeSignature(),
originalTypeInfo,
typeVisitor,
allTypeParameters,
- factory);
+ factory,
+ addAny);
} else if (typeSignature.isTypeVariableSignature()) {
populateKmTypeFromTypeVariableSignature(
typeSignature.asTypeVariableSignature(), typeVisitor, allTypeParameters);
@@ -81,13 +92,14 @@
KotlinTypeInfo originalTypeInfo,
Function<KmVisitorOption, KmTypeVisitor> typeVisitor,
List<KmTypeParameter> allTypeParameters,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ AddKotlinAnyType addAny) {
ArrayTypeSignature arrayTypeSignature = typeSignature.asArrayTypeSignature();
if (!arrayTypeSignature.elementSignature().isFieldTypeSignature()) {
return;
}
KmTypeVisitor kmType = typeVisitor.apply(KmVisitorOption.VISIT_NEW);
- kmType.visitClass(ClassClassifiers.arrayDescriptor);
+ kmType.visitClass(ClassClassifiers.arrayBinaryName);
KotlinTypeProjectionInfo projectionInfo =
originalTypeInfo == null ? null : originalTypeInfo.getArgumentOrNull(0);
populateKmTypeFromSignature(
@@ -104,7 +116,8 @@
}
},
allTypeParameters,
- factory);
+ factory,
+ addAny);
}
private static void populateKmTypeFromClassTypeSignature(
@@ -112,9 +125,10 @@
KotlinTypeInfo originalTypeInfo,
Function<KmVisitorOption, KmTypeVisitor> typeVisitor,
List<KmTypeParameter> allTypeParameters,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ AddKotlinAnyType addAny) {
// No need to record the trivial argument.
- if (factory.objectType == typeSignature.type()) {
+ if (addAny == AddKotlinAnyType.DISREGARD && factory.objectType == typeSignature.type()) {
return;
}
KmTypeVisitor kmType = typeVisitor.apply(KmVisitorOption.VISIT_NEW);
@@ -137,7 +151,8 @@
}
},
allTypeParameters,
- factory);
+ factory,
+ addAny);
}
}
@@ -249,6 +264,7 @@
return parameter.visitUpperBound(flagsOf());
},
allTypeParameters,
- factory);
+ factory,
+ AddKotlinAnyType.DISREGARD);
}
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
index 7e5e612..9826f3a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -4,12 +4,19 @@
package com.android.tools.r8.kotlin;
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableList;
import java.util.List;
import kotlinx.metadata.KmClassifier;
import kotlinx.metadata.KmType;
import kotlinx.metadata.KmTypeProjection;
+import kotlinx.metadata.KmTypeVisitor;
// Provides access to Kotlin information about a kotlin type.
public class KotlinTypeInfo {
@@ -50,10 +57,22 @@
return classifier instanceof KmClassifier.Class;
}
+ public KmClassifier.Class asClass() {
+ return (KmClassifier.Class) classifier;
+ }
+
+ public boolean isTypeParameter() {
+ return classifier instanceof KmClassifier.TypeParameter;
+ }
+
+ public KmClassifier.TypeParameter asTypeParameter() {
+ return (KmClassifier.TypeParameter) classifier;
+ }
+
public boolean isObjectArray() {
if (!isClass()) {
KmClassifier.Class classifier = (KmClassifier.Class) this.classifier;
- return classifier.getName().equals(ClassClassifiers.arrayDescriptor) && arguments.size() == 1;
+ return classifier.getName().equals(ClassClassifiers.arrayBinaryName) && arguments.size() == 1;
}
return false;
}
@@ -66,4 +85,63 @@
List<KotlinTypeProjectionInfo> arguments = getArguments();
return arguments.size() >= index ? getArguments().get(index) : null;
}
+
+ public KotlinTypeInfo toRenamed(KotlinMetadataSynthesizer synthesizer) {
+ DexType originalType = getLiveDexTypeFromClassClassifier(synthesizer.appView);
+ if (isClass() && originalType == null) {
+ return null;
+ }
+ KmClassifier renamedClassifier = classifier;
+ if (originalType != null) {
+ String typeClassifier = synthesizer.toRenamedClassifier(originalType);
+ if (typeClassifier != null) {
+ renamedClassifier = new KmClassifier.Class(typeClassifier);
+ }
+ }
+ if (arguments.isEmpty()) {
+ return renamedClassifier == classifier
+ ? this
+ : new KotlinTypeInfo(renamedClassifier, EMPTY_ARGUMENTS);
+ }
+ ImmutableList.Builder<KotlinTypeProjectionInfo> builder = ImmutableList.builder();
+ for (KotlinTypeProjectionInfo argument : arguments) {
+ builder.add(
+ new KotlinTypeProjectionInfo(
+ argument.variance,
+ argument.typeInfo == null ? null : argument.typeInfo.toRenamed(synthesizer)));
+ }
+ return new KotlinTypeInfo(renamedClassifier, builder.build());
+ }
+
+ private DexType getLiveDexTypeFromClassClassifier(AppView<AppInfoWithLiveness> appView) {
+ if (!isClass()) {
+ return null;
+ }
+ String descriptor = DescriptorUtils.getDescriptorFromKotlinClassifier(asClass().getName());
+ DexType type = appView.dexItemFactory().createType(descriptor);
+ if (appView.appInfo().wasPruned(type)) {
+ return null;
+ }
+ return type;
+ }
+
+ public KmType asKmType() {
+ KmType kmType = new KmType(flagsOf());
+ visit(kmType);
+ return kmType;
+ }
+
+ public void visit(KmTypeVisitor visitor) {
+ if (isClass()) {
+ visitor.visitClass(asClass().getName());
+ } else if (isTypeAlias()) {
+ visitor.visitTypeAlias(asTypeAlias().getName());
+ } else {
+ assert isTypeParameter();
+ visitor.visitTypeParameter(asTypeParameter().getId());
+ }
+ for (KotlinTypeProjectionInfo argument : arguments) {
+ argument.visit(visitor);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
index bd40bc4..0bee8cc 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeProjectionInfo.java
@@ -4,7 +4,10 @@
package com.android.tools.r8.kotlin;
+import static kotlinx.metadata.FlagsKt.flagsOf;
+
import kotlinx.metadata.KmTypeProjection;
+import kotlinx.metadata.KmTypeVisitor;
import kotlinx.metadata.KmVariance;
// Provides access to Kotlin information about the type projection of a type (arguments).
@@ -13,7 +16,7 @@
final KmVariance variance;
final KotlinTypeInfo typeInfo;
- private KotlinTypeProjectionInfo(KmVariance variance, KotlinTypeInfo typeInfo) {
+ KotlinTypeProjectionInfo(KmVariance variance, KotlinTypeInfo typeInfo) {
this.variance = variance;
this.typeInfo = typeInfo;
}
@@ -26,4 +29,13 @@
public boolean isStarProjection() {
return variance == null && typeInfo == null;
}
+
+ public void visit(KmTypeVisitor visitor) {
+ KmTypeVisitor kmTypeVisitor = visitor.visitArgument(flagsOf(), variance);
+ if (isStarProjection()) {
+ kmTypeVisitor.visitStarProjection();
+ } else {
+ typeInfo.visit(kmTypeVisitor);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index ad290b6..7772f09 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -773,7 +773,7 @@
private String messageWarningMissingNestHost(DexClass compiledClass) {
return messageErrorMissingNestHost(compiledClass)
- + "Class"
+ + "Class "
+ compiledClass.type.getName()
+ " is considered as not being part of any nest.";
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index 734ce50..5cd7513 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -4,22 +4,29 @@
package com.android.tools.r8.kotlin.metadata;
import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
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 junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertNotEquals;
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.kotlin.Kotlin.ClassClassifiers;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.KmClassifierSubject;
import com.android.tools.r8.utils.codeinspector.KmPackageSubject;
+import com.android.tools.r8.utils.codeinspector.KmTypeAliasSubject;
+import com.android.tools.r8.utils.codeinspector.KmTypeProjectionSubject;
+import com.android.tools.r8.utils.codeinspector.KmTypeSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
@@ -47,6 +54,7 @@
"true",
"42",
"1",
+ "ClassWithCompanion::fooOnCompanion",
"42",
"42",
"1",
@@ -86,6 +94,8 @@
public void smokeTest() throws Exception {
Path libJar = typeAliasLibJarMap.get(targetVersion);
+ testForJvm().addProgramFiles(libJar).run(parameters.getRuntime(), "Main").disassemble();
+
Path output =
kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
.addClasspathFiles(libJar)
@@ -107,33 +117,49 @@
.addProgramFiles(typeAliasLibJarMap.get(targetVersion))
// Keep non-private members of Impl
.addKeepRules("-keep class **.Impl { !private *; }")
- // Keep Itf, but allow minification.
- .addKeepRules("-keep,allowobfuscation class **.Itf")
+ // Keep but allow obfuscation of types.
+ .addKeepRules("-keep,allowobfuscation class " + PKG + ".typealias_lib.** { *; }")
+ .addKeepRules("-keepclassmembernames class " + PKG + ".typealias_lib.**" + " { *; }")
+ // Keep the Companion class for ClassWithCompanionC.
+ .addKeepRules("-keep class **.ClassWithCompanion$Companion { *; }")
+ // Keep the inner class, otherwise it cannot be constructed.
+ .addKeepRules("-keep class **.*Inner { *; }")
// Keep LibKt that contains the type-aliases and utils.
- .addKeepRules("-keep class **.LibKt { *; }")
- .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addKeepRules("-keep class **.LibKt, **.Lib_extKt { *; }")
+ // Keep the library test methods
+ .addKeepRules("-keep class " + PKG + ".typealias_lib.*Tester { *; }")
+ .addKeepRules("-keep class " + PKG + ".typealias_lib.*Tester$Companion { *; }")
+ .addKeepAttributes(
+ ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
+ ProguardKeepAttributes.SIGNATURE,
+ ProguardKeepAttributes.INNER_CLASSES,
+ ProguardKeepAttributes.ENCLOSING_METHOD)
.compile()
.inspect(this::inspect)
.writeToZip();
- ProcessResult kotlinTestCompileResult =
+ Path appJar =
kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typealias_app", "main"))
- .setOutputPath(temp.newFolder().toPath())
- // TODO(b/151194785): update to just .compile() once fixed.
- .compileRaw();
- // TODO(b/151194785): should be able to compile!
- assertNotEquals(0, kotlinTestCompileResult.exitCode);
- assertThat(
- kotlinTestCompileResult.stderr,
- containsString(
- "type mismatch: inferred type is ProgramClass but API /* = Itf */ was expected"));
+ .compile();
+
+ testForJvm()
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addClasspath(appJar)
+ .run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
+ .assertSuccessWithOutput(EXPECTED);
}
private void inspect(CodeInspector inspector) {
- String itfClassName = PKG + ".typealias_lib.Itf";
- String libKtClassName = PKG + ".typealias_lib.LibKt";
+ inspectLib(inspector);
+ inspectLibExt(inspector);
+ }
+
+ private void inspectLib(CodeInspector inspector) {
+ String packageName = PKG + ".typealias_lib";
+ String itfClassName = packageName + ".Itf";
+ String libKtClassName = packageName + ".LibKt";
ClassSubject itf = inspector.clazz(itfClassName);
assertThat(itf, isRenamed());
@@ -149,6 +175,115 @@
// API entry is kept, hence the presence of Metadata.
KmPackageSubject kmPackage = libKt.getKmPackage();
assertThat(kmPackage, isPresent());
- // TODO(b/151194785): need further inspection: many kinds of type appearances in typealias.
+
+ String arrayDescriptor =
+ DescriptorUtils.getDescriptorFromKotlinClassifier(ClassClassifiers.arrayBinaryName);
+
+ // Check that typealias myAliasedArray<T> = Array<T> exists.
+ KmTypeAliasSubject myAliasedArray = kmPackage.kmTypeAliasWithUniqueName("myAliasedArray");
+ assertThat(myAliasedArray, isPresent());
+ assertEquals(arrayDescriptor, myAliasedArray.expandedType().descriptor());
+
+ // Check that typealias API = Itf has been rewritten correctly.
+ KmTypeAliasSubject api = kmPackage.kmTypeAliasWithUniqueName("API");
+ assertThat(api, isPresent());
+ assertThat(api.expandedType(), isDexClass(itf.getDexClass()));
+ assertThat(api.underlyingType(), isDexClass(itf.getDexClass()));
+
+ // Check that the type-alias APIs exist and that the expanded type is renamed.
+ KmTypeAliasSubject apIs = kmPackage.kmTypeAliasWithUniqueName("APIs");
+ assertThat(apIs, isPresent());
+ assertEquals(arrayDescriptor, apIs.expandedType().descriptor());
+ assertEquals(1, apIs.expandedType().typeArguments().size());
+ KmTypeProjectionSubject expandedArgument = apIs.expandedType().typeArguments().get(0);
+ assertThat(expandedArgument.type(), isDexClass(itf.getDexClass()));
+
+ assertEquals(myAliasedArray.descriptor(packageName), apIs.underlyingType().descriptor());
+ assertEquals(1, apIs.underlyingType().typeArguments().size());
+ KmTypeProjectionSubject underlyingArgument = apIs.underlyingType().typeArguments().get(0);
+ KmTypeSubject type = underlyingArgument.type();
+ assertNotNull(type);
+ assertTrue(type.classifier().isTypeAlias());
+ assertEquals(api.descriptor(packageName), type.descriptor());
+ }
+
+ private void inspectLibExt(CodeInspector inspector) {
+ String packageName = PKG + ".typealias_lib";
+ String libKtClassName = packageName + ".Lib_extKt";
+
+ // Check that Arr has been renamed.
+ ClassSubject arr = inspector.clazz(packageName + ".Arr");
+ assertThat(arr, isRenamed());
+
+ ClassSubject libKt = inspector.clazz(libKtClassName);
+ KmPackageSubject kmPackage = libKt.getKmPackage();
+
+ // typealias Arr1D<K> = Arr<K>
+ KmTypeAliasSubject arr1D = kmPackage.kmTypeAliasWithUniqueName("Arr1D");
+ assertThat(arr1D, isPresent());
+ assertThat(arr1D.expandedType(), isDexClass(arr.getDexClass()));
+
+ // typealias Arr2D<K> = Arr1D<Arr1D<K>>
+ KmTypeAliasSubject arr2D = kmPackage.kmTypeAliasWithUniqueName("Arr2D");
+ assertThat(arr2D, isPresent());
+ assertThat(arr2D.expandedType(), isDexClass(arr.getDexClass()));
+ assertEquals(1, arr2D.expandedType().typeArguments().size());
+ KmTypeProjectionSubject arr2DexpandedArg = arr2D.expandedType().typeArguments().get(0);
+ assertThat(arr2DexpandedArg.type(), isDexClass(arr.getDexClass()));
+
+ assertEquals(arr1D.descriptor(packageName), arr2D.underlyingType().descriptor());
+ assertEquals(1, arr2D.underlyingType().typeArguments().size());
+ KmTypeProjectionSubject arr2DunderlyingArg = arr2D.underlyingType().typeArguments().get(0);
+ assertEquals(arr1D.descriptor(packageName), arr2DunderlyingArg.type().descriptor());
+
+ // typealias IntSet = Set<Int>
+ // typealias MyMapToSetOfInt<K> = MutableMap<K, IntSet>
+ KmTypeAliasSubject intSet = kmPackage.kmTypeAliasWithUniqueName("IntSet");
+ assertThat(intSet, isPresent());
+
+ KmTypeAliasSubject myMapToSetOfInt = kmPackage.kmTypeAliasWithUniqueName("MyMapToSetOfInt");
+ assertThat(myMapToSetOfInt, isPresent());
+ assertEquals(2, myMapToSetOfInt.underlyingType().typeArguments().size());
+ assertEquals(2, myMapToSetOfInt.expandedType().typeArguments().size());
+ assertEquals(1, myMapToSetOfInt.typeParameters().size());
+ KmClassifierSubject typeClassifier =
+ myMapToSetOfInt.underlyingType().typeArguments().get(0).type().classifier();
+ assertTrue(typeClassifier.isTypeParameter());
+ // Check that the type-variable K in 'MyMapToSetOfInt<K>' is the first argument in
+ // MutableMap<K, IntSet>.
+ assertEquals(
+ myMapToSetOfInt.typeParameters().get(0).getId(), typeClassifier.asTypeParameter().getId());
+
+ KmTypeSubject underlyingType = myMapToSetOfInt.underlyingType().typeArguments().get(1).type();
+ assertEquals(intSet.descriptor(packageName), underlyingType.descriptor());
+
+ KmTypeSubject expandedType = myMapToSetOfInt.expandedType().typeArguments().get(1).type();
+ assertEquals(intSet.expandedType(), expandedType);
+
+ // Check that the following exist:
+ // typealias MyHandler = (Int, Any) -> Unit
+ // typealias MyGenericPredicate<T> = (T) -> Boolean
+ assertThat(kmPackage.kmTypeAliasWithUniqueName("MyHandler"), isPresent());
+ KmTypeAliasSubject genericPredicate = kmPackage.kmTypeAliasWithUniqueName("MyGenericPredicate");
+ assertThat(genericPredicate, isPresent());
+
+ // Check that the type-variable T in 'MyGenericPredicate<T>' is the receiver argument in
+ // MutableMap<K, IntSet>.
+ assertEquals(1, genericPredicate.typeParameters().size());
+ assertEquals(1, genericPredicate.expandedType().typeArguments().size());
+ KmTypeProjectionSubject kmTypeProjectionSubject =
+ genericPredicate.expandedType().typeArguments().get(0);
+ assertTrue(kmTypeProjectionSubject.type().classifier().isTypeParameter());
+ assertEquals(
+ genericPredicate.typeParameters().get(0).getId(),
+ kmTypeProjectionSubject.type().classifier().asTypeParameter().getId());
+
+ // typealias ClassWithCompanionC = ClassWithCompanion.Companion
+ KmTypeAliasSubject classWithCompanionC =
+ kmPackage.kmTypeAliasWithUniqueName("ClassWithCompanionC");
+ assertThat(classWithCompanionC, isPresent());
+
+ ClassSubject companionClazz = inspector.clazz(packageName + ".ClassWithCompanion$Companion");
+ assertThat(classWithCompanionC.expandedType(), isDexClass(companionClazz.getDexClass()));
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt
index 396c2e4..f836216 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_app/main.kt
@@ -5,7 +5,7 @@
import com.android.tools.r8.kotlin.metadata.typealias_lib.API
import com.android.tools.r8.kotlin.metadata.typealias_lib.AlphaNaming
-import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr
+import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr1D
import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr2D
import com.android.tools.r8.kotlin.metadata.typealias_lib.Arr2DTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.CWithConstructor
@@ -13,6 +13,7 @@
import com.android.tools.r8.kotlin.metadata.typealias_lib.ClassWithCompanionC
import com.android.tools.r8.kotlin.metadata.typealias_lib.FunctionTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.Impl
+import com.android.tools.r8.kotlin.metadata.typealias_lib.IntSet
import com.android.tools.r8.kotlin.metadata.typealias_lib.InterfaceTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.MyAdvancedMap
import com.android.tools.r8.kotlin.metadata.typealias_lib.MyI
@@ -22,11 +23,10 @@
import com.android.tools.r8.kotlin.metadata.typealias_lib.OuterTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.SimpleClassTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.StillCWithConstructor
-import com.android.tools.r8.kotlin.metadata.typealias_lib.UnderlyingTypeTest
+import com.android.tools.r8.kotlin.metadata.typealias_lib.UnderlyingTypeTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.UnusedTypeArgument
import com.android.tools.r8.kotlin.metadata.typealias_lib.VerticalClassMergingTester
import com.android.tools.r8.kotlin.metadata.typealias_lib.seq
-import com.android.tools.r8.kotlin.metadata.typealias_lib.IntSet as IntSet1
class ProgramClass : Impl() {
override fun foo(): API {
@@ -46,7 +46,7 @@
}
fun testArr2D() {
- val arr1d : Arr<Int> = Arr(42);
+ val arr1d : Arr1D<Int> = Arr1D(42);
val arr2d : Arr2D<Int> = Arr2D(arr1d);
println(Arr2DTester.f(Arr2DTester.g(arr2d)).x.x);
}
@@ -57,10 +57,10 @@
println("42");
}
}
- InterfaceTester.f(InterfaceTester.g(myInstance)).f()
+ InterfaceTester.f(myInstance).f()
val map : MyMapToSetOfInt<Int> = HashMap();
- val set : IntSet1 = mutableSetOf(42);
+ val set : IntSet = mutableSetOf(42);
map.put(1, set);
println(InterfaceTester.i(InterfaceTester.h(map))[1]?.iterator()?.next() ?: "");
}
@@ -79,12 +79,12 @@
fun testNestedClasses() {
val nested = OuterNested(42);
val myInner : OuterNestedInner = nested.Inner(1)
- println(OuterTester.g(nested).y)
- println(OuterTester.f(myInner).x)
+ println(OuterTester.f(OuterTester.g(nested)).y)
+ println(OuterTester.h(OuterTester.i(myInner)).x)
}
fun testCompanion() {
- ClassWithCompanionC.foo;
+ println(ClassWithCompanionC.fooOnCompanion);
}
fun testConstructor() {
@@ -93,12 +93,12 @@
fun testUnderlyingType() {
val cWithConstructor = StillCWithConstructor(42)
- println(UnderlyingTypeTest.f(UnderlyingTypeTest.g(cWithConstructor)).x)
+ println(UnderlyingTypeTester.f(UnderlyingTypeTester.g(cWithConstructor)).x)
val advancedMap : MyAdvancedMap = HashMap();
val nested = OuterNested(42);
val myInner : OuterNestedInner = nested.Inner(1)
advancedMap.put(nested, myInner);
- val sameMap = UnderlyingTypeTest.h(UnderlyingTypeTest.i(advancedMap))
+ val sameMap = UnderlyingTypeTester.h(UnderlyingTypeTester.i(advancedMap))
println(sameMap.get(nested)?.x)
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt
index ba63667..60d5bda 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/typealias_lib/lib_ext.kt
@@ -1,6 +1,8 @@
// 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.
+@file:Suppress("UNCHECKED_CAST")
+
package com.android.tools.r8.kotlin.metadata.typealias_lib
// Unused type aliases
@@ -51,13 +53,14 @@
class SimpleClassTester {
companion object {
- fun f(a : SimpleClass) : AlphaNaming {
+ fun f(a : Any) : AlphaNaming {
+ return a as AlphaNaming;
+ }
+
+ fun g(a : AlphaNaming) : Any {
return a;
}
- fun g(a : AlphaNaming) : SimpleClass {
- return a;
- }
}
}
@@ -196,11 +199,11 @@
companion object {
- fun f(i : I<Int>) : MyI {
- return i;
+ fun f(i : Any) : MyI {
+ return i as MyI
}
- fun g(myI : MyI) : I<Int> {
+ fun g(myI : MyI) : Any {
return myI;
}
@@ -301,14 +304,21 @@
companion object {
- fun f(a : Outer.Nested.Inner) : OuterNestedInner {
+ fun f(a : Any) : OuterNested {
+ return a as OuterNested;
+ }
+
+ fun g(a : OuterNested) : Any {
return a;
}
- fun g(a : OuterNested) : Outer.Nested {
- return a;
+ fun h(a : Any) : OuterNestedInner {
+ return a as OuterNestedInner;
}
+ fun i(a : OuterNestedInner) : Any {
+ return a;
+ }
}
}
@@ -317,8 +327,8 @@
class ClassWithCompanion {
companion object {
- val foo: String
- get() = "A.Companion::foo"
+ val fooOnCompanion: String
+ get() = "ClassWithCompanion::fooOnCompanion"
}
}
@@ -355,11 +365,11 @@
companion object {
- fun f(a : C) : CWithConstructor {
- return a;
+ fun f(a : Any) : CWithConstructor {
+ return a as CWithConstructor;
}
- fun g(a : CWithConstructor) : C {
+ fun g(a : CWithConstructor) : Any {
return a;
}
}
@@ -391,7 +401,7 @@
// },
typealias MyAdvancedMap = MutableMap<OuterNested, OuterNestedInner>
-class UnderlyingTypeTest {
+class UnderlyingTypeTester {
companion object {
@@ -399,7 +409,7 @@
return a;
}
- fun g(a : C) : StillCWithConstructor {
+ fun g(a : CWithConstructor) : StillCWithConstructor {
return a;
}
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 c4d2078..a58d5ee 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
@@ -96,6 +96,16 @@
}
@Override
+ public List<KmTypeAliasSubject> getTypeAliases() {
+ return null;
+ }
+
+ @Override
+ public KmTypeAliasSubject kmTypeAliasWithUniqueName(String name) {
+ return null;
+ }
+
+ @Override
public List<String> getSuperTypeDescriptors() {
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
index a71d6f0..bbd1df6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmPackageSubject.java
@@ -88,4 +88,14 @@
public List<ClassSubject> getReturnTypesInProperties() {
return null;
}
+
+ @Override
+ public List<KmTypeAliasSubject> getTypeAliases() {
+ return null;
+ }
+
+ @Override
+ public KmTypeAliasSubject kmTypeAliasWithUniqueName(String name) {
+ return null;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java
new file mode 100644
index 0000000..78ac796
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentKmTypeAliasSubject.java
@@ -0,0 +1,51 @@
+// 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.errors.Unreachable;
+import java.util.List;
+
+public class AbsentKmTypeAliasSubject extends KmTypeAliasSubject {
+
+ @Override
+ public boolean isPresent() {
+ return false;
+ }
+
+ @Override
+ public boolean isRenamed() {
+ throw new Unreachable("Cannot determine if an absent KmTypeAlias is renamed");
+ }
+
+ @Override
+ public boolean isSynthetic() {
+ throw new Unreachable("Cannot determine if an absent KmTypeAlias is synthetic");
+ }
+
+ @Override
+ public String name() {
+ return null;
+ }
+
+ @Override
+ public List<KmTypeParameterSubject> typeParameters() {
+ return null;
+ }
+
+ @Override
+ public String descriptor(String pkg) {
+ return null;
+ }
+
+ @Override
+ public KmTypeSubject expandedType() {
+ return null;
+ }
+
+ @Override
+ public KmTypeSubject underlyingType() {
+ return null;
+ }
+}
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
index 626388f..6363747 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmDeclarationContainerSubject.java
@@ -18,6 +18,7 @@
import kotlinx.metadata.KmPropertyExtensionVisitor;
import kotlinx.metadata.KmPropertyVisitor;
import kotlinx.metadata.KmType;
+import kotlinx.metadata.KmTypeAlias;
import kotlinx.metadata.jvm.JvmFieldSignature;
import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor;
import kotlinx.metadata.jvm.JvmMethodSignature;
@@ -245,4 +246,22 @@
.filter(ClassSubject::isPresent)
.collect(Collectors.toList());
}
+
+ @Override
+ default List<KmTypeAliasSubject> getTypeAliases() {
+ CodeInspector inspector = codeInspector();
+ return getKmDeclarationContainer().getTypeAliases().stream()
+ .map(typeAlias -> new FoundKmTypeAliasSubject(inspector, typeAlias))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ default KmTypeAliasSubject kmTypeAliasWithUniqueName(String name) {
+ for (KmTypeAlias typeAlias : getKmDeclarationContainer().getTypeAliases()) {
+ if (typeAlias.getName().equals(name)) {
+ return new FoundKmTypeAliasSubject(codeInspector(), typeAlias);
+ }
+ }
+ return new AbsentKmTypeAliasSubject();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java
new file mode 100644
index 0000000..a07125c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeAliasSubject.java
@@ -0,0 +1,65 @@
+// 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.DESCRIPTOR_PACKAGE_SEPARATOR;
+import static com.android.tools.r8.utils.DescriptorUtils.getBinaryNameFromJavaType;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import kotlinx.metadata.KmTypeAlias;
+
+public class FoundKmTypeAliasSubject extends KmTypeAliasSubject {
+
+ private final KmTypeAlias kmTypeAlias;
+ private final CodeInspector codeInspector;
+
+ FoundKmTypeAliasSubject(CodeInspector codeInspector, KmTypeAlias kmTypeAlias) {
+ this.codeInspector = codeInspector;
+ this.kmTypeAlias = kmTypeAlias;
+ }
+
+ @Override
+ public boolean isPresent() {
+ return true;
+ }
+
+ @Override
+ public boolean isRenamed() {
+ return false;
+ }
+
+ @Override
+ public boolean isSynthetic() {
+ return false;
+ }
+
+ @Override
+ public String name() {
+ return kmTypeAlias.getName();
+ }
+
+ @Override
+ public List<KmTypeParameterSubject> typeParameters() {
+ return kmTypeAlias.getTypeParameters().stream()
+ .map(kmTypeParameter -> new FoundKmTypeParameterSubject(codeInspector, kmTypeParameter))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public String descriptor(String pkg) {
+ return "L" + getBinaryNameFromJavaType(pkg) + DESCRIPTOR_PACKAGE_SEPARATOR + name() + ";";
+ }
+
+ @Override
+ public KmTypeSubject expandedType() {
+ return new KmTypeSubject(codeInspector, kmTypeAlias.expandedType);
+ }
+
+ @Override
+ public KmTypeSubject underlyingType() {
+ return new KmTypeSubject(codeInspector, kmTypeAlias.underlyingType);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java
index a15e78b..fb5e909 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundKmTypeParameterSubject.java
@@ -51,4 +51,28 @@
.map(kmType -> new KmTypeSubject(codeInspector, kmType))
.collect(Collectors.toList());
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof FoundKmTypeParameterSubject)) {
+ return false;
+ }
+ KmTypeParameter other = ((FoundKmTypeParameterSubject) obj).kmTypeParameter;
+ if (!kmTypeParameter.getName().equals(other.getName())
+ || kmTypeParameter.getId() != other.getId()
+ || kmTypeParameter.getFlags() != other.getFlags()
+ || kmTypeParameter.getVariance() != other.getVariance()) {
+ return false;
+ }
+ if (kmTypeParameter.getUpperBounds().size() != other.getUpperBounds().size()) {
+ return false;
+ }
+ for (int i = 0; i < kmTypeParameter.getUpperBounds().size(); i++) {
+ if (!KmTypeSubject.areEqual(
+ kmTypeParameter.getUpperBounds().get(i), other.getUpperBounds().get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java
index a716822..8adb293 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmClassifierSubject.java
@@ -22,6 +22,14 @@
return (KmClassifier.TypeParameter) classifier;
}
+ public boolean isTypeAlias() {
+ return classifier instanceof KmClassifier.TypeAlias;
+ }
+
+ public KmClassifier.TypeAlias asTypeAlias() {
+ return (KmClassifier.TypeAlias) classifier;
+ }
+
@Override
public boolean isPresent() {
return true;
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
index 0893077..24e26da 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmDeclarationContainerSubject.java
@@ -29,4 +29,8 @@
List<KmPropertySubject> getProperties();
List<ClassSubject> getReturnTypesInProperties();
+
+ List<KmTypeAliasSubject> getTypeAliases();
+
+ KmTypeAliasSubject kmTypeAliasWithUniqueName(String name);
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.java
new file mode 100644
index 0000000..f87d368
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeAliasSubject.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 abstract class KmTypeAliasSubject extends Subject {
+
+ public abstract String name();
+
+ public abstract List<KmTypeParameterSubject> typeParameters();
+
+ public abstract String descriptor(String pkg);
+
+ public abstract KmTypeSubject expandedType();
+
+ public abstract KmTypeSubject underlyingType();
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java
index dd6b4a4..76f3782 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeProjectionSubject.java
@@ -38,4 +38,25 @@
public boolean isSynthetic() {
throw new Unreachable("Cannot determine if a type argument is synthetic");
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof KmTypeProjectionSubject)) {
+ return false;
+ }
+ return areEqual(this.kmTypeProjection, ((KmTypeProjectionSubject) obj).kmTypeProjection);
+ }
+
+ public static boolean areEqual(KmTypeProjection one, KmTypeProjection other) {
+ if (one == null && other == null) {
+ return true;
+ }
+ if (one == null || other == null) {
+ return false;
+ }
+ if (one.getVariance() != other.getVariance()) {
+ return false;
+ }
+ return KmTypeSubject.areEqual(one.getType(), other.getType());
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java
index 6523ec2..44a141a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/KmTypeSubject.java
@@ -10,8 +10,10 @@
import com.android.tools.r8.utils.Box;
import java.util.List;
import java.util.stream.Collectors;
+import kotlinx.metadata.KmAnnotation;
import kotlinx.metadata.KmType;
import kotlinx.metadata.KmTypeVisitor;
+import kotlinx.metadata.jvm.JvmExtensionsKt;
public class KmTypeSubject extends Subject {
private final CodeInspector codeInspector;
@@ -76,4 +78,66 @@
public boolean isSynthetic() {
throw new Unreachable("Cannot determine if a type is synthetic");
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof KmTypeSubject)) {
+ return false;
+ }
+ return areEqual(this.kmType, ((KmTypeSubject) obj).kmType);
+ }
+
+ public static boolean areEqual(KmType one, KmType other) {
+ if (one == null && other == null) {
+ return true;
+ }
+ if (one == null || other == null) {
+ return false;
+ }
+ if (one.getFlags() != other.getFlags()) {
+ return false;
+ }
+ if (!one.classifier.toString().equals(other.classifier.toString())) {
+ return false;
+ }
+ if (one.getArguments().size() != other.getArguments().size()) {
+ return false;
+ }
+ for (int i = 0; i < one.getArguments().size(); i++) {
+ if (!KmTypeProjectionSubject.areEqual(
+ one.getArguments().get(i), other.getArguments().get(i))) {
+ return false;
+ }
+ }
+ if (!areEqual(one.getAbbreviatedType(), other.getAbbreviatedType())) {
+ return false;
+ }
+ if (!areEqual(one.getOuterType(), other.getOuterType())) {
+ return false;
+ }
+ // TODO(b/152745540): Add equality for flexibleUpperBoundType.
+ if (JvmExtensionsKt.isRaw(one) != JvmExtensionsKt.isRaw(other)) {
+ return false;
+ }
+ List<KmAnnotation> annotationsOne = JvmExtensionsKt.getAnnotations(one);
+ List<KmAnnotation> annotationsOther = JvmExtensionsKt.getAnnotations(other);
+ if (annotationsOne.size() != annotationsOther.size()) {
+ return false;
+ }
+ for (int i = 0; i < annotationsOne.size(); i++) {
+ KmAnnotation kmAnnotationOne = annotationsOne.get(i);
+ KmAnnotation kmAnnotationOther = annotationsOther.get(i);
+ if (!kmAnnotationOne.getClassName().equals(kmAnnotationOther.getClassName())) {
+ return false;
+ }
+ if (!kmAnnotationOne
+ .getArguments()
+ .keySet()
+ .equals(kmAnnotationOther.getArguments().keySet())) {
+ return false;
+ }
+ assert false : "Not defined how to compare kmAnnotationArguments";
+ }
+ return true;
+ }
}