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