| // 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; |
| } |
| } |