[IR] Partial linkage: report the exact IR element where unlinked symbols are used

This commit is contained in:
Dmitriy Dolovov
2022-08-01 14:18:23 +02:00
parent bd3e3e2524
commit 12c6015d5e
2 changed files with 331 additions and 147 deletions
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.backend.common.serialization.unlinked
import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageSupport.UnlinkedMarkerTypeHandler
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedIrElementRenderer.appendDeclaration
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedIrElementRenderer.renderError
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.Companion.isUnlinked
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
@@ -22,9 +24,10 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.IrMessageLogger.Location
import org.jetbrains.kotlin.ir.util.IrMessageLogger.Severity
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addIfNotNull
internal class UnlinkedDeclarationsProcessor(
private val builtIns: IrBuiltIns,
@@ -32,14 +35,9 @@ internal class UnlinkedDeclarationsProcessor(
private val unlinkedMarkerTypeHandler: UnlinkedMarkerTypeHandler,
private val messageLogger: IrMessageLogger
) {
companion object {
private val ERROR_ORIGIN = object : IrStatementOriginImpl("LINKAGE ERROR") {}
}
fun addLinkageErrorIntoUnlinkedClasses() {
usedClassifierSymbols.forEachClassSymbolToPatch { unlinkedSymbol ->
val clazz = unlinkedSymbol.owner
clazz.reportUnlinkedSymbolsWarning("Class", clazz.fqNameForIrSerialization)
val anonInitializer = clazz.declarations.firstNotNullOfOrNull { it as? IrAnonymousInitializer }
?: builtIns.irFactory.createAnonymousInitializer(
@@ -53,38 +51,12 @@ internal class UnlinkedDeclarationsProcessor(
clazz.declarations.add(it)
}
anonInitializer.body.statements.clear()
anonInitializer.body.statements.add(clazz.throwLinkageError(clazz.symbol))
anonInitializer.body.statements += clazz.throwLinkageError() // TODO: which exactly classifiers are unlinked?
clazz.superTypes = clazz.superTypes.filter { !it.isUnlinked() }
}
}
private fun IrDeclaration.location(): IrMessageLogger.Location? = fileOrNull?.location(startOffset)
private fun IrFile.location(offset: Int): IrMessageLogger.Location {
val module = module.name
val fileEntry = fileEntry
val fileName = fileEntry.name
val lineNumber = fileEntry.getLineNumber(offset) + 1 // since humans count from 1, not 0
val columnNumber = fileEntry.getColumnNumber(offset) + 1
// unsure whether should module name be added here
return IrMessageLogger.Location("$module @ $fileName", lineNumber, columnNumber)
}
private fun IrDeclaration.reportUnlinkedSymbolsWarning(kind: String, fqn: FqName, localName: Name? = null) =
reportWarning(
buildString {
append(kind).append(" declaration ")
if (localName != null) append(localName.asString()).append(" at ")
append(fqn.asString()).append(" contains unlinked symbols")
},
location()
)
private fun reportWarning(message: String, location: IrMessageLogger.Location?) {
messageLogger.report(IrMessageLogger.Severity.WARNING, message, location)
}
fun signatureTransformer(): IrElementTransformerVoid = SignatureTransformer()
private inner class SignatureTransformer : IrElementTransformerVoid() {
@@ -117,10 +89,8 @@ internal class UnlinkedDeclarationsProcessor(
override fun visitField(declaration: IrField): IrStatement {
if (declaration.type.isUnlinked()) {
val fqn = declaration.correspondingPropertySymbol?.owner?.fqNameWhenAvailable ?: declaration.fqNameForIrSerialization
val kind = if (declaration.correspondingPropertySymbol != null) "Property" else "Field"
declaration.reportUnlinkedSymbolsWarning(kind, fqn)
// TODO: it would be more precise to use the set of unlinked symbols than a collection of unlinked types here.
declaration.logLinkageError(listOfNotNull((declaration.type as? IrSimpleType)?.classifier))
declaration.type = unlinkedMarkerTypeHandler.unlinkedMarkerType
declaration.initializer = null
} else {
@@ -131,11 +101,8 @@ internal class UnlinkedDeclarationsProcessor(
override fun visitVariable(declaration: IrVariable): IrStatement {
if (declaration.type.isUnlinked()) {
val fqn = declaration.parent.fqNameForIrSerialization
val localName = declaration.name
val kind = if (declaration.isVar) "var" else "val"
declaration.reportUnlinkedSymbolsWarning(kind, fqn, localName)
// TODO: it would be more precise to use the set of unlinked symbols than a collection of unlinked types here.
declaration.logLinkageError(listOfNotNull((declaration.type as? IrSimpleType)?.classifier))
declaration.type = unlinkedMarkerTypeHandler.unlinkedMarkerType
declaration.initializer = null
} else {
@@ -199,37 +166,23 @@ internal class UnlinkedDeclarationsProcessor(
if (!isImplementedFakeOverride && removedUnlinkedTypes.isEmpty()) {
transformChildrenVoid()
} else {
val functionKind = when {
this@transformBodyIfNecessary is IrSimpleFunction && correspondingPropertySymbol != null -> "property accessor"
this@transformBodyIfNecessary is IrConstructor -> "constructor"
else -> "function"
}
val errorMessages = listOfNotNull(
if (isImplementedFakeOverride)
buildString {
append("Abstract ").append(functionKind).append(" ")
append(fqNameForIrSerialization.asString())
append(" is not implemented in non-abstract class ")
append(parent.fqNameForIrSerialization.asString())
append("Abstract ").appendDeclaration(this@transformBodyIfNecessary)
append(" is not implemented in non-abstract ").appendDeclaration(parentAsClass)
}
else null,
if (removedUnlinkedTypes.isNotEmpty())
buildString {
append("The signature of ").append(functionKind).append(" ")
append(fqNameForIrSerialization.asString())
append(" contains unlinked symbols: ")
removedUnlinkedTypes.joinTo(this) { it.render() }
}
else null
if (removedUnlinkedTypes.isNotEmpty()) {
// TODO: it would be more precise to use the set of unlinked symbols than a collection of unlinked types here.
composeUnlinkedSymbolsErrorMessage(removedUnlinkedTypes.mapNotNull { (it as? IrSimpleType)?.classifier })
} else null
)
errorMessages.forEach { reportWarning(it, location()) }
body?.let { body ->
val bb = body as IrBlockBody
bb.statements.clear()
bb.statements.add(throwLinkageError(unlinkedSymbol = null, errorMessages.joinToString(separator = "; ")))
bb.statements += throwLinkageError(errorMessages, location())
}
}
@@ -240,7 +193,7 @@ internal class UnlinkedDeclarationsProcessor(
private fun IrSymbol.isUnlinked(): Boolean {
if (!isBound) return true
when (this) {
is IrClassifierSymbol -> this.isUnlinked()
is IrClassifierSymbol -> isUnlinked()
is IrPropertySymbol -> {
owner.getter?.let { if (it.symbol.isUnlinked()) return true }
owner.setter?.let { if (it.symbol.isUnlinked()) return true }
@@ -280,14 +233,36 @@ internal class UnlinkedDeclarationsProcessor(
return with(unlinkedMarkerTypeHandler) { isUnlinkedMarkerType() }
}
private fun IrElement.throwLinkageError(unlinkedSymbol: IrSymbol?, message: String = "Unlinked IR symbol"): IrCall {
val messageLiteral = message + unlinkedSymbol?.signature?.render()?.let { " $it" }.orEmpty()
private fun IrElement.composeUnlinkedSymbolsErrorMessage(unlinkedSymbols: Collection<IrSymbol>) =
renderError(this@composeUnlinkedSymbolsErrorMessage, unlinkedSymbols)
private fun IrDeclaration.throwLinkageError(unlinkedSymbols: Collection<IrSymbol> = emptyList()): IrCall =
throwLinkageError(
messages = listOf(composeUnlinkedSymbolsErrorMessage(unlinkedSymbols)),
location = location()
)
private fun IrElement.throwLinkageError(messages: List<String>, location: Location?): IrCall {
check(messages.isNotEmpty())
messages.forEach { logLinkageError(it, location) }
val irCall = IrCallImpl(startOffset, endOffset, builtIns.nothingType, builtIns.linkageErrorSymbol, 0, 1, ERROR_ORIGIN)
irCall.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, messageLiteral))
irCall.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, messages.joinToString("\n")))
return irCall
}
private fun IrDeclaration.logLinkageError(unlinkedSymbols: Collection<IrSymbol>) {
logLinkageError(
composeUnlinkedSymbolsErrorMessage(unlinkedSymbols),
location()
)
}
private fun logLinkageError(message: String, location: Location?) {
messageLogger.report(Severity.WARNING, message, location) // It's OK. We log it as a warning.
}
fun usageTransformer(): IrElementTransformerVoid = UsageTransformer()
private inner class UsageTransformer : IrElementTransformerVoid() {
@@ -302,118 +277,106 @@ internal class UnlinkedDeclarationsProcessor(
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
expression.transformChildrenVoid()
val checkType = expression.typeOperandClassifier
if (!checkType.isUnlinked()) return expression
reportWarning(
"TypeOperator contains unlinked symbol ${checkType.signature?.render() ?: ""}",
currentFile?.location(expression.startOffset)
)
val composite = IrCompositeImpl(expression.startOffset, expression.endOffset, builtIns.nothingType)
composite.statements.add(expression.argument)
composite.statements.add(expression.throwLinkageError(expression.typeOperandClassifier))
return composite
val classifierSymbol = expression.typeOperandClassifier
return if (classifierSymbol.isUnlinked())
IrCompositeImpl(expression.startOffset, expression.endOffset, builtIns.nothingType).apply {
statements += expression.argument
statements += expression.throwLinkageError(classifierSymbol)
}
else
expression
}
override fun visitExpression(expression: IrExpression): IrExpression {
if (expression.type.isUnlinked() || expression.type.isUnlinkedMarkerType()) {
reportWarning("Expression type contains unlinked symbol", currentFile?.location(expression.startOffset))
return expression.throwLinkageError(unlinkedSymbol = null, "Unlinked type of IR expression")
}
return super.visitExpression(expression)
return if (expression.type.isUnlinked() || expression.type.isUnlinkedMarkerType())
expression.throwLinkageError() // TODO: which exactly classifiers are unlinked?
else
super.visitExpression(expression)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression {
expression.transformChildrenVoid()
val symbol = expression.symbol
if (!symbol.isUnlinked() && !expression.type.isUnlinked()) return expression
return if (!expression.symbol.isUnlinked() && !expression.type.isUnlinked())
expression
else
IrCompositeImpl(expression.startOffset, expression.endOffset, builtIns.nothingType, expression.origin).apply {
statements.addIfNotNull(expression.dispatchReceiver)
statements.addIfNotNull(expression.extensionReceiver)
reportWarning(
"Accessing declaration with unlinked symbol ${symbol.signature?.render() ?: ""}",
currentFile?.location(expression.startOffset)
)
for (i in 0 until expression.valueArgumentsCount) {
statements.addIfNotNull(expression.getValueArgument(i))
}
val composite = IrCompositeImpl(expression.startOffset, expression.endOffset, builtIns.nothingType, expression.origin)
expression.dispatchReceiver?.let { composite.statements.add(it) }
expression.extensionReceiver?.let { composite.statements.add(it) }
for (i in 0 until expression.valueArgumentsCount) {
val arg = expression.getValueArgument(i)
arg?.let { composite.statements.add(it) }
}
composite.statements.add(
if (!symbol.isBound)
expression.throwLinkageError(symbol)
else
expression.throwLinkageError(symbol, "Unlinked type in signature of IR symbol")
)
return composite
statements += expression.throwLinkageError() // TODO: which exactly classifiers are unlinked?
}
}
override fun visitFieldAccess(expression: IrFieldAccessExpression): IrExpression {
expression.transformChildrenVoid()
val symbol = expression.symbol
if (!symbol.isUnlinked()) {
return expression
}
reportWarning(
"Accessing field contains unlinked symbol ${symbol.signature?.render()}",
currentFile?.location(expression.startOffset)
)
val composite = IrCompositeImpl(expression.startOffset, expression.endOffset, builtIns.nothingType, expression.origin)
expression.receiver?.let { composite.statements.add(it) }
if (expression is IrSetField) {
composite.statements.add(expression.value)
}
composite.statements.add(
if (!symbol.isBound)
expression.throwLinkageError(symbol)
else
expression.throwLinkageError(symbol, "Field type is unlinked in IR symbol")
)
return composite
return if (!expression.symbol.isUnlinked())
expression
else
IrCompositeImpl(expression.startOffset, expression.endOffset, builtIns.nothingType, expression.origin).apply {
statements.addIfNotNull(expression.receiver)
if (expression is IrSetField)
statements += expression.value
statements += expression.throwLinkageError(expression.symbol)
}
}
override fun visitClassReference(expression: IrClassReference): IrExpression {
if (expression.symbol.isUnlinked()) {
reportWarning(
"Accessing class contains unlinked symbol ${expression.symbol.signature?.render()}",
currentFile?.location(expression.startOffset)
)
return expression.throwLinkageError(expression.symbol)
}
return expression
return if (expression.symbol.isUnlinked())
expression.throwLinkageError(expression.symbol)
else
expression
}
override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid()
fun <S : IrSymbol> IrOverridableDeclaration<S>.filterOverriddens() {
fun <S : IrSymbol> IrOverridableDeclaration<S>.filterOverriddenSymbols() {
overriddenSymbols = overriddenSymbols.filter { it.isBound }
}
for (member in declaration.declarations) {
when (member) {
is IrSimpleFunction -> member.filterOverriddens()
is IrSimpleFunction -> member.filterOverriddenSymbols()
is IrProperty -> {
member.filterOverriddens()
member.getter?.filterOverriddens()
member.setter?.filterOverriddens()
member.filterOverriddenSymbols()
member.getter?.filterOverriddenSymbols()
member.setter?.filterOverriddenSymbols()
}
}
}
return declaration
}
private fun IrExpression.throwLinkageError(unlinkedSymbol: IrSymbol? = null): IrCall =
throwLinkageError(
messages = listOf(composeUnlinkedSymbolsErrorMessage(listOfNotNull(unlinkedSymbol))),
location = locationIn(currentFile)
)
}
}
companion object {
private val ERROR_ORIGIN = object : IrStatementOriginImpl("LINKAGE ERROR") {}
}
}
private fun IrDeclaration.location(): Location? = locationIn(fileOrNull)
private fun IrElement.locationIn(currentFile: IrFile?): Location? {
if (currentFile == null) return null
val moduleName = currentFile.module.name
val fileEntry = currentFile.fileEntry
val fileName = fileEntry.name
val lineNumber = fileEntry.getLineNumber(startOffset) + 1 // since humans count from 1, not 0
val columnNumber = fileEntry.getColumnNumber(startOffset) + 1
// unsure whether should module name be added here
return Location("$moduleName @ $fileName", lineNumber, columnNumber)
}
@@ -0,0 +1,221 @@
/*
* Copyright 2010-2022 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.backend.common.serialization.unlinked
import org.jetbrains.kotlin.backend.common.serialization.unlinked.DeclarationKind.*
import org.jetbrains.kotlin.backend.common.serialization.unlinked.ExpressionKind.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.IdSignature.*
import org.jetbrains.kotlin.ir.util.isAnonymousObject
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
// TODO: Consider getting rid of this class when new self-descriptive signatures are implemented.
internal object UnlinkedIrElementRenderer {
fun StringBuilder.appendDeclaration(declaration: IrDeclaration): StringBuilder = appendDeclaration(
declarationKind = declaration.declarationKind,
declarationName = declaration.symbol.guessName()
)
private fun StringBuilder.appendDeclaration(declarationKind: DeclarationKind, declarationName: String?): StringBuilder {
append(declarationKind)
if (declarationKind != ANONYMOUS_OBJECT) {
// This is a declaration NOT under a property.
appendWithWhitespaceBefore(declarationName ?: UNKNOWN_NAME)
}
return this
}
fun renderError(element: IrElement, unlinkedSymbols: Collection<IrSymbol>): String = buildString {
when (element) {
is IrDeclaration -> appendDeclaration(element)
is IrExpression -> {
val (expressionKind, referencedDeclarationKind) = element.expression
appendWithWhitespaceAfter(expressionKind.displayName)
if (referencedDeclarationKind != null) {
val referencedDeclarationSymbol = when (element) {
is IrDeclarationReference -> element.symbol
is IrInstanceInitializerCall -> element.classSymbol
else -> null
}
val referencedDeclaration = referencedDeclarationSymbol?.boundOwnerDeclarationOrNull
if (referencedDeclaration == null) {
// If it's impossible to obtain referenced declaration because the symbol of this declaration is unbound,
// but the declaration itself is supposed to be, then do best effort and try to output the short name of
// the declaration at least.
appendDeclaration(referencedDeclarationKind, referencedDeclarationSymbol?.guessName())
} else {
appendDeclaration(referencedDeclaration)
}
}
append(" can not be ").append(expressionKind.verb3rdForm).append(" because it")
}
else -> error("Unexpected type of IR element: ${this::class.java}, $this")
}
append(" uses unlinked symbols")
if (unlinkedSymbols.isNotEmpty()) {
unlinkedSymbols.joinTo(this, prefix = ": ") { it.anySignature?.render() ?: UNKNOWN_SYMBOL }
}
}
}
private enum class DeclarationKind(private val displayName: String) {
CLASS("class"),
INTERFACE("interface"),
ENUM_CLASS("enum class"),
ENUM_ENTRY("enum entry"),
ANNOTATION_CLASS("annotation class"),
OBJECT("object"),
ANONYMOUS_OBJECT("anonymous object"),
COMPANION_OBJECT("companion object"),
MUTABLE_VARIABLE("var"),
IMMUTABLE_VARIABLE("val"),
VALUE_PARAMETER("value parameter"),
FIELD("field"),
FIELD_OF_PROPERTY("backing field of property"),
PROPERTY("property"),
PROPERTY_ACCESSOR("property accessor"),
FUNCTION("function"),
CONSTRUCTOR("constructor"),
OTHER_DECLARATION("declaration");
override fun toString() = displayName
}
private val IrDeclaration.declarationKind: DeclarationKind
get() = when (this) {
is IrClass -> when (kind) {
ClassKind.CLASS -> if (isAnonymousObject) ANONYMOUS_OBJECT else CLASS
ClassKind.INTERFACE -> INTERFACE
ClassKind.ENUM_CLASS -> ENUM_CLASS
ClassKind.ENUM_ENTRY -> ENUM_ENTRY
ClassKind.ANNOTATION_CLASS -> ANNOTATION_CLASS
ClassKind.OBJECT -> if (isCompanion) COMPANION_OBJECT else OBJECT
}
is IrVariable -> if (isVar) MUTABLE_VARIABLE else IMMUTABLE_VARIABLE
is IrValueParameter -> VALUE_PARAMETER
is IrField -> if (correspondingPropertySymbol != null) FIELD_OF_PROPERTY else FIELD
is IrProperty -> PROPERTY
is IrSimpleFunction -> if (correspondingPropertySymbol != null) PROPERTY_ACCESSOR else FUNCTION
is IrConstructor -> CONSTRUCTOR
else -> OTHER_DECLARATION
}
private val IrFunctionSymbol.functionDeclarationKind: DeclarationKind
get() = when (this) {
is IrConstructorSymbol -> CONSTRUCTOR
is IrSimpleFunctionSymbol -> boundOwnerDeclarationOrNull?.declarationKind
?: if (anySignature is AccessorSignature) PROPERTY_ACCESSOR else FUNCTION
else -> OTHER_DECLARATION // Something unexpected.
}
private val IrFieldSymbol.fieldDeclarationKind: DeclarationKind
get() = boundOwnerDeclarationOrNull?.declarationKind
?: FIELD // Fallback to simple field as it's impossible to make a guess by signature.
private val IrValueSymbol.valueDeclarationKind: DeclarationKind
get() = when (this) {
is IrValueParameterSymbol -> VALUE_PARAMETER
is IrVariableSymbol -> boundOwnerDeclarationOrNull?.declarationKind
?: IMMUTABLE_VARIABLE // Fallback to immutable variable as it's impossible to make a guess by signature.
else -> OTHER_DECLARATION // Something unexpected.
}
private val IrSymbol.classDeclarationKind: DeclarationKind
get() = when (this) {
is IrClassSymbol -> boundOwnerDeclarationOrNull?.declarationKind
?: CLASS // Fallback to class as it's impossible to make a guess by signature.
is IrEnumEntrySymbol -> ENUM_ENTRY
else -> OTHER_DECLARATION // Something unexpected.
}
private data class Expression(val kind: ExpressionKind, val referencedDeclarationKind: DeclarationKind?)
private enum class ExpressionKind(val displayName: String?, val verb3rdForm: String) {
REFERENCE("reference to", "evaluated"),
CALLING(null, "called"),
CALLING_INSTANCE_INITIALIZER("instance initializer of", "called"),
READING(null, "read"),
WRITING(null, "written"),
GETTING_INSTANCE(null, "gotten"),
OTHER_EXPRESSION("expression", "evaluated")
}
// More can be added for verbosity in the future.
private val IrExpression.expression: Expression
get() = when (this) {
is IrDeclarationReference -> when (this) {
is IrFunctionReference -> Expression(REFERENCE, symbol.functionDeclarationKind)
is IrPropertyReference,
is IrLocalDelegatedPropertyReference -> Expression(REFERENCE, PROPERTY)
is IrCall -> Expression(CALLING, symbol.functionDeclarationKind)
is IrConstructorCall,
is IrEnumConstructorCall,
is IrDelegatingConstructorCall -> Expression(CALLING, CONSTRUCTOR)
is IrClassReference -> Expression(REFERENCE, symbol.classDeclarationKind)
is IrGetField -> Expression(READING, symbol.fieldDeclarationKind)
is IrSetField -> Expression(WRITING, symbol.fieldDeclarationKind)
is IrGetValue -> Expression(READING, symbol.valueDeclarationKind)
is IrSetValue -> Expression(WRITING, symbol.valueDeclarationKind)
is IrGetSingletonValue -> Expression(GETTING_INSTANCE, symbol.classDeclarationKind)
else -> Expression(REFERENCE, OTHER_DECLARATION)
}
is IrInstanceInitializerCall -> Expression(CALLING_INSTANCE_INITIALIZER, classSymbol.classDeclarationKind)
else -> Expression(OTHER_EXPRESSION, null)
}
private val IrSymbol.boundOwnerDeclarationOrNull: IrDeclaration?
get() = if (isBound) owner as? IrDeclaration else null
private fun IrSymbol.guessName(): String? {
fun IdSignature.guessNameBySignature(nameSegmentsToPickUp: Int): String? = when (this) {
is CommonSignature -> nameSegments.takeLast(nameSegmentsToPickUp).joinToString(".")
is CompositeSignature -> inner.guessNameBySignature(nameSegmentsToPickUp)
is AccessorSignature -> accessorSignature.guessNameBySignature(nameSegmentsToPickUp)
else -> null
}
return anySignature
?.let { effectiveSignature ->
val nameSegmentsToPickUp = when {
effectiveSignature is AccessorSignature -> 2 // property_name.accessor_name
this is IrConstructorSymbol -> 2 // class_name.<init>
else -> 1
}
effectiveSignature.guessNameBySignature(nameSegmentsToPickUp)
}
?: boundOwnerDeclarationOrNull?.nameForIrSerialization?.asString()
}
private val IrSymbol.anySignature: IdSignature?
get() = signature ?: privateSignature
private const val UNKNOWN_SYMBOL = "<unknown symbol>"
private const val UNKNOWN_NAME = "<unknown name>"
private fun StringBuilder.appendWithWhitespaceBefore(text: String): StringBuilder {
if (text.isNotEmpty()) appendWhitespaceIfNotEmpty().append(text)
return this
}
private fun StringBuilder.appendWithWhitespaceAfter(text: String?): StringBuilder {
if (!text.isNullOrEmpty()) append(text).append(" ")
return this
}
private fun StringBuilder.appendWhitespaceIfNotEmpty(): StringBuilder {
if (isNotEmpty()) append(" ")
return this
}