diff --git a/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirRenderer.kt b/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirRenderer.kt deleted file mode 100644 index 66c2407c221..00000000000 --- a/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirRenderer.kt +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2010-2019 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.compiler.visualizer - -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirNamedReference -import org.jetbrains.kotlin.fir.FirResolvedCallableReference -import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractMemberDeclaration -import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl -import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.references.FirErrorNamedReference -import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider -import org.jetbrains.kotlin.fir.resolve.directExpansionType -import org.jetbrains.kotlin.fir.resolve.transformers.firSafeNullable -import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe -import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol -import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol -import org.jetbrains.kotlin.fir.symbols.ConeSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl -import org.jetbrains.kotlin.fir.visitors.FirVisitor -import org.jetbrains.kotlin.ir.expressions.IrConstKind -import org.jetbrains.kotlin.name.ClassId - -class FirRenderer(private val firFile: FirFile) : FirVisitor() { - private val session = firFile.session - private val filePackage = firFile.packageFqName.toString().replace(".", "/") - private val symbolProvider = firFile.session.getService(FirSymbolProvider::class) - - private fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(firFile), this) } - - private fun removeCurrentFilePackage(fqName: String): String { - return if (fqName.startsWith(filePackage) && !fqName.substring(filePackage.length + 1).contains("/")) { - fqName.replaceFirst("$filePackage/", "") - } else { - fqName - } - } - - private fun ClassId.getWithoutCurrentPackage() = removeCurrentFilePackage(this.asString()) - - private fun renderListInTriangles(list: List, data: StringBuilder, withSpace: Boolean = false) { - if (list.isNotEmpty()) { - list.joinTo(data, separator = ", ", prefix = "<", postfix = ">") { - buildString { it.accept(this@FirRenderer, this) } - } - if (withSpace) data.append(" ") - } - } - - private fun visitArguments(arguments: List, data: StringBuilder) { - arguments.joinTo(data, ", ", "(", ")") { - if (it is FirResolvedQualifier) { - val lookupTag = (it.typeRef as FirResolvedTypeRefImpl).coneTypeSafe()?.lookupTag - val type = lookupTag?.let { - symbolProvider.getSymbolByLookupTag(it)?.firSafeNullable()?.superTypeRefs?.first()?.render() - } - if (type != null) return@joinTo type - } - it.typeRef.render() - } - } - - override fun visitElement(element: FirElement, data: StringBuilder) { - element.acceptChildren(this, data) - } - - override fun visitConstructor(constructor: FirConstructor, data: StringBuilder) { - data.append(renderSymbol(constructor.symbol)) - visitValueParameters(constructor.valueParameters, data) - } - - override fun visitTypeParameter(typeParameter: FirTypeParameter, data: StringBuilder) { - data.append(typeParameter.name) - val bounds = typeParameter.bounds.filterNot { it.render() == "kotlin/Any?" } - if (bounds.isNotEmpty()) { - data.append(" : ") - bounds.joinTo(data, separator = ", ") { - buildString { it.accept(this@FirRenderer, this) } - } - } - } - - override fun visitProperty(property: FirProperty, data: StringBuilder) { - data.append(property.returnTypeRef.render()) - } - - private fun visitValueParameters(valueParameters: List, data: StringBuilder) { - valueParameters.joinTo(data, separator = ", ", prefix = "(", postfix = ")") { - buildString { it.accept(this@FirRenderer, this) } - } - } - - override fun visitValueParameter(valueParameter: FirValueParameter, data: StringBuilder) { - if (valueParameter.isVararg) { - data.append("vararg ") - } - valueParameter.returnTypeRef.coneTypeSafe()?.arrayElementType(session)?.let { data.append(it.render()) } - ?: valueParameter.returnTypeRef.accept(this, data) - valueParameter.defaultValue?.let { data.append(" = ...") } - } - - override fun > visitVariable(variable: FirVariable, data: StringBuilder) { - data.append(variable.returnTypeRef.render()) - } - - override fun visitNamedReference(namedReference: FirNamedReference, data: StringBuilder) { - if (namedReference is FirErrorNamedReference) { - data.append("[ERROR : ${namedReference.errorReason}]") - return - } - super.visitNamedReference(namedReference, data) - } - - override fun visitResolvedCallableReference(resolvedCallableReference: FirResolvedCallableReference, data: StringBuilder) { - val symbol = resolvedCallableReference.coneSymbol - data.append(renderSymbol(symbol)) - } - - override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: StringBuilder) { - data.append(annotationCall.annotationTypeRef.render()) - } - - override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall, data: StringBuilder) { - val coneClassType = delegatedConstructorCall.constructedTypeRef.coneTypeSafe() - if (coneClassType != null) { - data.append("constructor").append(" ") - - data.append(coneClassType.lookupTag.classId.getWithoutCurrentPackage()) - - val typeParameters = symbolProvider.getSymbolByLookupTag(coneClassType.lookupTag) - ?.firSafeNullable() - ?.typeParameters ?: listOf() - renderListInTriangles(typeParameters, data) - visitArguments(delegatedConstructorCall.arguments, data) - } else { - data.append("[ERROR : ${delegatedConstructorCall.constructedTypeRef.render()}]") - } - } - - override fun visitOperatorCall(operatorCall: FirOperatorCall, data: StringBuilder) { - data.append("operator call ${operatorCall.operation}") - } - - override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: StringBuilder) { - //skip rendering for as/as?/is/!is - } - - override fun visitFunctionCall(functionCall: FirFunctionCall, data: StringBuilder) { - when (val callee = functionCall.calleeReference) { - is FirResolvedCallableReference -> { - if (callee.coneSymbol is FirConstructorSymbol) { - data.append(renderSymbol(callee.coneSymbol)) - visitArguments(functionCall.arguments, data) - } else { - data.append("fun ") - val firFunction = callee.coneSymbol.firSafeNullable() - firFunction?.let { renderListInTriangles(it.typeParameters, data, true) } - - data.append(renderSymbol(callee.coneSymbol)) - renderListInTriangles(functionCall.typeArguments, data) - visitValueParameters(callee.coneSymbol.firUnsafe>().valueParameters, data) - data.append(": ") - functionCall.typeRef.accept(this, data) - } - } - is FirErrorNamedReference -> data.append("[ERROR : ${callee.errorReason}]") - } - } - - override fun visitConstExpression(constExpression: FirConstExpression, data: StringBuilder) { - if (constExpression.kind != IrConstKind.String) { - data.append(constExpression.kind) - } - } - - override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: StringBuilder) { - resolvedQualifier.classId?.let { - val fir = symbolProvider.getClassLikeSymbolByFqName(it)?.fir - if (fir is FirClass) { - data.append(fir.classKind.name.toLowerCase()).append(" ") - data.append(fir.name) - if (fir.superTypeRefs.any { it.render() != "kotlin/Any" }) { - data.append(": ") - fir.superTypeRefs.joinTo(data, separator = ", ") { typeRef -> typeRef.render() } - } - } - } - } - - override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: StringBuilder) { - data.append("qualified access: \"${variableAssignment.operation}\"") - } - - override fun visitStarProjection(starProjection: FirStarProjection, data: StringBuilder) { - data.append("*") - } - - override fun visitTypeProjectionWithVariance(typeProjectionWithVariance: FirTypeProjectionWithVariance, data: StringBuilder) { - val variance = typeProjectionWithVariance.variance.label - if (variance.isNotEmpty()) data.append("$variance ") - typeProjectionWithVariance.typeRef.accept(this, data) - } - - override fun visitDelegatedTypeRef(delegatedTypeRef: FirDelegatedTypeRef, data: StringBuilder) { - delegatedTypeRef.typeRef.accept(this, data) - data.append(" by ") - delegatedTypeRef.delegate?.accept(this, data) - } - - override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: StringBuilder) { - val coneType = resolvedTypeRef.type - data.append(removeCurrentFilePackage(coneType.render())) - if (coneType is ConeAbbreviatedType) { - val original = coneType.directExpansionType(session) - original?.let { data.append(" /* = ${it.render()} */") } - } - } - - override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: StringBuilder) { - data.append("[ERROR : ${errorTypeRef.reason}]") - } - - override fun visitResolvedFunctionTypeRef(resolvedFunctionTypeRef: FirResolvedFunctionTypeRef, data: StringBuilder) { - resolvedFunctionTypeRef.receiverTypeRef?.let { - it.accept(this, data) - data.append(".") - } - visitValueParameters(resolvedFunctionTypeRef.valueParameters, data) - data.append(" -> ") - resolvedFunctionTypeRef.returnTypeRef.accept(this, data) - } - - override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability, data: StringBuilder) { - if (typeRefWithNullability.isMarkedNullable) { - data.append("?") - } - } - - private fun renderSymbol(symbol: ConeSymbol?): String { - val data = StringBuilder() - var id = when (symbol) { - is ConeCallableSymbol -> { - val callableId = symbol.callableId - val idWithPackage = callableId.toString().replace("." + callableId.callableName.asString(), "") - removeCurrentFilePackage(idWithPackage) - } - is ConeClassLikeSymbol -> symbol.classId.getWithoutCurrentPackage() - else -> "" - } - - if (id.startsWith("/")) { - id = id.substring(1) - } - - when (symbol) { - is FirNamedFunctionSymbol -> { - val callableName = symbol.callableId.callableName - val receiverType = symbol.fir.receiverTypeRef - if (receiverType == null) { - if (symbol.callableId.className == null) { - data.append(id) - } else { - data.append("($id).$callableName") - } - } else { - data.append("${receiverType.render()}.$callableName") - } - } - is FirPropertySymbol -> { - data.append(if (symbol.fir.isVar) "var" else "val").append(" ") - renderListInTriangles(symbol.fir.typeParameters, data, withSpace = true) - - val receiver = symbol.fir.receiverTypeRef?.render() - if (receiver != null) { - data.append(receiver).append(".") - } else if (id != symbol.callableId.callableName.asString()) { - data.append("($id)").append(".") - } - - data.append(symbol.callableId.callableName).append(": ") - symbol.fir.returnTypeRef.accept(this, data) - } - is FirVariableSymbol<*> -> { - if (symbol.fir !is FirValueParameter) { - if (symbol.fir.isVar) data.append("var ") else if (symbol.fir.isVal) data.append("val ") - } - data.append(id) - - data.append(": ") - symbol.fir.returnTypeRef.accept(this, data) - } - is FirConstructorSymbol -> { - data.append("constructor ") - val packageName = symbol.callableId.className - data.append(packageName) - renderListInTriangles(symbol.fir.typeParameters, data) - } - } - return data.toString() - } -} \ No newline at end of file diff --git a/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt b/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt index 5fdf12b15a9..4a68ef728bd 100644 --- a/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt +++ b/compiler/visualizer/render-fir/src/org/jetbrains/kotlin/compiler/visualizer/FirVisualizer.kt @@ -9,22 +9,38 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirLabel +import org.jetbrains.kotlin.fir.FirNamedReference import org.jetbrains.kotlin.fir.FirResolvedCallableReference import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor +import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock +import org.jetbrains.kotlin.fir.references.FirErrorNamedReference +import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.directExpansionType +import org.jetbrains.kotlin.fir.resolve.transformers.firSafeNullable +import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe +import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol +import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.ConeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid +import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl +import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.ir.expressions.IrConstKind +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.getChildOfType import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType private typealias Stack = MutableList>> class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { + private fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(), this) } + override fun addAnnotation(annotationText: String, element: PsiElement?, deleteDuplicate: Boolean) { super.addAnnotation(annotationText, element, false) } @@ -39,8 +55,6 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { //private var innerLambdaCount = 0 private val stack = mutableListOf("" to mutableListOf()) - private fun FirElement.render(): String = buildString { this@render.accept(FirRenderer(firFile), this) } - private fun Stack.push( levelName: String, defaultValues: MutableList = mutableListOf() @@ -268,4 +282,281 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { super.visitWhenEntry(jetWhenEntry) } } + + inner class FirRenderer : FirVisitor() { + private val session = firFile.session + private val filePackage = firFile.packageFqName.toString().replace(".", "/") + private val symbolProvider = firFile.session.getService(FirSymbolProvider::class) + + private fun removeCurrentFilePackage(fqName: String): String { + return if (fqName.startsWith(filePackage) && !fqName.substring(filePackage.length + 1).contains("/")) { + fqName.replaceFirst("$filePackage/", "") + } else { + fqName + } + } + + private fun ClassId.getWithoutCurrentPackage() = removeCurrentFilePackage(this.asString()) + + private fun renderListInTriangles(list: List, data: StringBuilder, withSpace: Boolean = false) { + if (list.isNotEmpty()) { + list.joinTo(data, separator = ", ", prefix = "<", postfix = ">") { + buildString { it.accept(this@FirRenderer, this) } + } + if (withSpace) data.append(" ") + } + } + + private fun visitArguments(arguments: List, data: StringBuilder) { + arguments.joinTo(data, ", ", "(", ")") { + if (it is FirResolvedQualifier) { + val lookupTag = (it.typeRef as FirResolvedTypeRefImpl).coneTypeSafe()?.lookupTag + val type = lookupTag?.let { + symbolProvider.getSymbolByLookupTag(it)?.firSafeNullable()?.superTypeRefs?.first()?.render() + } + if (type != null) return@joinTo type + } + it.typeRef.render() + } + } + + override fun visitElement(element: FirElement, data: StringBuilder) { + element.acceptChildren(this, data) + } + + override fun visitConstructor(constructor: FirConstructor, data: StringBuilder) { + data.append(renderSymbol(constructor.symbol)) + visitValueParameters(constructor.valueParameters, data) + } + + override fun visitTypeParameter(typeParameter: FirTypeParameter, data: StringBuilder) { + data.append(typeParameter.name) + val bounds = typeParameter.bounds.filterNot { it.render() == "kotlin/Any?" } + if (bounds.isNotEmpty()) { + data.append(" : ") + bounds.joinTo(data, separator = ", ") { + buildString { it.accept(this@FirRenderer, this) } + } + } + } + + override fun visitProperty(property: FirProperty, data: StringBuilder) { + data.append(property.returnTypeRef.render()) + } + + private fun visitValueParameters(valueParameters: List, data: StringBuilder) { + valueParameters.joinTo(data, separator = ", ", prefix = "(", postfix = ")") { + buildString { it.accept(this@FirRenderer, this) } + } + } + + override fun visitValueParameter(valueParameter: FirValueParameter, data: StringBuilder) { + if (valueParameter.isVararg) { + data.append("vararg ") + } + valueParameter.returnTypeRef.coneTypeSafe()?.arrayElementType(session)?.let { data.append(it.render()) } + ?: valueParameter.returnTypeRef.accept(this, data) + valueParameter.defaultValue?.let { data.append(" = ...") } + } + + override fun > visitVariable(variable: FirVariable, data: StringBuilder) { + data.append(variable.returnTypeRef.render()) + } + + override fun visitNamedReference(namedReference: FirNamedReference, data: StringBuilder) { + if (namedReference is FirErrorNamedReference) { + data.append("[ERROR : ${namedReference.errorReason}]") + return + } + super.visitNamedReference(namedReference, data) + } + + override fun visitResolvedCallableReference(resolvedCallableReference: FirResolvedCallableReference, data: StringBuilder) { + val symbol = resolvedCallableReference.coneSymbol + data.append(renderSymbol(symbol)) + } + + override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: StringBuilder) { + data.append(annotationCall.annotationTypeRef.render()) + } + + override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall, data: StringBuilder) { + val coneClassType = delegatedConstructorCall.constructedTypeRef.coneTypeSafe() + if (coneClassType != null) { + data.append("constructor").append(" ") + + data.append(coneClassType.lookupTag.classId.getWithoutCurrentPackage()) + + val typeParameters = symbolProvider.getSymbolByLookupTag(coneClassType.lookupTag) + ?.firSafeNullable() + ?.typeParameters ?: listOf() + renderListInTriangles(typeParameters, data) + visitArguments(delegatedConstructorCall.arguments, data) + } else { + data.append("[ERROR : ${delegatedConstructorCall.constructedTypeRef.render()}]") + } + } + + override fun visitOperatorCall(operatorCall: FirOperatorCall, data: StringBuilder) { + data.append("operator call ${operatorCall.operation}") + } + + override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: StringBuilder) { + //skip rendering for as/as?/is/!is + } + + override fun visitFunctionCall(functionCall: FirFunctionCall, data: StringBuilder) { + when (val callee = functionCall.calleeReference) { + is FirResolvedCallableReference -> { + if (callee.coneSymbol is FirConstructorSymbol) { + data.append(renderSymbol(callee.coneSymbol)) + visitArguments(functionCall.arguments, data) + } else { + data.append("fun ") + val firFunction = callee.coneSymbol.firSafeNullable() + firFunction?.let { renderListInTriangles(it.typeParameters, data, true) } + + data.append(renderSymbol(callee.coneSymbol)) + renderListInTriangles(functionCall.typeArguments, data) + visitValueParameters(callee.coneSymbol.firUnsafe>().valueParameters, data) + data.append(": ") + functionCall.typeRef.accept(this, data) + } + } + is FirErrorNamedReference -> data.append("[ERROR : ${callee.errorReason}]") + } + } + + override fun visitConstExpression(constExpression: FirConstExpression, data: StringBuilder) { + if (constExpression.kind != IrConstKind.String) { + data.append(constExpression.kind) + } + } + + override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: StringBuilder) { + resolvedQualifier.classId?.let { + val fir = symbolProvider.getClassLikeSymbolByFqName(it)?.fir + if (fir is FirClass) { + data.append(fir.classKind.name.toLowerCase()).append(" ") + data.append(fir.name) + if (fir.superTypeRefs.any { it.render() != "kotlin/Any" }) { + data.append(": ") + fir.superTypeRefs.joinTo(data, separator = ", ") { typeRef -> typeRef.render() } + } + } + } + } + + override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: StringBuilder) { + data.append("qualified access: \"${variableAssignment.operation}\"") + } + + override fun visitStarProjection(starProjection: FirStarProjection, data: StringBuilder) { + data.append("*") + } + + override fun visitTypeProjectionWithVariance(typeProjectionWithVariance: FirTypeProjectionWithVariance, data: StringBuilder) { + val variance = typeProjectionWithVariance.variance.label + if (variance.isNotEmpty()) data.append("$variance ") + typeProjectionWithVariance.typeRef.accept(this, data) + } + + override fun visitDelegatedTypeRef(delegatedTypeRef: FirDelegatedTypeRef, data: StringBuilder) { + delegatedTypeRef.typeRef.accept(this, data) + data.append(" by ") + delegatedTypeRef.delegate?.accept(this, data) + } + + override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: StringBuilder) { + val coneType = resolvedTypeRef.type + data.append(removeCurrentFilePackage(coneType.render())) + if (coneType is ConeAbbreviatedType) { + val original = coneType.directExpansionType(session) + original?.let { data.append(" /* = ${it.render()} */") } + } + } + + override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: StringBuilder) { + data.append("[ERROR : ${errorTypeRef.reason}]") + } + + override fun visitResolvedFunctionTypeRef(resolvedFunctionTypeRef: FirResolvedFunctionTypeRef, data: StringBuilder) { + resolvedFunctionTypeRef.receiverTypeRef?.let { + it.accept(this, data) + data.append(".") + } + visitValueParameters(resolvedFunctionTypeRef.valueParameters, data) + data.append(" -> ") + resolvedFunctionTypeRef.returnTypeRef.accept(this, data) + } + + override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability, data: StringBuilder) { + if (typeRefWithNullability.isMarkedNullable) { + data.append("?") + } + } + + private fun renderSymbol(symbol: ConeSymbol?): String { + val data = StringBuilder() + var id = when (symbol) { + is ConeCallableSymbol -> { + val callableId = symbol.callableId + val idWithPackage = callableId.toString().replace("." + callableId.callableName.asString(), "") + removeCurrentFilePackage(idWithPackage) + } + is ConeClassLikeSymbol -> symbol.classId.getWithoutCurrentPackage() + else -> "" + } + + if (id.startsWith("/")) { + id = id.substring(1) + } + + when (symbol) { + is FirNamedFunctionSymbol -> { + val callableName = symbol.callableId.callableName + val receiverType = symbol.fir.receiverTypeRef + if (receiverType == null) { + if (symbol.callableId.className == null) { + data.append(id) + } else { + data.append("($id).$callableName") + } + } else { + data.append("${receiverType.render()}.$callableName") + } + } + is FirPropertySymbol -> { + data.append(if (symbol.fir.isVar) "var" else "val").append(" ") + renderListInTriangles(symbol.fir.typeParameters, data, withSpace = true) + + val receiver = symbol.fir.receiverTypeRef?.render() + if (receiver != null) { + data.append(receiver).append(".") + } else if (id != symbol.callableId.callableName.asString()) { + data.append("($id)").append(".") + } + + data.append(symbol.callableId.callableName).append(": ") + symbol.fir.returnTypeRef.accept(this, data) + } + is FirVariableSymbol<*> -> { + if (symbol.fir !is FirValueParameter) { + if (symbol.fir.isVar) data.append("var ") else if (symbol.fir.isVal) data.append("val ") + } + data.append(id) + + data.append(": ") + symbol.fir.returnTypeRef.accept(this, data) + } + is FirConstructorSymbol -> { + data.append("constructor ") + val packageName = symbol.callableId.className + data.append(packageName) + renderListInTriangles(symbol.fir.typeParameters, data) + } + } + return data.toString() + } + } } \ No newline at end of file