From e19514f1dc2b877daf10bc3593aad649ee2e85c6 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Fri, 5 Mar 2021 15:36:49 +0300 Subject: [PATCH] [VISUALIZER] Render original symbols/descriptors in fir/psi --- .../compiler/visualizer/FirVisualizer.kt | 247 ++++++++++-------- .../compiler/visualizer/PsiVisualizer.kt | 82 ++++-- .../declarations/NestedOfAliasedType.kt | 2 +- .../propertyAccessorsContractDescription.kt | 5 +- .../simpleFunctionsContractDescription.kt | 5 +- .../rawBuilder/declarations/functionTypes.kt | 4 +- .../declarations/simpleTypeAlias.kt | 2 +- .../declarations/typeAliasWithGeneric.kt | 2 +- .../testData/rawBuilder/expressions/for.kt | 4 +- .../testData/rawBuilder/expressions/in.kt | 4 +- .../rawBuilder/expressions/inBrackets.kt | 4 +- .../testData/rawBuilder/expressions/lambda.kt | 2 +- .../expressions/lambdaAndAnonymousFunction.kt | 2 +- .../testData/rawBuilder/expressions/locals.kt | 7 +- .../expressions/qualifierWithTypeArguments.kt | 2 +- .../testData/rawBuilder/expressions/try.kt | 4 +- .../uncommonCases/resultFiles/dataClass.kt | 2 +- .../uncommonCases/resultFiles/delegation.kt | 2 +- .../uncommonCases/resultFiles/lists.kt | 2 +- .../uncommonCases/resultFiles/superTypes.kt | 11 +- .../uncommonCases/resultFiles/variance.kt | 2 +- .../uncommonCases/testFiles/superTypes.kt | 2 +- 22 files changed, 243 insertions(+), 156 deletions(-) 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 26e86aafae6..9f6b9eafd7e 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 @@ -7,13 +7,16 @@ package org.jetbrains.kotlin.compiler.visualizer import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe +import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* @@ -22,15 +25,17 @@ import org.jetbrains.kotlin.name.CallableId 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 import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly +private const val ANONYMOUS_NAME = "" private typealias Stack = MutableList>> class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { - private val implicitReceivers = mutableListOf() + private val implicitReceivers = mutableListOf() private fun FirElement.render(): String = buildString { this@render.accept(FirRendererForVisualizer(), this) } @@ -45,6 +50,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { private fun Stack.addName(name: String) = this.last().second.add(name) private fun Stack.addName(name: Name) = this.addName(name.asString()) private fun Stack.getPathByName(name: String): String { + if (name == ANONYMOUS_NAME) return "" for ((reversedIndex, names) in this.asReversed().map { it.second }.withIndex()) { if (names.contains(name)) { return this.filterIndexed { index, _ -> index < this.size - reversedIndex && index > 0 } @@ -129,8 +135,8 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { stack.pop() } is KtClassOrObject -> { - if (element.isLocal) stack.addName((element.name ?: "")) - stack.push((element.name ?: "")) + if (element.isLocal) stack.addName((element.name ?: ANONYMOUS_NAME)) + stack.push((element.name ?: ANONYMOUS_NAME)) element.acceptChildren(this) stack.pop() } @@ -151,8 +157,8 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } override fun visitNamedFunction(function: KtNamedFunction) { - if (function.isLocal) stack.addName(function.name ?: "") - stack.push((function.name ?: "")) + if (function.isLocal) stack.addName(function.name ?: ANONYMOUS_NAME) + stack.push((function.name ?: ANONYMOUS_NAME)) if (function.equalsToken != null) { function.bodyExpression!!.firstOfTypeWithRender(function.equalsToken) { this.result.typeRef } ?: function.firstOfTypeWithRender(function.equalsToken) { this.returnTypeRef } @@ -174,7 +180,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { renderVariableType(multiDeclarationEntry) override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) { - annotationEntry.firstOfTypeWithRender(annotationEntry.children.first()) + annotationEntry.firstOfTypeWithRender(annotationEntry.getChildOfType()) super.visitAnnotationEntry(annotationEntry) } @@ -262,9 +268,10 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { val firLambda = psi.firstOfType()?.expression as? FirAnonymousFunction firLambda?.receiverTypeRef?.let { lastCallWithLambda = psi.getLambdaExpression()?.firstOfType()?.name - implicitReceivers += it + implicitReceivers += it.coneType psi.accept(this) - implicitReceivers -= it + implicitReceivers -= it.coneType + lastCallWithLambda = null } ?: psi.accept(this) } else -> psi.accept(this) @@ -273,7 +280,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) { - stack.push("") + stack.push(ANONYMOUS_NAME) lastCallWithLambda?.let { addAnnotation("$it@${implicitReceivers.size - 1}", lambdaExpression) } super.visitLambdaExpression(lambdaExpression) stack.pop() @@ -386,10 +393,16 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { is ConeKotlinTypeProjectionIn -> "in ${type.tryToRenderConeAsFunctionType()}" is ConeKotlinTypeProjectionOut -> "out ${type.tryToRenderConeAsFunctionType()}" is ConeClassLikeType -> { + val type = this.fullyExpandedType(session) + if (type != this) return type.tryToRenderConeAsFunctionType() + val classId = type.lookupTag.classId buildString { - append(lookupTag.classId.asString()) - if (typeArguments.isNotEmpty()) { - append(typeArguments.joinToString(prefix = "<", postfix = ">") { it.tryToRenderConeAsFunctionType() }) + when { + classId.isLocal -> append(classId.shortClassName.asString().let { stack.getPathByName(it) + it }) + else -> append(classId.asString()) + } + if (type.typeArguments.isNotEmpty()) { + append(type.typeArguments.joinToString(prefix = "<", postfix = ">") { it.tryToRenderConeAsFunctionType() }) } append(nullabilitySuffix) } @@ -407,6 +420,10 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { tryToSquashFlexibleType(lowerRendered, upperRendered) ?: "$lowerRendered..$upperRendered" } } + is ConeIntersectionType -> { + intersectedTypes.map { it.render().replace("/", ".").replace("kotlin.", "") }.sorted() + .joinToString(separator = " & ", prefix = "{", postfix = "}") + } else -> this.render() } } @@ -422,32 +439,34 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { private fun renderListInTriangles(list: List, data: StringBuilder, withSpace: Boolean = false) { if (list.isNotEmpty()) { list.joinTo(data, separator = ", ", prefix = "<", postfix = ">") { - buildString { it.accept(this@FirRendererForVisualizer, this) } + it.render() } if (withSpace) data.append(" ") } } - private fun visitArguments(arguments: List, data: StringBuilder) { - arguments.joinTo(data, ", ", "(", ")") { - if (it is FirResolvedQualifier) { - val lookupTag = (it.typeRef as FirResolvedTypeRef).coneTypeSafe()?.lookupTag - val type = lookupTag?.let { tag -> - (symbolProvider.getSymbolByLookupTag(tag)?.fir as? FirClass)?.superTypeRefs?.first()?.render() - } - if (type != null) return@joinTo type - } - it.typeRef.render() + private inline fun > D.originalIfFakeOverrideOrDelegated(): D? { + return when (origin) { + FirDeclarationOrigin.SubstitutionOverride, FirDeclarationOrigin.IntersectionOverride -> originalIfFakeOverride() + FirDeclarationOrigin.Delegated -> delegatedWrapperData!!.wrapped + else -> this } } - private fun renderImplicitReceiver(symbol: AbstractFirBasedSymbol<*>, psi: PsiElement?) { - val implicitReceiverIndex = (symbol.fir as? FirCallableMemberDeclaration<*>)?.dispatchReceiverType?.let { - implicitReceivers.map { (it as? FirResolvedTypeRef)?.coneType }.indexOf(it) - } ?: return - if (implicitReceiverIndex != -1) { - addAnnotation("this@$implicitReceiverIndex", psi) + private inline fun > D.getOriginal(): D { + var current = this + var next = this.originalIfFakeOverrideOrDelegated() ?: this + while (current != next) { + current = next + next = current.originalIfFakeOverrideOrDelegated() ?: current } + return current + } + + private fun renderImplicitReceiver(symbol: AbstractFirBasedSymbol<*>, psi: PsiElement?) { + val receiverType = (symbol.fir as? FirCallableMemberDeclaration<*>)?.dispatchReceiverType ?: return + val implicitReceiverIndex = implicitReceivers.indexOf(receiverType) + if (implicitReceiverIndex != -1) addAnnotation("this@$implicitReceiverIndex", psi) } private fun renderConstructorSymbol(symbol: FirConstructorSymbol, data: StringBuilder) { @@ -456,48 +475,79 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { renderListInTriangles(symbol.firUnsafe().typeParameters, data) } + private fun renderField(field: FirField, data: StringBuilder) { + val original = field.getOriginal() + if (original.isVal) data.append("val ") else if (original.isVar) data.append("var ") + + data.append("(") + .append(original.dispatchReceiverType?.tryToRenderConeAsFunctionType()) + .append(").") + .append(original.name) + .append(": ") + .append(original.returnTypeRef.coneType.tryToRenderConeAsFunctionType()) + } + private fun renderVariable(variable: FirVariable<*>, data: StringBuilder) { - when (variable) { - is FirEnumEntry -> { + when { + variable is FirEnumEntry -> { data.append("enum entry ") variable.returnTypeRef.accept(this, data) data.append(".${variable.name}") return } - !is FirValueParameter -> when { + variable !is FirValueParameter || variable.name.asString() == "e" /* hack to match render with psi */ -> when { variable.isVar -> data.append("var ") variable.isVal -> data.append("val ") } } - data.append(getSymbolId(variable.symbol)) + val returnType = if ((variable as? FirValueParameter)?.isVararg == true) { + data.append("vararg ") + variable.returnTypeRef.coneType.arrayElementType() + } else { + variable.returnTypeRef.coneType + } + + val receiver = when (variable) { + is FirField -> variable.dispatchReceiverType?.tryToRenderConeAsFunctionType() + else -> getSymbolId(variable.symbol) + } + + data.append(receiver) .append(variable.symbol.callableId.callableName) .append(": ") - .append(variable.returnTypeRef.render()) + .append(returnType?.tryToRenderConeAsFunctionType()) + .append((variable as? FirValueParameter)?.defaultValue?.let { " = ..." } ?: "") } private fun renderPropertySymbol(symbol: FirPropertySymbol, data: StringBuilder) { - data.append(if (symbol.fir.isVar) "var" else "val").append(" ") - renderListInTriangles(symbol.fir.typeParameters, data, withSpace = true) + val fir = symbol.fir.getOriginal() + data.append(if (fir.isVar) "var" else "val").append(" ") + renderListInTriangles(fir.typeParameters, data, withSpace = true) - val id = getSymbolId(symbol) - val receiver = symbol.fir.receiverTypeRef?.render() - if (receiver != null) { - data.append(receiver).append(".") - } else if (id.isNotEmpty()) { - data.append("($id)").append(".") + val receiver = fir.receiverTypeRef?.render() + when { + receiver != null -> data.append(receiver).append(".").append(symbol.callableId.callableName) + fir.dispatchReceiverType != null -> { + val dispatchReceiver = fir.dispatchReceiverType?.tryToRenderConeAsFunctionType() + data.append("($dispatchReceiver)").append(".").append(symbol.callableId.callableName) + } + else -> { + val name = symbol.callableId.let { if (it.packageName.asString().isEmpty()) it.callableName else it } + data.append(name.toString().removeCurrentFilePackage()) + } } - data.append(symbol.callableId.callableName).append(": ") - data.append(symbol.fir.returnTypeRef.render()) + data.append(": ").append(fir.returnTypeRef.render()) } private fun renderFunctionSymbol(symbol: FirNamedFunctionSymbol, data: StringBuilder, call: FirFunctionCall? = null) { data.append("fun ") - renderListInTriangles(symbol.fir.typeParameters, data, true) + val fir = symbol.fir.getOriginal() + renderListInTriangles(fir.typeParameters, data, true) val id = getSymbolId(symbol) val callableName = symbol.callableId.callableName - val receiverType = symbol.fir.receiverTypeRef + val receiverType = fir.receiverTypeRef if (call == null) { // call is null for callable reference @@ -513,20 +563,19 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { when { call.extensionReceiver !is FirNoReceiverExpression -> { // render type from symbol because this way it will be consistent with psi render - symbol.fir.receiverTypeRef?.accept(this, data) + fir.receiverTypeRef?.accept(this, data) data.append(".").append(callableName) } call.dispatchReceiver.typeRef.annotations.any { it.isExtensionFunctionAnnotationCall } -> { withExtensionFunctionType = true - symbol.fir.valueParameters.first().returnTypeRef.accept(this, data) + fir.valueParameters.first().returnTypeRef.accept(this, data) data.append(".").append(callableName) } call.dispatchReceiver !is FirNoReceiverExpression -> { data.append("(") - val dispatch = buildString { call.dispatchReceiver.typeRef.accept(this@FirRendererForVisualizer, this) } + val dispatch = fir.dispatchReceiverType!!.tryToRenderConeAsFunctionType() .let { if (it.endsWith("!")) it.dropLast(1) else it } // this hack drop flexible annotation for receiver - val localPath = if (symbol.isLocalDeclaration()) stack.getPathByName(dispatch) else "" - data.append(localPath).append(dispatch).append(").").append(callableName) + data.append(dispatch).append(").").append(callableName) } else -> { data.append(id) @@ -536,10 +585,10 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } renderListInTriangles(call.typeArguments, data) - val valueParameters = symbol.fir.valueParameters.let { if (withExtensionFunctionType) it.drop(1) else it } + val valueParameters = fir.valueParameters.let { if (withExtensionFunctionType) it.drop(1) else it } visitValueParameters(valueParameters, data) data.append(": ") - symbol.fir.returnTypeRef.accept(this, data) + fir.returnTypeRef.accept(this, data) } override fun visitElement(element: FirElement, data: StringBuilder) { @@ -551,29 +600,15 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } private fun visitConstructor(call: FirResolvable, data: StringBuilder) { - val calleeReference = call.calleeReference - if (calleeReference !is FirResolvedNamedReference) { - data.append("[ERROR: Unresolved]") - } else { - when (call) { - is FirDelegatedConstructorCall -> { - val actualReturnType = calleeReference.resolvedSymbol.firUnsafe().returnTypeRef - if (call.constructedTypeRef.coneType != actualReturnType.coneType) { - // is typealias - val coneType = call.constructedTypeRef.coneType.localTypeRenderer() - val typeWithActual = buildString { call.constructedTypeRef.accept(this@FirRendererForVisualizer, this) } - data.append("fun ").append(coneType).append(".(): ").append(typeWithActual) - return - } - } - } - visitConstructor(calleeReference.resolvedSymbol.fir as FirConstructor, data) + when (val calleeReference = call.calleeReference) { + !is FirResolvedNamedReference -> data.append("[ERROR: Unresolved]") + else -> visitConstructor(calleeReference.resolvedSymbol.fir as FirConstructor, data) } } override fun visitConstructor(constructor: FirConstructor, data: StringBuilder) { renderConstructorSymbol(constructor.symbol, data) - visitValueParameters(constructor.valueParameters, data) + visitValueParameters(constructor.getOriginal().valueParameters, data) } override fun visitTypeParameterRef(typeParameterRef: FirTypeParameterRef, data: StringBuilder) { @@ -585,9 +620,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { val bounds = typeParameter.bounds.filterNot { it.render() == "kotlin/Any?" } if (bounds.isNotEmpty()) { data.append(" : ") - bounds.joinTo(data, separator = ", ") { - buildString { it.accept(this@FirRendererForVisualizer, this) } - } + bounds.joinTo(data, separator = ", ") { it.render() } } } @@ -609,14 +642,14 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { private fun visitValueParameters(valueParameters: List, data: StringBuilder) { valueParameters.joinTo(data, separator = ", ", prefix = "(", postfix = ")") { - buildString { it.accept(this@FirRendererForVisualizer, this) } + it.render() } } override fun visitValueParameter(valueParameter: FirValueParameter, data: StringBuilder) { if (valueParameter.isVararg) { data.append("vararg ") - valueParameter.returnTypeRef.coneTypeSafe()?.arrayElementType()?.let { data.append(it.localTypeRenderer()) } + valueParameter.returnTypeRef.coneType.arrayElementType()?.let { data.append(it.localTypeRenderer()) } } else { valueParameter.returnTypeRef.accept(this, data) } @@ -647,6 +680,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { .append(": ") .append(fir.dispatchReceiverType?.tryToRenderConeAsFunctionType()) } + symbol is FirFieldSymbol -> renderField(symbol.fir, data) else -> (symbol.fir as? FirVariable<*>)?.let { renderVariable(it, data) } } } @@ -654,6 +688,8 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { override fun visitResolvedCallableReference(resolvedCallableReference: FirResolvedCallableReference, data: StringBuilder) { when (val symbol = resolvedCallableReference.resolvedSymbol) { is FirPropertySymbol -> renderPropertySymbol(symbol, data) + is FirFieldSymbol -> renderField(symbol.fir, data) + is FirConstructorSymbol -> visitConstructor(symbol.fir, data) is FirNamedFunctionSymbol -> { renderFunctionSymbol(symbol, data) @@ -718,10 +754,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { renderImplicitReceiver(callee.resolvedSymbol, functionCall.source.psi) } when (callee.resolvedSymbol) { - is FirConstructorSymbol -> { - renderConstructorSymbol(callee.resolvedSymbol as FirConstructorSymbol, data) - visitValueParameters((callee.resolvedSymbol.fir as FirConstructor).valueParameters, data) - } + is FirConstructorSymbol -> visitConstructor(callee.resolvedSymbol.fir as FirConstructor, data) else -> renderFunctionSymbol(callee.resolvedSymbol as FirNamedFunctionSymbol, data, functionCall) } } @@ -738,15 +771,22 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: StringBuilder) { - resolvedQualifier.symbol?.fir?.let { fir -> - if (fir is FirClass) { + val fir = resolvedQualifier.symbol?.fir + when { + fir is FirRegularClass && fir.classKind != ClassKind.ENUM_CLASS && fir.companionObject?.defaultType() == resolvedQualifier.typeRef.coneTypeSafe() -> { + data.append("companion object ") + data.append(resolvedQualifier.typeRef.render()).append(": ") + data.append(fir.symbol.classId.asString().removeCurrentFilePackage()) + } + fir is FirClass -> { data.append(fir.classKind.name.toLowerCaseAsciiOnly().replace("_", " ")).append(" ") data.append(fir.symbol.classId.asString().removeCurrentFilePackage()) renderListInTriangles(fir.typeParameters, data) - if (fir.superTypeRefs.any { it.render() != "kotlin/Any" }) { - data.append(": ") - fir.superTypeRefs.joinTo(data, separator = ", ") { typeRef -> typeRef.render() } - } + val superTypes = fir.superTypeRefs + .map { it.render() } + .filter { it != "kotlin/Any" } + .sorted() + if (superTypes.isNotEmpty()) superTypes.joinTo(data, prefix = ": ", separator = ", ") } } } @@ -766,13 +806,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: StringBuilder) { - val coneType = resolvedTypeRef.type - data.append(coneType.tryToRenderConeAsFunctionType()) - - if (coneType is ConeClassLikeType) { - val original = coneType.directExpansionType(session) - original?.let { data.append(" /* = ${it.localTypeRenderer()} */") } - } + data.append(resolvedTypeRef.type.tryToRenderConeAsFunctionType()) } override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: StringBuilder) { @@ -790,22 +824,20 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: StringBuilder) { - val name = arrayOfCall.typeRef.coneType.classId?.shortClassName + val name = arrayOfCall.typeRef.coneType.classId!!.shortClassName.asString() val typeArguments = arrayOfCall.typeRef.coneType.typeArguments val typeParameters = if (typeArguments.isEmpty()) "" else " " - data.append("fun$typeParameters ${name?.asString()?.decapitalize()}Of") + data.append("fun$typeParameters ${name.decapitalize()}Of") typeArguments.firstOrNull()?.let { data.append("<").append(it.tryToRenderConeAsFunctionType()).append(">") } - data.append("(vararg T): $name${typeParameters.trim()}") // TODO change "T" to concrete type is array is primitive + val valueParameter = name.replace("Array", "").takeIf { it.isNotEmpty() } ?: "T" + data.append("(vararg $valueParameter): $name${typeParameters.trim()}") // TODO change "T" to concrete type is array is primitive } private fun AbstractFirBasedSymbol<*>.isLocalDeclaration(): Boolean { return when (val fir = this.fir) { - is FirConstructor -> { - val firClass = fir.returnTypeRef.coneTypeUnsafe().lookupTag.toFirRegularClass(session) - firClass?.isLocal ?: false - } + is FirConstructor -> fir.returnTypeRef.coneType.isLocal() is FirCallableDeclaration<*> -> { fir.dispatchReceiverClassOrNull()?.toFirRegularClass(session)?.isLocal ?: false } @@ -813,14 +845,21 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() { } } + private fun ConeKotlinType.isLocal(): Boolean { + if (this !is ConeClassLikeType) return false + return this.lookupTag.toFirRegularClass(session)?.isLocal == true + } + // id == packageName + className private fun getSymbolId(symbol: AbstractFirBasedSymbol<*>?): String { return when (symbol) { is FirCallableSymbol<*> -> { - val callableId = symbol.callableId.withoutName().removeCurrentFilePackage() - val isLocal = symbol.isLocalDeclaration() - val localPath = if (isLocal) stack.getPathByName(callableId) else "" - localPath + callableId + if (symbol.isLocalDeclaration()) { + val callableName = symbol.callableId.callableName.asString() + stack.getPathByName(callableName) + callableName + } else { + symbol.callableId.withoutName().removeCurrentFilePackage() + } } is FirClassLikeSymbol<*> -> symbol.classId.getWithoutCurrentPackage() else -> "" diff --git a/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiVisualizer.kt b/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiVisualizer.kt index 39a5f8205ab..af7a8b19dbb 100644 --- a/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiVisualizer.kt +++ b/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiVisualizer.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.compiler.visualizer.Annotator.annotate import org.jetbrains.kotlin.contracts.parsing.isEqualsDescriptor import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor +import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi.* @@ -141,6 +142,14 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : addAnnotation(renderType(expression), expression) } + override fun visitConstructorCalleeExpression(constructorCalleeExpression: KtConstructorCalleeExpression) { + // this is hack for JvmField annotation, for some reason it is not represented as KtAnnotationEntry + if (constructorCalleeExpression.text == "JvmField") { + return addAnnotation("constructor jvm/JvmField()", constructorCalleeExpression) + } + super.visitConstructorCalleeExpression(constructorCalleeExpression) + } + private fun renderCall(expression: KtExpression, renderOn: PsiElement = expression): ResolvedCall? { val call = expression.getCall(bindingContext) val resolvedCall = expression.getResolvedCall(bindingContext) @@ -163,23 +172,32 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : addReceiverAnnotation(resolvedCall.extensionReceiver, ExplicitReceiverKind.EXTENSION_RECEIVER) addReceiverAnnotation(resolvedCall.dispatchReceiver, ExplicitReceiverKind.DISPATCH_RECEIVER) - val descriptor = resolvedCall.candidateDescriptor + val descriptor = resolvedCall.candidateDescriptor.let { + if (it is TypeAliasConstructorDescriptor) it.underlyingConstructorDescriptor else it + } val typeArguments = resolvedCall.typeArguments .takeIf { it.isNotEmpty() } ?.values?.joinToString(", ", "<", ">") { renderType(it) } ?: "" - val annotation = when { - descriptor.isEqualsDescriptor() -> "EQ operator call" - else -> descriptorRenderer.render(descriptor).replace(argumentsLabel, typeArguments) - } + val annotation = descriptorRenderer.render(descriptor).replace(argumentsLabel, typeArguments) addAnnotation(annotation, renderOn, deleteDuplicate = false) return resolvedCall } + override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) { + val descriptor = bindingContext[QUALIFIER, expression]?.descriptor + if (descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY) { + // if not here, enum entry will be processed as KtSimpleNameExpression + // at this point it is easier to get corresponding qualifier + addAnnotation(descriptorRenderer.render(descriptor), expression.selectorExpression) + } + super.visitDotQualifiedExpression(expression) + } + override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { - val qualifierDescriptor = bindingContext[QUALIFIER, expression]?.descriptor - if (qualifierDescriptor != null) { - addAnnotation(descriptorRenderer.render(qualifierDescriptor), expression) + val descriptor = bindingContext[QUALIFIER, expression]?.descriptor + if (descriptor != null) { + addAnnotation(descriptorRenderer.render(descriptor), expression) } else { renderCall(expression) } @@ -187,6 +205,12 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : override fun visitBinaryExpression(expression: KtBinaryExpression) { val opName = expression.operationReference.getReferencedName() + if (opName == "==" || opName == "!=") { + addAnnotation("EQ operator call", expression.operationReference) + expression.left?.accept(this) + expression.right?.accept(this) + return + } expression.left?.takeIf { it.node.elementType == KtNodeTypes.ARRAY_ACCESS_EXPRESSION && opName == "=" }?.let { renderCall(it, expression.operationReference) } @@ -255,30 +279,46 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : modifiers = emptySet() classifierNamePolicy = object : ClassifierNamePolicy { override fun renderClassifier(classifier: ClassifierDescriptor, renderer: DescriptorRenderer): String { + if (classifier.name == SpecialNames.NO_NAME_PROVIDED) return "" return renderFqName(classifier) } } includeAdditionalModifiers = false parameterNameRenderingPolicy = ParameterNameRenderingPolicy.NONE + parameterNamesInFunctionalTypes = false withoutTypeParameters = true + renderUnabbreviatedType = false + renderTypeExpansions = true } private fun CallableDescriptor.isSpecial(): Boolean { return this.name.asString().contains("SPECIAL-FUNCTION") } + private fun DeclarationDescriptor.resolveFakeOverride(): DeclarationDescriptor { + fun CallableMemberDescriptor.isFakeOverrideOrDelegate(): Boolean { + return kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE || kind == CallableMemberDescriptor.Kind.DELEGATION + } + + var current = this as? CallableMemberDescriptor + while (current != null && current.isFakeOverrideOrDelegate()) { + current = current.overriddenDescriptors.singleOrNull { !it.isFakeOverrideOrDelegate() } + ?: current.overriddenDescriptors.firstOrNull() + } + return current ?: this + } + fun render(declarationDescriptor: DeclarationDescriptor): String { if (declarationDescriptor is CallableDescriptor && declarationDescriptor.isSpecial()) { return if (needToRenderSpecialFun) this.renderSpecialFunction(declarationDescriptor) else "" } return buildString { - declarationDescriptor.accept(this@PsiDescriptorRenderer, this) + declarationDescriptor.resolveFakeOverride().original.accept(this@PsiDescriptorRenderer, this) } } fun renderType(type: KotlinType): String { - if (type.toString() == SpecialNames.NO_NAME_PROVIDED.asString()) return "" return typeRenderer.renderType(type) } @@ -297,7 +337,7 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : } private fun qualifierNameCombine(descriptor: DeclarationDescriptor): String { - val nameString = descriptor.name.render() + val nameString = descriptor.name.render().let { if (it == SpecialNames.NO_NAME_PROVIDED.asString()) "" else it } if (nameString == FqName.ROOT.toString()) return "" val containingDeclaration = descriptor.containingDeclaration @@ -336,10 +376,12 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : if (KotlinBuiltIns.isNothing(klass.defaultType)) return val supertypes = klass.typeConstructor.supertypes - if (supertypes.isEmpty() || supertypes.size == 1 && KotlinBuiltIns.isAnyOrNullableAny(supertypes.iterator().next())) return + .filter { !KotlinBuiltIns.isAnyOrNullableAny(it) } + .map { renderType(it) } + .sorted() - builder.append(": ") - supertypes.joinTo(builder, ", ") { renderType(it) } + if (supertypes.isEmpty()) return + supertypes.joinTo(builder, prefix = ": ", separator = ", ") } private fun renderValueParameter( @@ -504,11 +546,17 @@ class PsiVisualizer(private val file: KtFile, analysisResult: AnalysisResult) : override fun visitPropertyDescriptor(property: PropertyDescriptor, data: StringBuilder) { data.append(if (property.isVar) "var" else "val").append(" ") - visitTypeParameters(property.typeParameters, data) - if (property.typeParameters.isNotEmpty()) data.append(" ") + + if (property !is SyntheticPropertyDescriptor) { + visitTypeParameters(property.typeParameters, data) + if (property.typeParameters.isNotEmpty()) data.append(" ") + } //render receiver - val receiver = renderReceiver(property, data) + val receiver = when (property) { + is SyntheticPropertyDescriptor -> renderReceiver(property.getMethod, data) + else -> renderReceiver(property, data) + } //render name data.append(renderName(property, receiver != null)) diff --git a/compiler/visualizer/testData/rawBuilder/declarations/NestedOfAliasedType.kt b/compiler/visualizer/testData/rawBuilder/declarations/NestedOfAliasedType.kt index 893bccbcd6f..2b5dde9d8c9 100644 --- a/compiler/visualizer/testData/rawBuilder/declarations/NestedOfAliasedType.kt +++ b/compiler/visualizer/testData/rawBuilder/declarations/NestedOfAliasedType.kt @@ -4,7 +4,7 @@ abstract class A { typealias TA = A -// fun TA.(): TA /* = A */ +// constructor A() // │ class B : TA() { // constructor A.Nested() diff --git a/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/propertyAccessorsContractDescription.kt b/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/propertyAccessorsContractDescription.kt index 05c509eb8f1..043519a102f 100644 --- a/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/propertyAccessorsContractDescription.kt +++ b/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/propertyAccessorsContractDescription.kt @@ -45,8 +45,9 @@ class SomeClass(multiplier: Int?) { // Int // │ get() contract [returnsNotNull()] = 1 -// Int [ERROR: unknown type] -// │ │ +// EQ operator call +// Int │ [ERROR: unknown type] +// │ │ │ set(value) contract [returns() implies (value != null)] { // SomeClass..value: Int // │ [ERROR: not resolved] diff --git a/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/simpleFunctionsContractDescription.kt b/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/simpleFunctionsContractDescription.kt index 44ba8ada1c3..a7b4bb684f9 100644 --- a/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/simpleFunctionsContractDescription.kt +++ b/compiler/visualizer/testData/rawBuilder/declarations/contracts/newSyntax/simpleFunctionsContractDescription.kt @@ -1,7 +1,8 @@ // FIR_IGNORE // new contracts syntax for simple functions -// [ERROR : MyClass]? [ERROR: unknown type] [ERROR: unknown type] -// │ │ │ +// EQ operator call +// [ERROR : MyClass]? │ [ERROR: unknown type] [ERROR: unknown type] +// │ │ │ │ fun test1(s: MyClass?) contract [returns() implies (s != null), returns() implies (s is MySubClass)] { // [ERROR: not resolved] // │ diff --git a/compiler/visualizer/testData/rawBuilder/declarations/functionTypes.kt b/compiler/visualizer/testData/rawBuilder/declarations/functionTypes.kt index be648389b48..ad2f7f71cf1 100644 --- a/compiler/visualizer/testData/rawBuilder/declarations/functionTypes.kt +++ b/compiler/visualizer/testData/rawBuilder/declarations/functionTypes.kt @@ -1,4 +1,4 @@ -// T fun (() -> T).invoke(): T +// T fun (() -> R).invoke(): R // │ │ fun simpleRun(f: () -> T): T = f() @@ -10,6 +10,6 @@ fun List.simpleMap(f: (T) -> R): R { // Unit // │ simpleWith.t: T -// │ │ fun T.invoke(): Unit +// │ │ fun P1.invoke(): R // │ │ │ fun simpleWith(t: T, f: T.() -> Unit): Unit = t.f() diff --git a/compiler/visualizer/testData/rawBuilder/declarations/simpleTypeAlias.kt b/compiler/visualizer/testData/rawBuilder/declarations/simpleTypeAlias.kt index 681b3eaa974..0a549422d7e 100644 --- a/compiler/visualizer/testData/rawBuilder/declarations/simpleTypeAlias.kt +++ b/compiler/visualizer/testData/rawBuilder/declarations/simpleTypeAlias.kt @@ -2,6 +2,6 @@ interface B typealias C = B -// C /* = B */ +// B // │ class D : C diff --git a/compiler/visualizer/testData/rawBuilder/declarations/typeAliasWithGeneric.kt b/compiler/visualizer/testData/rawBuilder/declarations/typeAliasWithGeneric.kt index 2e914b73ef4..cc85e4732f3 100644 --- a/compiler/visualizer/testData/rawBuilder/declarations/typeAliasWithGeneric.kt +++ b/compiler/visualizer/testData/rawBuilder/declarations/typeAliasWithGeneric.kt @@ -4,6 +4,6 @@ interface B typealias C = B -// C /* = B */ +// B // │ class D : C diff --git a/compiler/visualizer/testData/rawBuilder/expressions/for.kt b/compiler/visualizer/testData/rawBuilder/expressions/for.kt index 313314af5cc..ce2f60fed88 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/for.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/for.kt @@ -40,7 +40,7 @@ fun fooLabeled() { // │ fun bar(list: List) { // bar.list: collections/List -// │ fun (collections/List).subList(Int, Int): collections/List +// │ fun (collections/List).subList(Int, Int): collections/List // │ │ Int // String │ │ │ Int // │ │ │ │ │ @@ -51,7 +51,7 @@ fun bar(list: List) { println(element) } // bar.list: collections/List -// │ fun (collections/List).subList(Int, Int): collections/List +// │ fun (collections/List).subList(Int, Int): collections/List // │ │ fun io/println(Any?): Unit // String │ │ Int Int │ val bar.element: String // │ │ │ │ │ │ │ diff --git a/compiler/visualizer/testData/rawBuilder/expressions/in.kt b/compiler/visualizer/testData/rawBuilder/expressions/in.kt index c66399a3765..7086704d4e3 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/in.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/in.kt @@ -4,10 +4,10 @@ // │ │ fun foo(x: Int, y: Int, c: Collection) = // foo.x: Int -// │ fun (collections/Collection).contains(Int): Boolean +// │ fun (collections/Collection).contains(E): Boolean // │ │ foo.c: collections/Collection // │ │ │ foo.y: Int -// │ │ │ │ fun (collections/Collection).contains(Int): Boolean +// │ │ │ │ fun (collections/Collection).contains(E): Boolean // │ │ │ │ │ foo.c: collections/Collection // │ │ │ │ │ │ x in c && y !in c diff --git a/compiler/visualizer/testData/rawBuilder/expressions/inBrackets.kt b/compiler/visualizer/testData/rawBuilder/expressions/inBrackets.kt index eee73cdc94e..5afdd3478ce 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/inBrackets.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/inBrackets.kt @@ -2,12 +2,12 @@ fun test(e: Int.() -> String) { // String // │ Int -// │ │ fun Int.invoke(): String +// │ │ fun P1.invoke(): R // │ │ │ val s = 3.e() // String // │ Int -// │ │ fun Int.invoke(): String +// │ │ fun P1.invoke(): R // │ │ │test.e: Int.() -> String // │ │ ││ val ss = 3.(e)() diff --git a/compiler/visualizer/testData/rawBuilder/expressions/lambda.kt b/compiler/visualizer/testData/rawBuilder/expressions/lambda.kt index dcfa0d4504d..d3d92722796 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/lambda.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/lambda.kt @@ -3,7 +3,7 @@ data class Tuple(val x: Int, val y: Int) // Int -// │ fun ((Tuple) -> Int).invoke(Tuple): Int +// │ fun ((P1) -> R).invoke(P1): R // │ │ constructor Tuple(Int, Int) // │ │ │ Int // │ │ │ │ Int diff --git a/compiler/visualizer/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt b/compiler/visualizer/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt index 10ab80d27af..4db6e4e269f 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt @@ -1,5 +1,5 @@ // FIR_IGNORE -// T fun (() -> T).invoke(): T +// T fun (() -> R).invoke(): R // │ │ fun run(block: () -> T): T = block() diff --git a/compiler/visualizer/testData/rawBuilder/expressions/locals.kt b/compiler/visualizer/testData/rawBuilder/expressions/locals.kt index b7bc7b222ae..3185c8dc533 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/locals.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/locals.kt @@ -1,4 +1,3 @@ -// FIR_IGNORE fun withLocals(p: Int): Int { class Local(val pp: Int) { // Int @@ -17,7 +16,7 @@ fun withLocals(p: Int): Int { fun sum(y: Int, z: Int, f: (Int, Int) -> Int): Int { // val withLocals.x: Int // │ fun (Int).plus(Int): Int -// │ │ fun ((Int, Int) -> Int).invoke(Int, Int): Int +// │ │ fun ((P1, P2) -> R).invoke(P1, P2): R // │ │ │ withLocals.sum.y: Int // │ │ │ │ withLocals.sum.z: Int // │ │ │ │ │ @@ -41,9 +40,9 @@ fun withLocals(p: Int): Int { // │ │ │ Int // │ │ │ │ fun (withLocals.Local).diff(): Int // │ │ │ │ │ Int -// │ │ │ │ │ │ withLocals..x: Int +// │ │ │ │ │ │ withLocals..x: Int // │ │ │ │ │ │ │ fun (Int).plus(Int): Int -// │ │ │ │ │ │ │ │ withLocals..y: Int +// │ │ │ │ │ │ │ │ withLocals..y: Int // │ │ │ │ │ │ │ │ │ return sum(code, Local(1).diff(), fun(x: Int, y: Int) = x + y) } diff --git a/compiler/visualizer/testData/rawBuilder/expressions/qualifierWithTypeArguments.kt b/compiler/visualizer/testData/rawBuilder/expressions/qualifierWithTypeArguments.kt index 68849bf4d42..da5eb616d58 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/qualifierWithTypeArguments.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/qualifierWithTypeArguments.kt @@ -1,5 +1,5 @@ fun test() { -// class Array: Any, Cloneable, java/io/Serializable +// class Array: java/io/Serializable, Cloneable // │ Array::class } diff --git a/compiler/visualizer/testData/rawBuilder/expressions/try.kt b/compiler/visualizer/testData/rawBuilder/expressions/try.kt index f0532163526..5fa789f110a 100644 --- a/compiler/visualizer/testData/rawBuilder/expressions/try.kt +++ b/compiler/visualizer/testData/rawBuilder/expressions/try.kt @@ -4,13 +4,13 @@ fun some() { // constructor KotlinNullPointerException() // │ throw KotlinNullPointerException() -// RuntimeException /* = java/lang/RuntimeException */ +// java/lang/RuntimeException // │ } catch (e: RuntimeException) { // fun io/println(Any?): Unit // │ println("Runtime exception") -// Exception /* = java/lang/Exception */ +// java/lang/Exception // │ } catch (e: Exception) { // fun io/println(Any?): Unit diff --git a/compiler/visualizer/testData/uncommonCases/resultFiles/dataClass.kt b/compiler/visualizer/testData/uncommonCases/resultFiles/dataClass.kt index 6a6c23c5612..e6803708c0f 100644 --- a/compiler/visualizer/testData/uncommonCases/resultFiles/dataClass.kt +++ b/compiler/visualizer/testData/uncommonCases/resultFiles/dataClass.kt @@ -48,7 +48,7 @@ fun main() { println("a hash - ${a.hashCode()}") // val main.a: Vector -// │ EQ operator call +// │ fun (Vector).equals(Any?): Boolean // fun io/println(Any?): Unit │ │ val main.b: Vector // │ │ │ │ println("a is equal to b ${a.equals(b)}") diff --git a/compiler/visualizer/testData/uncommonCases/resultFiles/delegation.kt b/compiler/visualizer/testData/uncommonCases/resultFiles/delegation.kt index b9e3ca590ae..30ebb4349f9 100644 --- a/compiler/visualizer/testData/uncommonCases/resultFiles/delegation.kt +++ b/compiler/visualizer/testData/uncommonCases/resultFiles/delegation.kt @@ -35,7 +35,7 @@ fun main() { Derived(b).printMessage() // constructor Derived(Base) // │ val main.b: BaseImpl -// │ │ fun (Derived).printMessageLine(): Unit +// │ │ fun (Base).printMessageLine(): Unit // │ │ │ Derived(b).printMessageLine() } diff --git a/compiler/visualizer/testData/uncommonCases/resultFiles/lists.kt b/compiler/visualizer/testData/uncommonCases/resultFiles/lists.kt index f9486587787..915a6730a62 100644 --- a/compiler/visualizer/testData/uncommonCases/resultFiles/lists.kt +++ b/compiler/visualizer/testData/uncommonCases/resultFiles/lists.kt @@ -20,7 +20,7 @@ fun move(): java.util.ArrayList { // │ │ for (elem in listOfInt) { // val javaList: java/util/ArrayList -// │ fun (java/util/ArrayList).add(Int): Boolean +// │ fun (java/util/ArrayList).add(E): Boolean // │ │ val move.elem: Int // │ │ │ javaList.add(elem) diff --git a/compiler/visualizer/testData/uncommonCases/resultFiles/superTypes.kt b/compiler/visualizer/testData/uncommonCases/resultFiles/superTypes.kt index 3715df1ca3e..f8d9e73a73d 100644 --- a/compiler/visualizer/testData/uncommonCases/resultFiles/superTypes.kt +++ b/compiler/visualizer/testData/uncommonCases/resultFiles/superTypes.kt @@ -1,16 +1,15 @@ -// FIR_IGNORE package org.jetbrains.kotlin.test abstract class Base(var x: T) { abstract fun replace(newValue: T) } -// constructor Base(T) -// │ Derived..x: Int -// │ │ -class Derived(var x: Int): Base(x) { +// constructor Base(T) +// │ Derived..x: Int +// │ │ +class Derived(x: Int): Base(x) { override fun replace(newValue: Int) { -// var (Derived).x: Int +// var (Base).x: T // │ Derived.replace.newValue: Int // │ │ x = newValue diff --git a/compiler/visualizer/testData/uncommonCases/resultFiles/variance.kt b/compiler/visualizer/testData/uncommonCases/resultFiles/variance.kt index 2009bb5aea2..146abe7ed2c 100644 --- a/compiler/visualizer/testData/uncommonCases/resultFiles/variance.kt +++ b/compiler/visualizer/testData/uncommonCases/resultFiles/variance.kt @@ -14,7 +14,7 @@ interface Comparable { fun demo(x: Comparable) { // demo.x: Comparable -// │ fun (Comparable).compareTo(Number): Int +// │ fun (Comparable).compareTo(T): Int // │ │ Double // │ │ │ x.compareTo(1.0) diff --git a/compiler/visualizer/testData/uncommonCases/testFiles/superTypes.kt b/compiler/visualizer/testData/uncommonCases/testFiles/superTypes.kt index 7efe6b1f347..1af1202a02f 100644 --- a/compiler/visualizer/testData/uncommonCases/testFiles/superTypes.kt +++ b/compiler/visualizer/testData/uncommonCases/testFiles/superTypes.kt @@ -4,7 +4,7 @@ abstract class Base(var x: T) { abstract fun replace(newValue: T) } -class Derived(var x: Int): Base(x) { +class Derived(x: Int): Base(x) { override fun replace(newValue: Int) { x = newValue }