blob: f5ce062970280242fc76cb0c0964d16915dda1f7 [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.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.naming.NamingLens;
import com.android.tools.r8.utils.Reporter;
import java.util.List;
import kotlinx.metadata.KmFunction;
import kotlinx.metadata.KmFunctionVisitor;
import kotlinx.metadata.jvm.JvmExtensionsKt;
import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor;
// Holds information about KmFunction
public final class KotlinFunctionInfo implements KotlinMethodLevelInfo {
// Original flags
private final int flags;
// Original name;
private final String name;
// 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;
// Information about version requirements.
private final KotlinVersionRequirementInfo versionRequirements;
// Kotlin contract information.
private final KotlinContractInfo contract;
// A value describing if any of the parameters are crossinline.
private final boolean crossInlineParameter;
private KotlinFunctionInfo(
int flags,
String name,
KotlinTypeInfo returnType,
KotlinTypeInfo receiverParameterType,
List<KotlinValueParameterInfo> valueParameters,
List<KotlinTypeParameterInfo> typeParameters,
KotlinJvmMethodSignatureInfo signature,
KotlinTypeReference lambdaClassOrigin,
KotlinVersionRequirementInfo versionRequirements,
KotlinContractInfo contract,
boolean crossInlineParameter) {
this.flags = flags;
this.name = name;
this.returnType = returnType;
this.receiverParameterType = receiverParameterType;
this.valueParameters = valueParameters;
this.typeParameters = typeParameters;
this.signature = signature;
this.lambdaClassOrigin = lambdaClassOrigin;
this.versionRequirements = versionRequirements;
this.contract = contract;
this.crossInlineParameter = crossInlineParameter;
}
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.getFlags(),
kmFunction.getName(),
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),
KotlinVersionRequirementInfo.create(kmFunction.getVersionRequirements()),
KotlinContractInfo.create(kmFunction.getContract(), factory, reporter),
isCrossInline);
}
private static KotlinTypeReference getlambdaClassOrigin(
KmFunction kmFunction, DexItemFactory factory) {
String lambdaClassOriginName = JvmExtensionsKt.getLambdaClassOriginName(kmFunction);
if (lambdaClassOriginName != null) {
return KotlinTypeReference.fromBinaryName(lambdaClassOriginName, factory);
}
return null;
}
public void rewrite(
KmVisitorProviders.KmFunctionVisitorProvider visitorProvider,
DexEncodedMethod method,
AppView<?> appView,
NamingLens namingLens) {
// TODO(b/154348683): Check method for flags to pass in.
String finalName = this.name;
if (method != null) {
String methodName = method.method.name.toString();
String rewrittenName = namingLens.lookupName(method.method).toString();
if (!methodName.equals(rewrittenName)) {
finalName = rewrittenName;
}
}
KmFunctionVisitor kmFunction = visitorProvider.get(flags, finalName);
// TODO(b/154348149): ReturnType could have been merged to a subtype.
returnType.rewrite(kmFunction::visitReturnType, appView, namingLens);
for (KotlinValueParameterInfo valueParameterInfo : valueParameters) {
valueParameterInfo.rewrite(kmFunction::visitValueParameter, appView, namingLens);
}
for (KotlinTypeParameterInfo typeParameterInfo : typeParameters) {
typeParameterInfo.rewrite(kmFunction::visitTypeParameter, appView, namingLens);
}
if (receiverParameterType != null) {
receiverParameterType.rewrite(kmFunction::visitReceiverParameterType, appView, namingLens);
}
versionRequirements.rewrite(kmFunction::visitVersionRequirement);
JvmFunctionExtensionVisitor extensionVisitor =
(JvmFunctionExtensionVisitor) kmFunction.visitExtensions(JvmFunctionExtensionVisitor.TYPE);
if (signature != null && extensionVisitor != null) {
extensionVisitor.visit(signature.rewrite(method, appView, namingLens));
}
if (lambdaClassOrigin != null && extensionVisitor != null) {
String lambdaClassOriginName =
lambdaClassOrigin.toRenamedBinaryNameOrDefault(appView, namingLens, null);
if (lambdaClassOriginName != null) {
extensionVisitor.visitLambdaClassOriginName(lambdaClassOriginName);
}
}
contract.rewrite(kmFunction::visitContract, appView, namingLens);
}
@Override
public boolean isFunction() {
return true;
}
@Override
public KotlinFunctionInfo asFunction() {
return this;
}
public boolean isExtensionFunction() {
return receiverParameterType != null;
}
public KotlinJvmMethodSignatureInfo getSignature() {
return signature;
}
@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);
if (signature != null) {
signature.trace(definitionSupplier);
}
if (lambdaClassOrigin != null) {
lambdaClassOrigin.trace(definitionSupplier);
}
contract.trace(definitionSupplier);
}
}