Update kotlin metadata library from 0.2.0 to 0.3.0
Bug: 206855609
Bug: 207397158
Change-Id: Iefad4c3e5435e8173bea4bce65e0593f93511785
diff --git a/build.gradle b/build.gradle
index 5220ac2..324c0e2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,13 +11,6 @@
import tasks.DownloadDependency
import tasks.GetJarsFromConfiguration
import utils.Utils
-import org.gradle.api.tasks.testing.logging.TestExceptionFormat
-import org.gradle.api.tasks.testing.logging.TestLogEvent
-import org.gradle.api.tasks.testing.TestOutputEvent
-
-import java.nio.charset.StandardCharsets
-import java.nio.file.Files
-import java.nio.file.StandardOpenOption
buildscript {
repositories {
@@ -53,7 +46,7 @@
// The kotlin version is only here to specify the kotlin language level,
// all kotlin compilations are done in tests.
kotlinVersion = '1.3.72'
- kotlinExtMetadataJVMVersion = '0.2.0'
+ kotlinExtMetadataJVMVersion = '0.3.0'
smaliVersion = '2.2b4'
errorproneVersion = '2.3.2'
testngVersion = '6.10'
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 ef44b4b..9470367 100644
--- a/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
+++ b/src/main/java/com/android/tools/r8/kotlin/Kotlin.java
@@ -9,8 +9,10 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.google.common.collect.ImmutableSet;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -28,11 +30,64 @@
public static final String NAME = "kotlin";
public static final String PACKAGE_PREFIX = "L" + NAME + "/";
+ public final DexString kotlinJvmTypePrefix;
+
public static final class ClassClassifiers {
public static final String arrayBinaryName = NAME + "/Array";
+ public static final String arrayDescriptor = PACKAGE_PREFIX + "Array;";
public static final String anyDescriptor = PACKAGE_PREFIX + "Any;";
+ public static final String unitDescriptor = PACKAGE_PREFIX + "Unit;";
+ public static final String booleanDescriptor = PACKAGE_PREFIX + "Boolean";
+ public static final String charDescriptor = PACKAGE_PREFIX + "Char";
+ public static final String byteDescriptor = PACKAGE_PREFIX + "Byte";
+ public static final String uByteDescriptor = PACKAGE_PREFIX + "UByte";
+ public static final String shortDescriptor = PACKAGE_PREFIX + "Short;";
+ public static final String uShortDescriptor = PACKAGE_PREFIX + "UShort;";
+ public static final String intDescriptor = PACKAGE_PREFIX + "Int;";
+ public static final String uIntDescriptor = PACKAGE_PREFIX + "UInt;";
+ public static final String floatDescriptor = PACKAGE_PREFIX + "Float;";
+ public static final String longDescriptor = PACKAGE_PREFIX + "Long;";
+ public static final String uLongDescriptor = PACKAGE_PREFIX + "ULong;";
+ public static final String doubleDescriptor = PACKAGE_PREFIX + "Double;";
+ public static final String functionDescriptor = PACKAGE_PREFIX + "Function;";
+ public static final String kFunctionDescriptor = PACKAGE_PREFIX + "KFunction;";
public static final String anyName = NAME + "/Any";
+
+ public static final Set<String> kotlinPrimitivesDescriptors =
+ ImmutableSet.<String>builder()
+ .add(booleanDescriptor)
+ .add(charDescriptor)
+ .add(byteDescriptor)
+ .add(uByteDescriptor)
+ .add(shortDescriptor)
+ .add(uShortDescriptor)
+ .add(intDescriptor)
+ .add(uIntDescriptor)
+ .add(floatDescriptor)
+ .add(longDescriptor)
+ .add(uLongDescriptor)
+ .add(doubleDescriptor)
+ .build();
+
+ // Kotlin static known types is a possible not complete collection of descriptors that kotlinc
+ // and kotlin reflect know and expect the existence of.
+ public static final Set<String> kotlinStaticallyKnownTypes;
+
+ static {
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ kotlinPrimitivesDescriptors.forEach(
+ primitive -> {
+ builder.add(primitive);
+ builder.add(primitive.substring(0, primitive.length() - 1) + "Array;");
+ });
+ builder.add(unitDescriptor);
+ builder.add(anyDescriptor);
+ builder.add(arrayDescriptor);
+ builder.add(functionDescriptor);
+ builder.add(kFunctionDescriptor);
+ kotlinStaticallyKnownTypes = builder.build();
+ }
}
public Kotlin(DexItemFactory factory) {
@@ -41,6 +96,7 @@
this.intrinsics = new Intrinsics();
this.metadata = new Metadata();
this.assertions = new _Assertions();
+ kotlinJvmTypePrefix = factory.createString("Lkotlin/jvm/");
}
public final class Functional {
@@ -67,10 +123,6 @@
private Functional() {
}
- public final DexString kotlinStyleLambdaInstanceName = factory.createString("INSTANCE");
-
- public final DexType functionBase =
- factory.createType(PACKAGE_PREFIX + "jvm/internal/FunctionBase;");
public final DexType lambdaType = factory.createType(PACKAGE_PREFIX + "jvm/internal/Lambda;");
public final DexMethod lambdaInitializerMethod = factory.createMethod(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
index 883be66..6f34ad1 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationArgumentInfo.java
@@ -29,10 +29,10 @@
ImmutableMap.of();
abstract boolean rewrite(
- Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens);
+ Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens);
private static KotlinAnnotationArgumentInfo createArgument(
- KmAnnotationArgument<?> arg, DexItemFactory factory) {
+ KmAnnotationArgument arg, DexItemFactory factory) {
if (arg instanceof KClassValue) {
return KotlinAnnotationClassValueInfo.create((KClassValue) arg, factory);
} else if (arg instanceof EnumValue) {
@@ -47,7 +47,7 @@
}
static Map<String, KotlinAnnotationArgumentInfo> create(
- Map<String, KmAnnotationArgument<?>> arguments, DexItemFactory factory) {
+ Map<String, KmAnnotationArgument> arguments, DexItemFactory factory) {
if (arguments.isEmpty()) {
return EMPTY_ARGUMENTS;
}
@@ -59,14 +59,17 @@
private static class KotlinAnnotationClassValueInfo extends KotlinAnnotationArgumentInfo {
private final KotlinTypeReference value;
+ private final int arrayDimensionCount;
- private KotlinAnnotationClassValueInfo(KotlinTypeReference value) {
+ private KotlinAnnotationClassValueInfo(KotlinTypeReference value, int arrayDimensionCount) {
this.value = value;
+ this.arrayDimensionCount = arrayDimensionCount;
}
private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) {
return new KotlinAnnotationClassValueInfo(
- KotlinTypeReference.fromBinaryName(arg.getValue(), factory));
+ KotlinTypeReference.fromBinaryName(arg.getClassName(), factory, arg.getClassName()),
+ arg.getArrayDimensionCount());
}
@Override
@@ -76,9 +79,9 @@
@Override
boolean rewrite(
- Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+ Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
return value.toRenamedBinaryNameOrDefault(
- rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue)),
+ rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue, arrayDimensionCount)),
appView,
namingLens,
ClassClassifiers.anyName);
@@ -97,7 +100,8 @@
private static KotlinAnnotationEnumValueInfo create(EnumValue arg, DexItemFactory factory) {
return new KotlinAnnotationEnumValueInfo(
- KotlinTypeReference.fromBinaryName(arg.getEnumClassName(), factory),
+ KotlinTypeReference.fromBinaryName(
+ arg.getEnumClassName(), factory, arg.getEnumClassName()),
arg.getEnumEntryName());
}
@@ -108,7 +112,7 @@
@Override
boolean rewrite(
- Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+ Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
return enumClassName.toRenamedBinaryNameOrDefault(
rewrittenEnumClassName ->
consumer.accept(new EnumValue(rewrittenEnumClassName, enumEntryName)),
@@ -129,7 +133,7 @@
private static KotlinAnnotationAnnotationValueInfo create(
AnnotationValue arg, DexItemFactory factory) {
return new KotlinAnnotationAnnotationValueInfo(
- KotlinAnnotationInfo.create(arg.getValue(), factory));
+ KotlinAnnotationInfo.create(arg.getAnnotation(), factory));
}
@Override
@@ -139,7 +143,7 @@
@Override
boolean rewrite(
- Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+ Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
return value.rewrite(
rewrittenAnnotation -> {
if (rewrittenAnnotation != null) {
@@ -163,11 +167,11 @@
}
private static KotlinAnnotationArrayValueInfo create(ArrayValue arg, DexItemFactory factory) {
- if (arg.getValue().isEmpty()) {
+ if (arg.getElements().isEmpty()) {
return EMPTY;
}
ImmutableList.Builder<KotlinAnnotationArgumentInfo> builder = ImmutableList.builder();
- for (KmAnnotationArgument<?> argument : arg.getValue()) {
+ for (KmAnnotationArgument argument : arg.getElements()) {
builder.add(createArgument(argument, factory));
}
return new KotlinAnnotationArrayValueInfo(builder.build());
@@ -182,8 +186,8 @@
@Override
boolean rewrite(
- Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
- List<KmAnnotationArgument<?>> rewrittenArguments = new ArrayList<>();
+ Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
+ List<KmAnnotationArgument> rewrittenArguments = new ArrayList<>();
boolean rewritten = false;
for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
rewritten |=
@@ -203,13 +207,13 @@
private static class KotlinAnnotationPrimitiveArgumentInfo extends KotlinAnnotationArgumentInfo {
- private final KmAnnotationArgument<?> argument;
+ private final KmAnnotationArgument argument;
- private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument<?> argument) {
+ private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument argument) {
this.argument = argument;
}
- private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument<?> argument) {
+ private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument argument) {
return new KotlinAnnotationPrimitiveArgumentInfo(argument);
}
@@ -220,7 +224,7 @@
@Override
boolean rewrite(
- Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
+ Consumer<KmAnnotationArgument> consumer, AppView<?> appView, NamingLens namingLens) {
consumer.accept(argument);
return false;
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
index fd036d8..d21cfb1 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinAnnotationInfo.java
@@ -34,7 +34,8 @@
static KotlinAnnotationInfo create(KmAnnotation annotation, DexItemFactory factory) {
return new KotlinAnnotationInfo(
- KotlinTypeReference.fromBinaryName(annotation.getClassName(), factory),
+ KotlinTypeReference.fromBinaryName(
+ annotation.getClassName(), factory, annotation.getClassName()),
KotlinAnnotationArgumentInfo.create(annotation.getArguments(), factory));
}
@@ -63,7 +64,7 @@
return;
}
String classifier = DescriptorUtils.descriptorToKotlinClassifier(renamedDescriptor);
- Map<String, KmAnnotationArgument<?>> rewrittenArguments = new LinkedHashMap<>();
+ Map<String, KmAnnotationArgument> rewrittenArguments = new LinkedHashMap<>();
arguments.forEach(
(key, arg) ->
rewritten.or(
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index e440049..9e7d703 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.Reporter;
@@ -37,6 +38,7 @@
private final int flags;
private final String name;
+ private final boolean nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin;
private final String moduleName;
private final List<KotlinConstructorInfo> constructorsWithNoBacking;
private final KotlinDeclarationContainerInfo declarationContainerInfo;
@@ -50,10 +52,16 @@
private final String packageName;
private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
private final int[] metadataVersion;
+ private final String inlineClassUnderlyingPropertyName;
+ private final KotlinTypeInfo inlineClassUnderlyingType;
+
+ // List of tracked assignments of kotlin metadata.
+ private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo;
private KotlinClassInfo(
int flags,
String name,
+ boolean nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin,
String moduleName,
KotlinDeclarationContainerInfo declarationContainerInfo,
List<KotlinTypeParameterInfo> typeParameters,
@@ -66,9 +74,14 @@
KotlinTypeReference anonymousObjectOrigin,
String packageName,
KotlinLocalDelegatedPropertyInfo localDelegatedProperties,
- int[] metadataVersion) {
+ int[] metadataVersion,
+ String inlineClassUnderlyingPropertyName,
+ KotlinTypeInfo inlineClassUnderlyingType,
+ KotlinMetadataMembersTracker originalMembersWithKotlinInfo) {
this.flags = flags;
this.name = name;
+ this.nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin =
+ nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin;
this.moduleName = moduleName;
this.declarationContainerInfo = declarationContainerInfo;
this.typeParameters = typeParameters;
@@ -82,6 +95,9 @@
this.packageName = packageName;
this.localDelegatedProperties = localDelegatedProperties;
this.metadataVersion = metadataVersion;
+ this.inlineClassUnderlyingPropertyName = inlineClassUnderlyingPropertyName;
+ this.inlineClassUnderlyingType = inlineClassUnderlyingType;
+ this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo;
}
public static KotlinClassInfo create(
@@ -107,6 +123,8 @@
}
ImmutableList.Builder<KotlinConstructorInfo> notBackedConstructors = ImmutableList.builder();
int constructorIndex = 0;
+ KotlinMetadataMembersTracker originalMembersWithKotlinInfo =
+ new KotlinMetadataMembersTracker(appView);
for (KmConstructor kmConstructor : kmClass.getConstructors()) {
boolean readConstructorSignature =
extensionInformation.hasJvmMethodSignatureExtensionForConstructor(constructorIndex++);
@@ -117,6 +135,7 @@
DexEncodedMethod method = methodMap.get(signature.asString());
if (method != null) {
method.setKotlinMemberInfo(constructorInfo);
+ originalMembersWithKotlinInfo.add(method.getReference());
continue;
}
}
@@ -125,11 +144,26 @@
}
KotlinDeclarationContainerInfo container =
KotlinDeclarationContainerInfo.create(
- kmClass, methodMap, fieldMap, factory, reporter, keepByteCode, extensionInformation);
+ kmClass,
+ methodMap,
+ fieldMap,
+ factory,
+ reporter,
+ keepByteCode,
+ extensionInformation,
+ originalMembersWithKotlinInfo);
setCompanionObject(kmClass, hostClass, reporter);
+ KotlinTypeReference anonymousObjectOrigin = getAnonymousObjectOrigin(kmClass, factory);
+ boolean nameCanBeDeducedFromClassOrOrigin =
+ kmClass.name.equals(
+ KotlinMetadataUtils.getKotlinClassName(
+ hostClass, hostClass.getType().toDescriptorString()))
+ || (anonymousObjectOrigin != null
+ && kmClass.name.equals(anonymousObjectOrigin.toKotlinClassifier(true)));
return new KotlinClassInfo(
kmClass.getFlags(),
kmClass.name,
+ nameCanBeDeducedFromClassOrOrigin,
JvmExtensionsKt.getModuleName(kmClass),
container,
KotlinTypeParameterInfo.create(kmClass.getTypeParameters(), factory, reporter),
@@ -139,18 +173,22 @@
getNestedClasses(hostClass, kmClass.getNestedClasses(), factory),
kmClass.getEnumEntries(),
KotlinVersionRequirementInfo.create(kmClass.getVersionRequirements()),
- getAnonymousObjectOrigin(kmClass, factory),
+ anonymousObjectOrigin,
packageName,
KotlinLocalDelegatedPropertyInfo.create(
JvmExtensionsKt.getLocalDelegatedProperties(kmClass), factory, reporter),
- metadataVersion);
+ metadataVersion,
+ kmClass.getInlineClassUnderlyingPropertyName(),
+ KotlinTypeInfo.create(kmClass.getInlineClassUnderlyingType(), factory, reporter),
+ originalMembersWithKotlinInfo);
}
private static KotlinTypeReference getAnonymousObjectOrigin(
KmClass kmClass, DexItemFactory factory) {
String anonymousObjectOriginName = JvmExtensionsKt.getAnonymousObjectOriginName(kmClass);
if (anonymousObjectOriginName != null) {
- return KotlinTypeReference.fromBinaryName(anonymousObjectOriginName, factory);
+ return KotlinTypeReference.fromBinaryName(
+ anonymousObjectOriginName, factory, anonymousObjectOriginName);
}
return null;
}
@@ -161,7 +199,7 @@
for (String nestedClass : nestedClasses) {
String binaryName =
clazz.type.toBinaryName() + DescriptorUtils.INNER_CLASS_SEPARATOR + nestedClass;
- nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
+ nestedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, nestedClass));
}
return nestedTypes.build();
}
@@ -173,7 +211,7 @@
String binaryName =
sealedSubClass.replace(
DescriptorUtils.JAVA_PACKAGE_SEPARATOR, DescriptorUtils.INNER_CLASS_SEPARATOR);
- sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory));
+ sealedTypes.add(KotlinTypeReference.fromBinaryName(binaryName, factory, sealedSubClass));
}
return sealedTypes.build();
}
@@ -221,14 +259,29 @@
// Set potentially renamed class name.
DexString originalDescriptor = clazz.type.descriptor;
DexString rewrittenDescriptor = namingLens.lookupDescriptor(clazz.type);
- // If the original descriptor equals the rewritten descriptor, we pick the original name
- // to preserve potential errors in the original name. As an example, the kotlin stdlib has
- // name: .kotlin/collections/CollectionsKt___CollectionsKt$groupingBy$1, which seems incorrect.
boolean rewritten = !originalDescriptor.equals(rewrittenDescriptor);
- kmClass.setName(
- !rewritten
- ? this.name
- : DescriptorUtils.getBinaryNameFromDescriptor(rewrittenDescriptor.toString()));
+ if (!nameCanBeSynthesizedFromClassOrAnonymousObjectOrigin) {
+ kmClass.setName(this.name);
+ } else {
+ String rewrittenName = null;
+ // When the class has an anonymousObjectOrigin and the name equals the identifier there, we
+ // keep the name tied to the anonymousObjectOrigin.
+ if (anonymousObjectOrigin != null
+ && name.equals(anonymousObjectOrigin.toKotlinClassifier(true))) {
+ Box<String> rewrittenOrigin = new Box<>();
+ anonymousObjectOrigin.toRenamedBinaryNameOrDefault(
+ rewrittenOrigin::set, appView, namingLens, null);
+ if (rewrittenOrigin.isSet()) {
+ rewrittenName = "." + rewrittenOrigin.get();
+ }
+ }
+ if (rewrittenName == null) {
+ rewrittenName =
+ KotlinMetadataUtils.getKotlinClassName(clazz, rewrittenDescriptor.toString());
+ }
+ kmClass.setName(rewrittenName);
+ rewritten |= !name.equals(rewrittenName);
+ }
// Find a companion object.
for (DexEncodedField field : clazz.fields()) {
if (field.getKotlinInfo().isCompanion()) {
@@ -241,10 +294,12 @@
rewritten |= constructorInfo.rewrite(kmClass, null, appView, namingLens);
}
// Find all constructors.
+ KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
for (DexEncodedMethod method : clazz.methods()) {
if (method.getKotlinInfo().isConstructor()) {
KotlinConstructorInfo constructorInfo = method.getKotlinInfo().asConstructor();
rewritten |= constructorInfo.rewrite(kmClass, method, appView, namingLens);
+ rewrittenReferences.add(method.getReference());
}
}
// Rewrite functions, type-aliases and type-parameters.
@@ -255,7 +310,8 @@
kmClass::visitTypeAlias,
clazz,
appView,
- namingLens);
+ namingLens,
+ rewrittenReferences);
// Rewrite type parameters.
for (KotlinTypeParameterInfo typeParameter : typeParameters) {
rewritten |= typeParameter.rewrite(kmClass::visitTypeParameter, appView, namingLens);
@@ -271,30 +327,31 @@
}
// Rewrite nested classes.
for (KotlinTypeReference nestedClass : nestedClasses) {
- rewritten |=
+ Box<String> nestedDescriptorBox = new Box<>();
+ boolean nestedClassRewritten =
nestedClass.toRenamedBinaryNameOrDefault(
- nestedDescriptor -> {
- if (nestedDescriptor != null) {
- // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
- // is the
- // name we should record.
- int innerClassIndex =
- nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
- kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
- }
- },
- appView,
- namingLens,
- null);
+ nestedDescriptorBox::set, appView, namingLens, null);
+ if (nestedDescriptorBox.isSet()) {
+ if (nestedClassRewritten) {
+ // If the class is a nested class, it should be on the form Foo.Bar$Baz, where Baz
+ // is the name we should record.
+ String nestedDescriptor = nestedDescriptorBox.get();
+ int innerClassIndex = nestedDescriptor.lastIndexOf(DescriptorUtils.INNER_CLASS_SEPARATOR);
+ kmClass.visitNestedClass(nestedDescriptor.substring(innerClassIndex + 1));
+ } else {
+ kmClass.visitNestedClass(nestedClass.getOriginalName());
+ }
+ }
+ rewritten |= nestedClassRewritten;
}
// Rewrite sealed sub classes.
for (KotlinTypeReference sealedSubClass : sealedSubClasses) {
rewritten |=
sealedSubClass.toRenamedBinaryNameOrDefault(
- sealedDescriptor -> {
- if (sealedDescriptor != null) {
+ sealedName -> {
+ if (sealedName != null) {
kmClass.visitSealedSubclass(
- sealedDescriptor.replace(
+ sealedName.replace(
DescriptorUtils.INNER_CLASS_SEPARATOR,
DescriptorUtils.JAVA_PACKAGE_SEPARATOR));
}
@@ -306,6 +363,12 @@
// TODO(b/154347404): Understand enum entries.
kmClass.getEnumEntries().addAll(enumEntries);
rewritten |= versionRequirements.rewrite(kmClass::visitVersionRequirement);
+ if (inlineClassUnderlyingPropertyName != null && inlineClassUnderlyingType != null) {
+ kmClass.setInlineClassUnderlyingPropertyName(inlineClassUnderlyingPropertyName);
+ rewritten |=
+ inlineClassUnderlyingType.rewrite(
+ kmClass::visitInlineClassUnderlyingType, appView, namingLens);
+ }
JvmClassExtensionVisitor extensionVisitor =
(JvmClassExtensionVisitor) kmClass.visitExtensions(JvmClassExtensionVisitor.TYPE);
extensionVisitor.visitModuleName(moduleName);
@@ -327,7 +390,9 @@
extensionVisitor.visitEnd();
KotlinClassMetadata.Class.Writer writer = new KotlinClassMetadata.Class.Writer();
kmClass.accept(writer);
- return Pair.create(writer.write().getHeader(), rewritten);
+ return Pair.create(
+ writer.write().getHeader(),
+ rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView));
}
@Override
@@ -346,7 +411,7 @@
declarationContainerInfo.trace(definitionSupplier);
forEachApply(typeParameters, param -> param::trace, definitionSupplier);
forEachApply(superTypes, type -> type::trace, definitionSupplier);
- forEachApply(sealedSubClasses, sealed -> sealed::trace, definitionSupplier);
+ forEachApply(sealedSubClasses, sealedClass -> sealedClass::trace, definitionSupplier);
forEachApply(nestedClasses, nested -> nested::trace, definitionSupplier);
localDelegatedProperties.trace(definitionSupplier);
// TODO(b/154347404): trace enum entries.
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 bfabd6c..7f4c47d 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -33,6 +33,8 @@
public final class KotlinClassMetadataReader {
+ private static final int SYNTHETIC_CLASS_KIND = 3;
+
public static KotlinClassLevelInfo getKotlinInfo(
DexClass clazz, AppView<?> appView, Consumer<DexEncodedMethod> keepByteCode) {
DexAnnotation meta =
@@ -75,16 +77,25 @@
public static boolean isLambda(AppView<?> appView, DexClass clazz) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
Kotlin kotlin = dexItemFactory.kotlin;
+ Flavour flavour = getFlavour(clazz, kotlin);
+ if (flavour == Flavour.Unclassified) {
+ return false;
+ }
DexAnnotation metadataAnnotation =
clazz.annotations().getFirstMatching(dexItemFactory.kotlinMetadataType);
- if (metadataAnnotation != null) {
- KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, metadataAnnotation.annotation);
+ if (metadataAnnotation == null) {
+ return false;
+ }
+ Map<DexString, DexAnnotationElement> elementMap = toElementMap(metadataAnnotation.annotation);
+ if (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND) {
+ KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, elementMap);
if (kMetadata instanceof SyntheticClass) {
- SyntheticClass syntheticClass = (SyntheticClass) kMetadata;
- return syntheticClass.isLambda()
- && getFlavour(syntheticClass, clazz, kotlin) != Flavour.Unclassified;
+ return ((SyntheticClass) kMetadata).isLambda();
}
}
+ assert toKotlinClassMetadata(kotlin, elementMap) instanceof SyntheticClass
+ == (getKind(kotlin, elementMap) == SYNTHETIC_CLASS_KIND)
+ : "Synthetic class kinds should agree";
return false;
}
@@ -98,16 +109,21 @@
public static KotlinClassMetadata toKotlinClassMetadata(
Kotlin kotlin, DexEncodedAnnotation metadataAnnotation) {
+ return toKotlinClassMetadata(kotlin, toElementMap(metadataAnnotation));
+ }
+
+ private static Map<DexString, DexAnnotationElement> toElementMap(
+ DexEncodedAnnotation metadataAnnotation) {
Map<DexString, DexAnnotationElement> elementMap = new IdentityHashMap<>();
for (DexAnnotationElement element : metadataAnnotation.elements) {
elementMap.put(element.name, element);
}
+ return elementMap;
+ }
- DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
- if (kind == null) {
- throw new MetadataError("element 'k' is missing.");
- }
- Integer k = (Integer) kind.value.getBoxedValue();
+ private static KotlinClassMetadata toKotlinClassMetadata(
+ Kotlin kotlin, Map<DexString, DexAnnotationElement> elementMap) {
+ int k = getKind(kotlin, elementMap);
DexAnnotationElement metadataVersion = elementMap.get(kotlin.metadata.metadataVersion);
int[] mv = metadataVersion == null ? null : getUnboxedIntArray(metadataVersion.value, "mv");
DexAnnotationElement bytecodeVersion = elementMap.get(kotlin.metadata.bytecodeVersion);
@@ -127,6 +143,14 @@
return KotlinClassMetadata.read(header);
}
+ private static int getKind(Kotlin kotlin, Map<DexString, DexAnnotationElement> elementMap) {
+ DexAnnotationElement kind = elementMap.get(kotlin.metadata.kind);
+ if (kind == null) {
+ throw new MetadataError("element 'k' is missing.");
+ }
+ return (Integer) kind.value.getBoxedValue();
+ }
+
public static KotlinClassLevelInfo createKotlinInfo(
Kotlin kotlin,
DexClass clazz,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
index 5f5b696..9b2939e 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getKotlinLocalOrAnonymousNameFromDescriptor;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
@@ -68,13 +70,8 @@
boolean rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens) {
return type.toRenamedDescriptorOrDefault(
descriptor -> {
- // For local or anonymous classes, the classifier is prefixed with '.' and inner classes
- // are separated with '$'.
- if (isLocalOrAnonymous) {
- visitor.visitClass("." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor));
- } else {
- visitor.visitClass(DescriptorUtils.descriptorToKotlinClassifier(descriptor));
- }
+ visitor.visitClass(
+ getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, isLocalOrAnonymous));
},
appView,
namingLens,
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
index e84f57a..9e79ee0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinDeclarationContainerInfo.java
@@ -56,7 +56,8 @@
DexItemFactory factory,
Reporter reporter,
Consumer<DexEncodedMethod> keepByteCode,
- KotlinJvmSignatureExtensionInformation extensionInformation) {
+ KotlinJvmSignatureExtensionInformation extensionInformation,
+ KotlinMetadataMembersTracker originalAssignmentTracker) {
ImmutableList.Builder<KotlinFunctionInfo> notBackedFunctions = ImmutableList.builder();
int functionCounter = 0;
for (KmFunction kmFunction : container.getFunctions()) {
@@ -88,6 +89,7 @@
}
keepIfInline(kmFunction.getFlags(), method, keepByteCode);
method.setKotlinMemberInfo(kotlinFunctionInfo);
+ originalAssignmentTracker.add(method.getReference());
}
ImmutableList.Builder<KotlinPropertyInfo> notBackedProperties = ImmutableList.builder();
@@ -102,6 +104,7 @@
if (field != null) {
hasBacking = true;
field.setKotlinMemberInfo(kotlinPropertyInfo);
+ originalAssignmentTracker.add(field.getReference());
}
}
if (propertyProcessor.getterSignature() != null) {
@@ -111,6 +114,7 @@
hasBacking = true;
keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode);
method.setKotlinMemberInfo(kotlinPropertyInfo);
+ originalAssignmentTracker.add(method.getReference());
}
}
if (propertyProcessor.setterSignature() != null) {
@@ -120,6 +124,7 @@
hasBacking = true;
keepIfAccessorInline(kmProperty.getGetterFlags(), method, keepByteCode);
method.setKotlinMemberInfo(kotlinPropertyInfo);
+ originalAssignmentTracker.add(method.getReference());
}
}
if (!hasBacking) {
@@ -161,7 +166,8 @@
KmVisitorProviders.KmTypeAliasVisitorProvider typeAliasProvider,
DexClass clazz,
AppView<?> appView,
- NamingLens namingLens) {
+ NamingLens namingLens,
+ KotlinMetadataMembersTracker rewrittenMembersWithKotlinInfo) {
// Type aliases only have a representation here, so we can generate them directly.
boolean rewritten = false;
for (KotlinTypeAliasInfo typeAlias : typeAliases) {
@@ -175,6 +181,7 @@
.computeIfAbsent(
field.getKotlinInfo().asProperty(), ignored -> new KotlinPropertyGroup())
.setBackingField(field);
+ rewrittenMembersWithKotlinInfo.add(field.getReference());
}
}
for (DexEncodedMethod method : clazz.methods()) {
@@ -184,12 +191,14 @@
.getKotlinInfo()
.asFunction()
.rewrite(functionProvider, method, appView, namingLens);
+ rewrittenMembersWithKotlinInfo.add(method.getReference());
continue;
}
KotlinPropertyInfo kotlinPropertyInfo = method.getKotlinInfo().asProperty();
if (kotlinPropertyInfo == null) {
continue;
}
+ rewrittenMembersWithKotlinInfo.add(method.getReference());
KotlinPropertyGroup kotlinPropertyGroup =
properties.computeIfAbsent(kotlinPropertyInfo, ignored -> new KotlinPropertyGroup());
if (method.getReference().proto.returnType == appView.dexItemFactory().voidType) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
index e6a249c..5001c40 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinFunctionInfo.java
@@ -106,7 +106,8 @@
KmFunction kmFunction, DexItemFactory factory) {
String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction);
if (lambdaClassOriginName != null) {
- return KotlinTypeReference.fromBinaryName(lambdaClassOriginName, factory);
+ return KotlinTypeReference.fromBinaryName(
+ lambdaClassOriginName, factory, lambdaClassOriginName);
}
return null;
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
new file mode 100644
index 0000000..88691a9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataMembersTracker.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2021, 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.graph.AppView;
+import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.IterableUtils;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import java.util.Set;
+
+public class KotlinMetadataMembersTracker {
+
+ private int count;
+ // Only used for asserting equality during local testing.
+ private final Set<DexMember<?, ?>> references;
+
+ public KotlinMetadataMembersTracker(AppView<?> appView) {
+ references = appView.options().testing.enableTestAssertions ? Sets.newIdentityHashSet() : null;
+ }
+
+ public void add(DexMember<?, ?> reference) {
+ count += 1;
+ if (references != null) {
+ references.add(reference);
+ }
+ }
+
+ public boolean isEqual(KotlinMetadataMembersTracker tracker, AppView<?> appView) {
+ if (count != tracker.count) {
+ return false;
+ }
+ if (references != null) {
+ assert tracker.references != null;
+ assert references.size() == tracker.references.size();
+ SetView<DexMember<?, ?>> diffComparedToRewritten =
+ Sets.difference(references, tracker.references);
+ if (!diffComparedToRewritten.isEmpty()) {
+ SetView<DexMember<?, ?>> diffComparedToOriginal =
+ Sets.difference(tracker.references, references);
+ // Known kotlin types may not exist directly in the way they are annotated in the metadata.
+ // As an example kotlin.Function2 exists in the metadata but the concrete type is
+ // kotlin.jvm.functions.Function2. As a result we may not rewrite metadata but the
+ // underlying types are changed.
+ diffComparedToRewritten.forEach(
+ diff -> {
+ DexReference rewrittenReference = appView.graphLens().lookupReference(diff);
+ assert diffComparedToOriginal.contains(rewrittenReference);
+ assert IterableUtils.findOrDefault(
+ diff.getReferencedTypes(), type -> isKotlinJvmType(appView, type), null)
+ != null;
+ });
+ }
+ }
+ return true;
+ }
+
+ private boolean isKotlinJvmType(AppView<?> appView, DexType type) {
+ return type.descriptor.startsWith(appView.dexItemFactory().kotlin.kotlinJvmTypePrefix);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
index 7eb45f6..2d6f39a 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataUtils.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -201,4 +202,27 @@
// Check if the type is matched
return proguardKeepRule.getClassNames().matches(factory.kotlinMetadataType);
}
+
+ static String getKotlinClassName(DexClass clazz, String descriptor) {
+ InnerClassAttribute innerClassAttribute = clazz.getInnerClassAttributeForThisClass();
+ if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
+ return DescriptorUtils.descriptorToKotlinClassifier(descriptor);
+ } else if (clazz.isLocalClass() || clazz.isAnonymousClass()) {
+ return getKotlinLocalOrAnonymousNameFromDescriptor(descriptor, true);
+ } else {
+ // We no longer have an innerclass relationship to maintain and we therefore return a binary
+ // name.
+ return DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+ }
+ }
+
+ static String getKotlinLocalOrAnonymousNameFromDescriptor(
+ String descriptor, boolean isLocalOrAnonymous) {
+ // For local or anonymous classes, the classifier is prefixed with '.' and inner classes
+ // are separated with '$'.
+ if (isLocalOrAnonymous) {
+ return "." + DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
+ }
+ return DescriptorUtils.descriptorToKotlinClassifier(descriptor);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
index fbfb3bb..ee9ea2c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataWriter.java
@@ -325,6 +325,22 @@
appendKmType(nextIndent, sb, kmType);
});
});
+ if (kmClass.getInlineClassUnderlyingPropertyName() != null) {
+ appendKeyValue(
+ indent,
+ "inlineClassUnderlyingPropertyName",
+ sb,
+ kmClass.getInlineClassUnderlyingPropertyName());
+ }
+ if (kmClass.getInlineClassUnderlyingType() != null) {
+ appendKeyValue(
+ indent,
+ "inlineClassUnderlyingType",
+ sb,
+ nextIndent -> {
+ appendKmType(nextIndent, sb, kmClass.getInlineClassUnderlyingType());
+ });
+ }
String companionObject = kmClass.getCompanionObject();
appendKeyValue(
indent, "enumEntries", sb, "[" + StringUtils.join(",", kmClass.getEnumEntries()) + "]");
@@ -769,7 +785,7 @@
"arguments",
sb,
nextIndent -> {
- Map<String, KmAnnotationArgument<?>> arguments = kmAnnotation.getArguments();
+ Map<String, KmAnnotationArgument> arguments = kmAnnotation.getArguments();
appendKmList(
nextIndent,
"{ key: String, value: KmAnnotationArgument<?> }",
@@ -795,9 +811,9 @@
}
private static void appendKmArgument(
- String indent, StringBuilder sb, KmAnnotationArgument<?> annotationArgument) {
+ String indent, StringBuilder sb, KmAnnotationArgument annotationArgument) {
if (annotationArgument instanceof KmAnnotationArgument.ArrayValue) {
- List<KmAnnotationArgument<?>> value = ((ArrayValue) annotationArgument).getValue();
+ List<KmAnnotationArgument> value = ((ArrayValue) annotationArgument).getElements();
appendKmList(
indent,
"ArrayValue",
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
index 7088c7f..0545b20 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMultiFileClassFacadeInfo.java
@@ -40,7 +40,7 @@
DexItemFactory factory) {
ImmutableList.Builder<KotlinTypeReference> builder = ImmutableList.builder();
for (String partClassName : kmMultiFileClassFacade.getPartClassNames()) {
- builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory));
+ builder.add(KotlinTypeReference.fromBinaryName(partClassName, factory, partClassName));
}
return new KotlinMultiFileClassFacadeInfo(builder.build(), packageName, metadataVersion);
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
index d28e7c3..fa483ae 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinPackageInfo.java
@@ -27,14 +27,17 @@
private final String moduleName;
private final KotlinDeclarationContainerInfo containerInfo;
private final KotlinLocalDelegatedPropertyInfo localDelegatedProperties;
+ private final KotlinMetadataMembersTracker originalMembersWithKotlinInfo;
private KotlinPackageInfo(
String moduleName,
KotlinDeclarationContainerInfo containerInfo,
- KotlinLocalDelegatedPropertyInfo localDelegatedProperties) {
+ KotlinLocalDelegatedPropertyInfo localDelegatedProperties,
+ KotlinMetadataMembersTracker originalMembersWithKotlinInfo) {
this.moduleName = moduleName;
this.containerInfo = containerInfo;
this.localDelegatedProperties = localDelegatedProperties;
+ this.originalMembersWithKotlinInfo = originalMembersWithKotlinInfo;
}
public static KotlinPackageInfo create(
@@ -51,6 +54,8 @@
for (DexEncodedMethod method : clazz.methods()) {
methodMap.put(toJvmMethodSignature(method.getReference()).asString(), method);
}
+ KotlinMetadataMembersTracker originalMembersWithKotlinInfo =
+ new KotlinMetadataMembersTracker(appView);
return new KotlinPackageInfo(
JvmExtensionsKt.getModuleName(kmPackage),
KotlinDeclarationContainerInfo.create(
@@ -60,14 +65,17 @@
appView.dexItemFactory(),
appView.reporter(),
keepByteCode,
- extensionInformation),
+ extensionInformation,
+ originalMembersWithKotlinInfo),
KotlinLocalDelegatedPropertyInfo.create(
JvmExtensionsKt.getLocalDelegatedProperties(kmPackage),
appView.dexItemFactory(),
- appView.reporter()));
+ appView.reporter()),
+ originalMembersWithKotlinInfo);
}
boolean rewrite(KmPackage kmPackage, DexClass clazz, AppView<?> appView, NamingLens namingLens) {
+ KotlinMetadataMembersTracker rewrittenReferences = new KotlinMetadataMembersTracker(appView);
boolean rewritten =
containerInfo.rewrite(
kmPackage::visitFunction,
@@ -75,7 +83,8 @@
kmPackage::visitTypeAlias,
clazz,
appView,
- namingLens);
+ namingLens,
+ rewrittenReferences);
JvmPackageExtensionVisitor extensionVisitor =
(JvmPackageExtensionVisitor) kmPackage.visitExtensions(JvmPackageExtensionVisitor.TYPE);
rewritten |=
@@ -83,7 +92,7 @@
extensionVisitor::visitLocalDelegatedProperty, appView, namingLens);
extensionVisitor.visitModuleName(moduleName);
extensionVisitor.visitEnd();
- return rewritten;
+ return rewritten || !originalMembersWithKotlinInfo.isEqual(rewrittenReferences, appView);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
index 08e95b3..ee55f8b 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinSyntheticClassInfo.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.utils.Pair;
import kotlinx.metadata.KmLambda;
import kotlinx.metadata.jvm.KotlinClassHeader;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass.Writer;
@@ -55,7 +54,7 @@
? KotlinLambdaInfo.create(
clazz, lambda, appView.dexItemFactory(), appView.reporter(), extensionInformation)
: null,
- getFlavour(syntheticClass, clazz, kotlin),
+ getFlavour(clazz, kotlin),
packageName,
metadataVersion);
}
@@ -64,14 +63,6 @@
return lambda != null && flavour != Flavour.Unclassified;
}
- public boolean isKotlinStyleLambda() {
- return flavour == Flavour.KotlinStyleLambda;
- }
-
- public boolean isJavaStyleLambda() {
- return flavour == Flavour.JavaStyleLambda;
- }
-
@Override
public boolean isSyntheticClass() {
return true;
@@ -112,23 +103,17 @@
return metadataVersion;
}
- public static Flavour getFlavour(
- KotlinClassMetadata.SyntheticClass metadata, DexClass clazz, Kotlin kotlin) {
- // Returns KotlinStyleLambda if the given clazz is a Kotlin-style lambda:
- // a class that
- // 1) is recognized as lambda in its Kotlin metadata;
- // 2) directly extends kotlin.jvm.internal.Lambda
- if (metadata.isLambda() && clazz.superType == kotlin.functional.lambdaType) {
+ public static Flavour getFlavour(DexClass clazz, Kotlin kotlin) {
+ // Returns KotlinStyleLambda if the given clazz has shape of a Kotlin-style lambda:
+ // a class that directly extends kotlin.jvm.internal.Lambda
+ if (clazz.superType == kotlin.functional.lambdaType) {
return Flavour.KotlinStyleLambda;
}
- // Returns JavaStyleLambda if the given clazz is a Java-style lambda:
+ // Returns JavaStyleLambda if the given clazz has shape of a Java-style lambda:
// a class that
- // 1) is recognized as lambda in its Kotlin metadata;
- // 2) doesn't extend any other class;
- // 3) directly implements only one Java SAM.
- if (metadata.isLambda()
- && clazz.superType == kotlin.factory.objectType
- && clazz.interfaces.size() == 1) {
+ // 1) doesn't extend any other class;
+ // 2) directly implements only one Java SAM.
+ if (clazz.superType == kotlin.factory.objectType && clazz.interfaces.size() == 1) {
return Flavour.JavaStyleLambda;
}
return Flavour.Unclassified;
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 4d0d990..4fd93a0 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -4,11 +4,14 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getKotlinLocalOrAnonymousNameFromDescriptor;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -22,28 +25,33 @@
class KotlinTypeReference implements EnqueuerMetadataTraceable {
private final DexType known;
- private final String unknown;
+ private final String originalName;
- private KotlinTypeReference(DexType known) {
+ private KotlinTypeReference(String originalName, DexType known) {
+ this.originalName = originalName;
this.known = known;
- this.unknown = null;
assert known != null;
}
- private KotlinTypeReference(String unknown) {
+ private KotlinTypeReference(String originalName) {
this.known = null;
- this.unknown = unknown;
- assert unknown != null;
+ this.originalName = originalName;
+ assert originalName != null;
}
public DexType getKnown() {
return known;
}
- static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) {
+ public String getOriginalName() {
+ return originalName;
+ }
+
+ static KotlinTypeReference fromBinaryName(
+ String binaryName, DexItemFactory factory, String originalName) {
if (DescriptorUtils.isValidBinaryName(binaryName)) {
return fromDescriptor(
- DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, binaryName);
+ DescriptorUtils.getDescriptorFromClassBinaryName(binaryName), factory, originalName);
}
return new KotlinTypeReference(binaryName);
}
@@ -53,12 +61,12 @@
}
static KotlinTypeReference fromDescriptor(
- String descriptor, DexItemFactory factory, String unknownValue) {
+ String descriptor, DexItemFactory factory, String originalName) {
if (DescriptorUtils.isDescriptor(descriptor)) {
DexType type = factory.createType(descriptor);
- return new KotlinTypeReference(type);
+ return new KotlinTypeReference(originalName, type);
}
- return new KotlinTypeReference(unknownValue);
+ return new KotlinTypeReference(originalName);
}
boolean toRenamedDescriptorOrDefault(
@@ -66,29 +74,44 @@
AppView<?> appView,
NamingLens namingLens,
String defaultValue) {
- if (unknown != null) {
- rewrittenConsumer.accept(unknown);
+ if (known == null) {
+ rewrittenConsumer.accept(originalName);
return false;
}
- assert known != null;
DexType rewrittenType = toRewrittenTypeOrNull(appView, known);
if (rewrittenType == null) {
- rewrittenConsumer.accept(defaultValue);
- return true;
+ String knownDescriptor = known.toDescriptorString();
+ // Static known kotlin types can be pruned without rewriting to Any since the types are known
+ // by kotlinc and kotlin reflect.
+ if (ClassClassifiers.kotlinStaticallyKnownTypes.contains(knownDescriptor)) {
+ rewrittenConsumer.accept(knownDescriptor);
+ return false;
+ } else {
+ rewrittenConsumer.accept(defaultValue);
+ return true;
+ }
}
String renamedString = namingLens.lookupDescriptor(rewrittenType).toString();
rewrittenConsumer.accept(renamedString);
return !known.toDescriptorString().equals(renamedString);
}
+ String toKotlinClassifier(boolean isLocalOrAnonymous) {
+ if (known == null) {
+ return originalName;
+ }
+ return getKotlinLocalOrAnonymousNameFromDescriptor(
+ known.toDescriptorString(), isLocalOrAnonymous);
+ }
+
boolean toRenamedBinaryNameOrDefault(
Consumer<String> rewrittenConsumer,
AppView<?> appView,
NamingLens namingLens,
String defaultValue) {
- if (unknown != null) {
+ if (known == null) {
// Unknown values are always on the input form, so we can just return it.
- rewrittenConsumer.accept(unknown);
+ rewrittenConsumer.accept(originalName);
return false;
}
return toRenamedDescriptorOrDefault(
@@ -126,7 +149,7 @@
@Override
public String toString() {
- return known != null ? known.descriptor.toString() : unknown;
+ return known != null ? known.descriptor.toString() : originalName;
}
@Override
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 820f2a3..c602a1c 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -2171,7 +2171,7 @@
}
public static KotlinCompiler[] getKotlinCompilers() {
- return new KotlinCompiler[] {getKotlinC_1_3_72(), getKotlinC_1_4_20(), getKotlinC_1_5_0_m2()};
+ return new KotlinCompiler[] {getKotlinC_1_4_20(), getKotlinC_1_5_0_m2()};
}
public static void disassemble(AndroidApp app, PrintStream ps) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index cccbde4..9d53d71 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -167,14 +167,14 @@
assertEquals(
DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB) + "/AnnoWithClassArr",
annotation.getClassName());
- Map<String, KmAnnotationArgument<?>> arguments = annotation.getArguments();
+ Map<String, KmAnnotationArgument> arguments = annotation.getArguments();
assertEquals(1, arguments.size());
ArrayValue classes = (ArrayValue) arguments.get("classes");
assertEquals(
- "KClassValue(value=" + foo.getFinalBinaryName() + ")",
- classes.getValue().get(0).toString());
+ "KClassValue(className=" + foo.getFinalBinaryName() + ", arrayDimensionCount=0)",
+ classes.getElements().get(0).toString());
assertEquals(
- "KClassValue(value=" + bar.getFinalBinaryName() + ")",
- classes.getValue().get(1).toString());
+ "KClassValue(className=" + bar.getFinalBinaryName() + ", arrayDimensionCount=0)",
+ classes.getElements().get(1).toString());
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index 605b16c..7939805 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -94,6 +94,7 @@
.addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addKeepAttributeInnerClassesAndEnclosingMethod()
.compile()
.inspect(this::inspect)
.writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 80578a3..370ab75 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -78,6 +78,7 @@
.addKeepAllClassesRule()
.addKeepKotlinMetadata()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addKeepAttributeInnerClassesAndEnclosingMethod()
.allowDiagnosticWarningMessages()
.compile()
.assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))