
org.jetbrains.kotlin.fir.backend.jvm.FirJvmMangleComputer.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.backend.jvm
import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleMode
import org.jetbrains.kotlin.backend.common.serialization.mangle.collectForMangler
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
open class FirJvmMangleComputer(
private val builder: StringBuilder,
private val mode: MangleMode,
private val session: FirSession
) : FirVisitor(), KotlinMangleComputer {
private val typeParameterContainer = ArrayList(4)
private var isRealExpect = false
open fun FirFunction<*>.platformSpecificFunctionName(): String? = null
open fun FirFunction<*>.specialValueParamPrefix(param: FirValueParameter): String = ""
private fun addReturnType(): Boolean = false
override fun copy(newMode: MangleMode): FirJvmMangleComputer =
FirJvmMangleComputer(builder, newMode, session)
private fun StringBuilder.appendName(s: String) {
if (mode.fqn) {
append(s)
}
}
private fun StringBuilder.appendName(c: Char) {
if (mode.fqn) {
append(c)
}
}
private fun StringBuilder.appendSignature(s: String) {
if (mode.signature) {
append(s)
}
}
private fun StringBuilder.appendSignature(c: Char) {
if (mode.signature) {
append(c)
}
}
private fun StringBuilder.appendSignature(i: Int) {
if (mode.signature) {
append(i)
}
}
private fun FirDeclaration.visitParent() {
val (parentPackageFqName, parentClassId) = when (this) {
is FirCallableMemberDeclaration<*> -> this.containingClass()?.classId?.let { it.packageFqName to it } ?: return
is FirClassLikeDeclaration<*> -> this.symbol.classId.let { it.packageFqName to it.outerClassId }
else -> return
}
if (parentClassId != null && !parentClassId.isLocal) {
val parentClassLike = this@FirJvmMangleComputer.session.firSymbolProvider.getClassLikeSymbolByFqName(parentClassId)?.fir
?: error("Attempt to find parent ($parentClassId) for probably-local declaration!")
if (parentClassLike is FirRegularClass || parentClassLike is FirTypeAlias) {
parentClassLike.accept(this@FirJvmMangleComputer, false)
} else {
error("Strange class-like declaration: ${parentClassLike.render()}")
}
} else if (parentClassId == null && !parentPackageFqName.isRoot) {
builder.appendName(parentPackageFqName.asString())
}
}
private fun FirDeclaration.mangleSimpleDeclaration(name: String) {
val l = builder.length
visitParent()
if (builder.length != l) {
builder.appendName(MangleConstant.FQN_SEPARATOR)
}
builder.appendName(name)
}
private fun FirFunction<*>.mangleFunction(isCtor: Boolean, isStatic: Boolean, container: FirDeclaration) {
isRealExpect = isRealExpect || (this as? FirMemberDeclaration)?.isExpect == true
if (container is FirMemberDeclaration) {
typeParameterContainer.add(container)
}
visitParent()
builder.appendName(MangleConstant.FUNCTION_NAME_PREFIX)
platformSpecificFunctionName()?.let {
builder.append(it)
return
}
val name = (this as? FirSimpleFunction)?.name ?: Name.special("")
builder.append(name.asString())
mangleSignature(isCtor, isStatic)
}
private fun FirFunction<*>.mangleSignature(isCtor: Boolean, isStatic: Boolean) {
if (!mode.signature) {
return
}
if (isStatic) {
builder.appendSignature(MangleConstant.STATIC_MEMBER_MARK)
}
receiverTypeRef?.let {
builder.appendSignature(MangleConstant.EXTENSION_RECEIVER_PREFIX)
mangleType(builder, it.coneType)
}
valueParameters.collectForMangler(builder, MangleConstant.VALUE_PARAMETERS) {
appendSignature(specialValueParamPrefix(it))
mangleValueParameter(this, it)
}
typeParameters.filterIsInstance().withIndex().toList()
.collectForMangler(builder, MangleConstant.TYPE_PARAMETERS) { (index, typeParameter) ->
mangleTypeParameter(this, typeParameter, index)
}
if (!isCtor && !returnTypeRef.isUnit && addReturnType()) {
mangleType(builder, returnTypeRef.coneType)
}
}
private fun FirTypeParameter.effectiveParent(): FirMemberDeclaration {
for (parent in typeParameterContainer) {
if (this in parent.typeParameters) {
return parent
}
if (parent is FirCallableDeclaration<*>) {
val overriddenFir = parent.originalForSubstitutionOverride
if (overriddenFir is FirTypeParametersOwner && this in overriddenFir.typeParameters) {
return parent
}
}
}
throw IllegalStateException("Should not be here!")
}
private fun mangleValueParameter(vpBuilder: StringBuilder, param: FirValueParameter) {
mangleType(vpBuilder, param.returnTypeRef.coneType)
if (param.isVararg) {
vpBuilder.appendSignature(MangleConstant.VAR_ARG_MARK)
}
}
private fun mangleTypeParameter(tpBuilder: StringBuilder, param: FirTypeParameter, index: Int) {
tpBuilder.appendSignature(index)
tpBuilder.appendSignature(MangleConstant.UPPER_BOUND_SEPARATOR)
param.bounds.map { it.coneType }.collectForMangler(tpBuilder, MangleConstant.UPPER_BOUNDS) {
mangleType(this, it)
}
}
private fun StringBuilder.mangleTypeParameterReference(typeParameter: FirTypeParameter) {
val parent = typeParameter.effectiveParent()
val ci = typeParameterContainer.indexOf(parent)
require(ci >= 0) { "No type container found for ${typeParameter.render()}" }
appendSignature(ci)
appendSignature(MangleConstant.INDEX_SEPARATOR)
appendSignature(parent.typeParameters.indexOf(typeParameter))
}
private fun mangleType(tBuilder: StringBuilder, type: ConeKotlinType) {
when (type) {
is ConeLookupTagBasedType -> {
when (val symbol = type.lookupTag.toSymbol(session)) {
is FirTypeAliasSymbol -> {
mangleType(tBuilder, type.fullyExpandedType(session))
return
}
is FirClassSymbol -> symbol.fir.accept(copy(MangleMode.FQNAME), false)
is FirTypeParameterSymbol -> tBuilder.mangleTypeParameterReference(symbol.fir)
}
type.typeArguments.asList().ifNotEmpty {
collectForMangler(tBuilder, MangleConstant.TYPE_ARGUMENTS) { arg ->
when (arg) {
is ConeStarProjection -> appendSignature(MangleConstant.STAR_MARK)
is ConeKotlinTypeProjection -> {
if (arg.kind != ProjectionKind.INVARIANT) {
appendSignature(arg.kind.name.toLowerCase())
appendSignature(MangleConstant.VARIANCE_SEPARATOR)
}
mangleType(this, arg.type)
}
}
}
}
if (type.isMarkedNullable) {
tBuilder.appendSignature(MangleConstant.Q_MARK)
}
if (type.hasEnhancedNullability) {
tBuilder.appendSignature(MangleConstant.ENHANCED_NULLABILITY_MARK)
}
}
is ConeFlexibleType -> {
// TODO: is that correct way to mangle flexible type?
with(MangleConstant.FLEXIBLE_TYPE) {
tBuilder.appendSignature(prefix)
mangleType(tBuilder, type.lowerBound)
tBuilder.appendSignature(separator)
mangleType(tBuilder, type.upperBound)
tBuilder.appendSignature(suffix)
}
}
is ConeDefinitelyNotNullType -> {
// E.g. not-null type parameter in Java
mangleType(tBuilder, type.original)
}
is ConeCapturedType -> {
mangleType(tBuilder, type.lowerType ?: type.constructor.supertypes!!.first())
}
else -> error("Unexpected type $type")
}
}
override fun visitElement(element: FirElement, data: Boolean) = error("unexpected element ${element.render()}")
override fun visitRegularClass(regularClass: FirRegularClass, data: Boolean) {
isRealExpect = isRealExpect or regularClass.isExpect
typeParameterContainer.add(regularClass)
regularClass.mangleSimpleDeclaration(regularClass.name.asString())
}
override fun visitProperty(property: FirProperty, data: Boolean) {
isRealExpect = isRealExpect or property.isExpect
typeParameterContainer.add(property)
property.visitParent()
val isStaticProperty = property.isStatic
if (isStaticProperty) {
builder.appendSignature(MangleConstant.STATIC_MEMBER_MARK)
}
property.receiverTypeRef?.let {
builder.appendSignature(MangleConstant.EXTENSION_RECEIVER_PREFIX)
mangleType(builder, it.coneType)
}
property.typeParameters.withIndex().toList().collectForMangler(builder, MangleConstant.TYPE_PARAMETERS) { (index, typeParameter) ->
mangleTypeParameter(this, typeParameter, index)
}
builder.append(property.name.asString())
}
override fun visitField(field: FirField, data: Boolean) =
field.mangleSimpleDeclaration(field.name.asString())
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Boolean) {
enumEntry.mangleSimpleDeclaration(enumEntry.name.asString())
}
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: Boolean) =
typeAlias.mangleSimpleDeclaration(typeAlias.name.asString())
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Boolean) {
isRealExpect = isRealExpect || simpleFunction.isExpect
val isStatic = simpleFunction.isStatic
simpleFunction.mangleFunction(false, isStatic, simpleFunction)
}
override fun visitConstructor(constructor: FirConstructor, data: Boolean) =
constructor.mangleFunction(isCtor = true, isStatic = false, constructor)
override fun computeMangle(declaration: FirDeclaration): String {
declaration.accept(this, true)
return builder.toString()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy