blob: 8c4ccafee007f992f98bbd5e4061c6c6d9d3d8a3 [file] [log] [blame]
// Copyright (c) 2018, 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.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata;
public final class KotlinSyntheticClass extends KotlinInfo<KotlinClassMetadata.SyntheticClass> {
// TODO(b/151194794): Once converted to internal data structure, this can be gone.
private KotlinClassMetadata.SyntheticClass metadata;
public enum Flavour {
KotlinStyleLambda,
JavaStyleLambda,
Unclassified
}
private final Flavour flavour;
static KotlinSyntheticClass fromKotlinClassMetadata(
KotlinClassMetadata kotlinClassMetadata, Kotlin kotlin, DexClass clazz) {
assert kotlinClassMetadata instanceof KotlinClassMetadata.SyntheticClass;
KotlinClassMetadata.SyntheticClass syntheticClass =
(KotlinClassMetadata.SyntheticClass) kotlinClassMetadata;
if (isKotlinStyleLambda(syntheticClass, kotlin, clazz)) {
return new KotlinSyntheticClass(Flavour.KotlinStyleLambda, syntheticClass, clazz);
} else if (isJavaStyleLambda(syntheticClass, kotlin, clazz)) {
return new KotlinSyntheticClass(Flavour.JavaStyleLambda, syntheticClass, clazz);
} else {
return new KotlinSyntheticClass(Flavour.Unclassified, syntheticClass, clazz);
}
}
private KotlinSyntheticClass(
Flavour flavour, KotlinClassMetadata.SyntheticClass metadata, DexClass clazz) {
super(metadata, clazz);
this.flavour = flavour;
}
@Override
void processMetadata(KotlinClassMetadata.SyntheticClass metadata) {
this.metadata = metadata;
if (metadata.isLambda()) {
// TODO(b/151194794): Use #toKmLambda to store a mutable model if needed.
}
}
@Override
void rewrite(AppView<AppInfoWithLiveness> appView, NamingLens lens) {
// TODO(b/151194794): no idea yet!
assert lens.lookupType(clazz.type, appView.dexItemFactory()) == clazz.type
|| appView.options().enableKotlinMetadataRewritingForRenamedClasses
: toString();
}
@Override
KotlinClassHeader createHeader() {
// TODO(b/151194794): may need to update if `rewrite` is implemented.
return metadata.getHeader();
}
public boolean isLambda() {
return isKotlinStyleLambda() || isJavaStyleLambda();
}
public boolean isKotlinStyleLambda() {
return flavour == Flavour.KotlinStyleLambda;
}
public boolean isJavaStyleLambda() {
return flavour == Flavour.JavaStyleLambda;
}
@Override
public final Kind getKind() {
return Kind.Synthetic;
}
@Override
public final boolean isSyntheticClass() {
return true;
}
@Override
public KotlinSyntheticClass asSyntheticClass() {
return this;
}
/**
* Returns {@code true} if the given {@link DexClass} is a Kotlin-style lambda:
* a class that
* 1) is recognized as lambda in its Kotlin metadata;
* 2) directly extends kotlin.jvm.internal.Lambda
*/
private static boolean isKotlinStyleLambda(
KotlinClassMetadata.SyntheticClass metadata, Kotlin kotlin, DexClass clazz) {
return metadata.isLambda()
&& clazz.superType == kotlin.functional.lambdaType;
}
/**
* Returns {@code true} if the given {@link DexClass} is 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.
*/
private static boolean isJavaStyleLambda(
KotlinClassMetadata.SyntheticClass metadata, Kotlin kotlin, DexClass clazz) {
return metadata.isLambda()
&& clazz.superType == kotlin.factory.objectType
&& clazz.interfaces.size() == 1;
}
@Override
public String toString(String indent) {
return indent + "Metadata.SyntheticClass { function: " + metadata.toString() + "}";
}
}