blob: ee55f8b9fa8d605c7c07f78cd3985c6cc09f9900 [file] [log] [blame]
// 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.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.Pair;
import kotlinx.metadata.KmLambda;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass;
import kotlinx.metadata.jvm.KotlinClassMetadata.SyntheticClass.Writer;
// Holds information about a Metadata.SyntheticClass object.
public class KotlinSyntheticClassInfo implements KotlinClassLevelInfo {
private final KotlinLambdaInfo lambda;
private final String packageName;
private final int[] metadataVersion;
public enum Flavour {
KotlinStyleLambda,
JavaStyleLambda,
Unclassified
}
private final Flavour flavour;
private KotlinSyntheticClassInfo(
KotlinLambdaInfo lambda, Flavour flavour, String packageName, int[] metadataVersion) {
this.lambda = lambda;
this.flavour = flavour;
this.packageName = packageName;
this.metadataVersion = metadataVersion;
}
static KotlinSyntheticClassInfo create(
SyntheticClass syntheticClass,
String packageName,
int[] metadataVersion,
DexClass clazz,
Kotlin kotlin,
AppView<?> appView) {
KmLambda lambda = syntheticClass.toKmLambda();
assert lambda == null || syntheticClass.isLambda();
KotlinJvmSignatureExtensionInformation extensionInformation =
KotlinJvmSignatureExtensionInformation.readInformationFromMessage(
syntheticClass, appView.options());
return new KotlinSyntheticClassInfo(
lambda != null
? KotlinLambdaInfo.create(
clazz, lambda, appView.dexItemFactory(), appView.reporter(), extensionInformation)
: null,
getFlavour(clazz, kotlin),
packageName,
metadataVersion);
}
public boolean isLambda() {
return lambda != null && flavour != Flavour.Unclassified;
}
@Override
public boolean isSyntheticClass() {
return true;
}
@Override
public KotlinSyntheticClassInfo asSyntheticClass() {
return this;
}
@Override
public Pair<KotlinClassHeader, Boolean> rewrite(
DexClass clazz, AppView<?> appView, NamingLens namingLens) {
Writer writer = new Writer();
boolean rewritten = false;
if (lambda != null) {
KmLambda kmLambda = new KmLambda();
rewritten = lambda.rewrite(() -> kmLambda, clazz, appView, namingLens);
kmLambda.accept(writer);
}
return Pair.create(writer.write().getHeader(), rewritten);
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
if (lambda != null) {
lambda.trace(definitionSupplier);
}
}
@Override
public String getPackageName() {
return packageName;
}
@Override
public int[] getMetadataVersion() {
return metadataVersion;
}
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 has shape of a Java-style lambda:
// a class that
// 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;
}
}