blob: c880a0ebbaa8ebc39893050246f13cfe896189d7 [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 static com.android.tools.r8.kotlin.KotlinMetadataUtils.rewriteIfNotNull;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.rewriteList;
import static com.android.tools.r8.utils.FunctionUtils.forEachApply;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
import java.util.List;
import java.util.function.Consumer;
import kotlin.metadata.KmFunction;
import kotlin.metadata.jvm.JvmExtensionsKt;
// Holds information about KmFunction
public final class KotlinFunctionInfo implements KotlinMethodLevelInfo {
// Original function.
private final KmFunction kmFunction;
// Information from original KmValueParameter(s) if available.
private final List<KotlinValueParameterInfo> valueParameters;
// Information from original KmFunction.returnType. Null if this is from a KmConstructor.
public final KotlinTypeInfo returnType;
// Information from original KmFunction.receiverType. Null if this is from a KmConstructor.
private final KotlinTypeInfo receiverParameterType;
// Information about original type parameters. Null if this is from a KmConstructor.
private final List<KotlinTypeParameterInfo> typeParameters;
// Information about the signature
private final KotlinJvmMethodSignatureInfo signature;
// Information about the lambdaClassOrigin.
private final KotlinTypeReference lambdaClassOrigin;
// Kotlin contract information.
private final KotlinContractInfo contract;
// A value describing if any of the parameters are crossinline.
private final boolean crossInlineParameter;
// Collection of context receiver types
private final List<KotlinTypeInfo> contextReceiverTypes;
private KotlinFunctionInfo(
KmFunction kmFunction,
KotlinTypeInfo returnType,
KotlinTypeInfo receiverParameterType,
List<KotlinValueParameterInfo> valueParameters,
List<KotlinTypeParameterInfo> typeParameters,
KotlinJvmMethodSignatureInfo signature,
KotlinTypeReference lambdaClassOrigin,
KotlinContractInfo contract,
boolean crossInlineParameter,
List<KotlinTypeInfo> contextReceiverTypes) {
this.kmFunction = kmFunction;
this.returnType = returnType;
this.receiverParameterType = receiverParameterType;
this.valueParameters = valueParameters;
this.typeParameters = typeParameters;
this.signature = signature;
this.lambdaClassOrigin = lambdaClassOrigin;
this.contract = contract;
this.crossInlineParameter = crossInlineParameter;
this.contextReceiverTypes = contextReceiverTypes;
}
public boolean hasCrossInlineParameter() {
return crossInlineParameter;
}
static KotlinFunctionInfo create(
KmFunction kmFunction, DexItemFactory factory, Reporter reporter) {
boolean isCrossInline = false;
List<KotlinValueParameterInfo> valueParameters =
KotlinValueParameterInfo.create(kmFunction.getValueParameters(), factory, reporter);
for (KotlinValueParameterInfo valueParameter : valueParameters) {
if (valueParameter.isCrossInline()) {
isCrossInline = true;
break;
}
}
return new KotlinFunctionInfo(
kmFunction,
KotlinTypeInfo.create(kmFunction.getReturnType(), factory, reporter),
KotlinTypeInfo.create(kmFunction.getReceiverParameterType(), factory, reporter),
valueParameters,
KotlinTypeParameterInfo.create(kmFunction.getTypeParameters(), factory, reporter),
KotlinJvmMethodSignatureInfo.create(JvmExtensionsKt.getSignature(kmFunction), factory),
getlambdaClassOrigin(kmFunction, factory),
KotlinContractInfo.create(kmFunction.getContract(), factory, reporter),
isCrossInline,
ListUtils.map(
kmFunction.getContextReceiverTypes(),
contextReceiverType -> KotlinTypeInfo.create(contextReceiverType, factory, reporter)));
}
private static KotlinTypeReference getlambdaClassOrigin(
KmFunction kmFunction, DexItemFactory factory) {
String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction);
if (lambdaClassOriginName != null) {
return KotlinTypeReference.fromBinaryNameOrKotlinClassifier(
lambdaClassOriginName, factory, lambdaClassOriginName);
}
return null;
}
public String getName() {
return kmFunction.getName();
}
boolean rewriteNoBacking(Consumer<KmFunction> consumer, AppView<?> appView) {
return rewrite(consumer, null, appView);
}
boolean rewrite(Consumer<KmFunction> consumer, DexEncodedMethod method, AppView<?> appView) {
// TODO(b/154348683): Check method for flags to pass in.
boolean rewritten = false;
String finalName = getName();
// Only rewrite the kotlin method name if it was equal to the method name when reading the
// metadata.
if (method != null) {
String methodName = method.getReference().name.toString();
String rewrittenName = appView.getNamingLens().lookupName(method.getReference()).toString();
if (!methodName.equals(rewrittenName)) {
rewritten = true;
finalName = rewrittenName;
}
}
KmFunction rewrittenKmFunction = new KmFunction(finalName);
consumer.accept(rewrittenKmFunction);
KotlinFlagUtils.copyAllFlags(kmFunction, rewrittenKmFunction);
// TODO(b/154348149): ReturnType could have been merged to a subtype.
rewritten |= returnType.rewrite(rewrittenKmFunction::setReturnType, appView);
rewritten |=
rewriteList(
appView,
valueParameters,
rewrittenKmFunction.getValueParameters(),
KotlinValueParameterInfo::rewrite);
rewritten |=
rewriteList(
appView,
typeParameters,
rewrittenKmFunction.getTypeParameters(),
KotlinTypeParameterInfo::rewrite);
rewritten |=
rewriteList(
appView,
contextReceiverTypes,
rewrittenKmFunction.getContextReceiverTypes(),
KotlinTypeInfo::rewrite);
rewritten |=
rewriteIfNotNull(
appView,
receiverParameterType,
rewrittenKmFunction::setReceiverParameterType,
KotlinTypeInfo::rewrite);
rewrittenKmFunction.getVersionRequirements().addAll(kmFunction.getVersionRequirements());
if (signature != null) {
rewritten |=
signature.rewrite(
signature -> JvmExtensionsKt.setSignature(rewrittenKmFunction, signature),
method,
appView);
}
if (lambdaClassOrigin != null) {
rewritten |=
lambdaClassOrigin.toRenamedBinaryNameOrDefault(
lambdaClassOriginName -> {
if (lambdaClassOriginName != null) {
JvmExtensionsKt.setLambdaClassOriginName(
rewrittenKmFunction, lambdaClassOriginName);
}
},
appView,
null);
}
rewritten |= contract.rewrite(rewrittenKmFunction::setContract, appView);
return rewritten;
}
@Override
public boolean isFunction() {
return true;
}
@Override
public KotlinFunctionInfo asFunction() {
return this;
}
public boolean isExtensionFunction() {
return receiverParameterType != null;
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
forEachApply(valueParameters, param -> param::trace, definitionSupplier);
returnType.trace(definitionSupplier);
if (receiverParameterType != null) {
receiverParameterType.trace(definitionSupplier);
}
forEachApply(typeParameters, param -> param::trace, definitionSupplier);
forEachApply(contextReceiverTypes, type -> type::trace, definitionSupplier);
if (signature != null) {
signature.trace(definitionSupplier);
}
if (lambdaClassOrigin != null) {
lambdaClassOrigin.trace(definitionSupplier);
}
contract.trace(definitionSupplier);
}
}