blob: 0e195e70101b95aa55bc555c22e096f16247de44 [file] [log] [blame]
// Copyright (c) 2019, 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.Kotlin.addKotlinPrefix;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToInternalName;
import static kotlinx.metadata.FlagsKt.flagsOf;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.List;
import kotlinx.metadata.KmFunction;
import kotlinx.metadata.KmType;
import kotlinx.metadata.KmValueParameter;
class KotlinMetadataSynthesizer {
static KmType toKmType(String descriptor) {
KmType kmType = new KmType(flagsOf());
kmType.visitClass(descriptorToInternalName(descriptor));
return kmType;
}
static KmType toRenamedKmType(
DexType type, AppView<AppInfoWithLiveness> appView, NamingLens lens) {
// E.g., [Ljava/lang/String; -> Lkotlin/Array;
if (type.isArrayType()) {
return toKmType(addKotlinPrefix("Array;"));
}
// E.g., void -> Lkotlin/Unit;
if (appView.dexItemFactory().kotlin.knownTypeConversion.containsKey(type)) {
KmType kmType = new KmType(flagsOf());
DexType convertedType = appView.dexItemFactory().kotlin.knownTypeConversion.get(type);
assert convertedType != null;
kmType.visitClass(descriptorToInternalName(convertedType.toDescriptorString()));
return kmType;
}
DexClass clazz = appView.definitionFor(type);
if (clazz == null) {
return null;
}
// For library or classpath class, synthesize @Metadata always.
// For a program class, make sure it is live.
if (!appView.appInfo().isNonProgramTypeOrLiveProgramType(type)) {
return null;
}
DexType renamedType = lens.lookupType(type, appView.dexItemFactory());
// For library or classpath class, we should not have renamed it.
assert clazz.isProgramClass() || renamedType == type
: type.toSourceString() + " -> " + renamedType.toSourceString();
// TODO(b/70169921): Mysterious, why attempts to properly set flags bothers kotlinc?
// and/or why wiping out flags works for KmType but not KmFunction?!
KmType kmType = new KmType(flagsOf());
kmType.visitClass(descriptorToInternalName(renamedType.toDescriptorString()));
return kmType;
}
static KmFunction toRenamedKmFunction(
DexMethod method, AppView<AppInfoWithLiveness> appView, NamingLens lens) {
DexEncodedMethod encodedMethod = appView.definitionFor(method);
if (encodedMethod == null) {
return null;
}
// For library overrides, synthesize @Metadata always.
// For regular methods, make sure it is live.
if (!encodedMethod.isLibraryMethodOverride().isTrue()
&& !appView.appInfo().liveMethods.contains(method)) {
return null;
}
DexMethod renamedMethod = lens.lookupMethod(method, appView.dexItemFactory());
// For a library method override, we should not have renamed it.
assert !encodedMethod.isLibraryMethodOverride().isTrue() || renamedMethod == method
: method.toSourceString() + " -> " + renamedMethod.toSourceString();
// TODO(b/70169921): Consult kotlinx.metadata.Flag.Function for kind (e.g., suspend).
KmFunction kmFunction =
new KmFunction(encodedMethod.accessFlags.getAsKotlinFlags(), renamedMethod.name.toString());
KmType kmReturnType = toRenamedKmType(method.proto.returnType, appView, lens);
assert kmReturnType != null;
kmFunction.setReturnType(kmReturnType);
List<KmValueParameter> parameters = kmFunction.getValueParameters();
for (int i = 0; i < method.proto.parameters.values.length; i++) {
DexType paramType = method.proto.parameters.values[i];
DebugLocalInfo debugLocalInfo = encodedMethod.getParameterInfo().get(i);
String parameterName =
debugLocalInfo != null ? debugLocalInfo.name.toString() : ("p" + i);
// TODO(b/70169921): Consult kotlinx.metadata.Flag.ValueParameter.
KmValueParameter kmValueParameter = new KmValueParameter(flagsOf(), parameterName);
KmType kmParamType = toRenamedKmType(paramType, appView, lens);
assert kmParamType != null;
kmValueParameter.setType(kmParamType);
parameters.add(kmValueParameter);
}
return kmFunction;
}
}