[VISUALIZER] Render original symbols/descriptors in fir/psi
This commit is contained in:
committed by
TeamCityServer
parent
869585870d
commit
e19514f1dc
+143
-104
@@ -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 = "<anonymous>"
|
||||
private typealias Stack = MutableList<Pair<String, MutableList<String>>>
|
||||
|
||||
class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
||||
private val implicitReceivers = mutableListOf<FirTypeRef>()
|
||||
private val implicitReceivers = mutableListOf<ConeKotlinType>()
|
||||
|
||||
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 ?: "<anonymous>"))
|
||||
stack.push((element.name ?: "<anonymous>"))
|
||||
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 ?: "<no name provided>")
|
||||
stack.push((function.name ?: "<no name provided>"))
|
||||
if (function.isLocal) stack.addName(function.name ?: ANONYMOUS_NAME)
|
||||
stack.push((function.name ?: ANONYMOUS_NAME))
|
||||
if (function.equalsToken != null) {
|
||||
function.bodyExpression!!.firstOfTypeWithRender<FirReturnExpression>(function.equalsToken) { this.result.typeRef }
|
||||
?: function.firstOfTypeWithRender<FirTypedDeclaration>(function.equalsToken) { this.returnTypeRef }
|
||||
@@ -174,7 +180,7 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
||||
renderVariableType(multiDeclarationEntry)
|
||||
|
||||
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) {
|
||||
annotationEntry.firstOfTypeWithRender<FirAnnotationCall>(annotationEntry.children.first())
|
||||
annotationEntry.firstOfTypeWithRender<FirAnnotationCall>(annotationEntry.getChildOfType<KtConstructorCalleeExpression>())
|
||||
super.visitAnnotationEntry(annotationEntry)
|
||||
}
|
||||
|
||||
@@ -262,9 +268,10 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
|
||||
val firLambda = psi.firstOfType<FirLambdaArgumentExpression>()?.expression as? FirAnonymousFunction
|
||||
firLambda?.receiverTypeRef?.let {
|
||||
lastCallWithLambda = psi.getLambdaExpression()?.firstOfType<FirLabel>()?.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("<anonymous>")
|
||||
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 <T : FirElement> renderListInTriangles(list: List<T>, 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<FirExpression>, data: StringBuilder) {
|
||||
arguments.joinTo(data, ", ", "(", ")") {
|
||||
if (it is FirResolvedQualifier) {
|
||||
val lookupTag = (it.typeRef as FirResolvedTypeRef).coneTypeSafe<ConeClassLikeType>()?.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 <reified D : FirCallableDeclaration<*>> 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 <reified D : FirCallableDeclaration<*>> 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<FirConstructor>().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<FirConstructor>().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(".<init>(): ").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<FirValueParameter>, 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<ConeClassLikeType>()?.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 " <T>"
|
||||
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<ConeClassLikeType>().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 -> ""
|
||||
|
||||
+65
-17
@@ -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<out CallableDescriptor>? {
|
||||
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 "<anonymous>"
|
||||
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 "<anonymous>"
|
||||
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()) "<anonymous>" 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))
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ abstract class A {
|
||||
|
||||
typealias TA = A
|
||||
|
||||
// fun TA.<init>(): TA /* = A */
|
||||
// constructor A()
|
||||
// │
|
||||
class B : TA() {
|
||||
// constructor A.Nested()
|
||||
|
||||
+3
-2
@@ -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.<set-someInt>.value: Int
|
||||
// │ [ERROR: not resolved]
|
||||
|
||||
+3
-2
@@ -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]
|
||||
// │
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// T fun (() -> T).invoke(): T
|
||||
// T fun (() -> R).invoke(): R
|
||||
// │ │
|
||||
fun <T> simpleRun(f: () -> T): T = f()
|
||||
|
||||
@@ -10,6 +10,6 @@ fun <T, R> List<T>.simpleMap(f: (T) -> R): R {
|
||||
|
||||
// Unit
|
||||
// │ simpleWith.t: T
|
||||
// │ │ fun T.invoke(): Unit
|
||||
// │ │ fun P1.invoke(): R
|
||||
// │ │ │
|
||||
fun <T> simpleWith(t: T, f: T.() -> Unit): Unit = t.f()
|
||||
|
||||
@@ -2,6 +2,6 @@ interface B
|
||||
|
||||
typealias C = B
|
||||
|
||||
// C /* = B */
|
||||
// B
|
||||
// │
|
||||
class D : C
|
||||
|
||||
+1
-1
@@ -4,6 +4,6 @@ interface B<S, T : A>
|
||||
|
||||
typealias C<T> = B<T, A>
|
||||
|
||||
// C<A> /* = B<A, A> */
|
||||
// B<A, A>
|
||||
// │
|
||||
class D : C<A>
|
||||
|
||||
@@ -40,7 +40,7 @@ fun fooLabeled() {
|
||||
// │
|
||||
fun bar(list: List<String>) {
|
||||
// bar.list: collections/List<String>
|
||||
// │ fun (collections/List<String>).subList(Int, Int): collections/List<String>
|
||||
// │ fun (collections/List<E>).subList(Int, Int): collections/List<E>
|
||||
// │ │ Int
|
||||
// String │ │ │ Int
|
||||
// │ │ │ │ │
|
||||
@@ -51,7 +51,7 @@ fun bar(list: List<String>) {
|
||||
println(element)
|
||||
}
|
||||
// bar.list: collections/List<String>
|
||||
// │ fun (collections/List<String>).subList(Int, Int): collections/List<String>
|
||||
// │ fun (collections/List<E>).subList(Int, Int): collections/List<E>
|
||||
// │ │ fun io/println(Any?): Unit
|
||||
// String │ │ Int Int │ val bar.element: String
|
||||
// │ │ │ │ │ │ │
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
// │ │
|
||||
fun foo(x: Int, y: Int, c: Collection<Int>) =
|
||||
// foo.x: Int
|
||||
// │ fun (collections/Collection<Int>).contains(Int): Boolean
|
||||
// │ fun (collections/Collection<E>).contains(E): Boolean
|
||||
// │ │ foo.c: collections/Collection<Int>
|
||||
// │ │ │ foo.y: Int
|
||||
// │ │ │ │ fun (collections/Collection<Int>).contains(Int): Boolean
|
||||
// │ │ │ │ fun (collections/Collection<E>).contains(E): Boolean
|
||||
// │ │ │ │ │ foo.c: collections/Collection<Int>
|
||||
// │ │ │ │ │ │
|
||||
x in c && y !in c
|
||||
|
||||
@@ -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)()
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIR_IGNORE
|
||||
// T fun (() -> T).invoke(): T
|
||||
// T fun (() -> R).invoke(): R
|
||||
// │ │
|
||||
fun <T> run(block: () -> T): T = block()
|
||||
|
||||
|
||||
@@ -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.<no name provided>.x: Int
|
||||
// │ │ │ │ │ │ withLocals.<anonymous>.x: Int
|
||||
// │ │ │ │ │ │ │ fun (Int).plus(Int): Int
|
||||
// │ │ │ │ │ │ │ │ withLocals.<no name provided>.y: Int
|
||||
// │ │ │ │ │ │ │ │ withLocals.<anonymous>.y: Int
|
||||
// │ │ │ │ │ │ │ │ │
|
||||
return sum(code, Local(1).diff(), fun(x: Int, y: Int) = x + y)
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fun test() {
|
||||
// class Array<T>: Any, Cloneable, java/io/Serializable
|
||||
// class Array<T>: java/io/Serializable, Cloneable
|
||||
// │
|
||||
Array<String>::class
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)}")
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ fun move(): java.util.ArrayList<Int> {
|
||||
// │ │
|
||||
for (elem in listOfInt) {
|
||||
// val javaList: java/util/ArrayList<Int>
|
||||
// │ fun (java/util/ArrayList<Int>).add(Int): Boolean
|
||||
// │ fun (java/util/ArrayList<E>).add(E): Boolean
|
||||
// │ │ val move.elem: Int
|
||||
// │ │ │
|
||||
javaList.add(elem)
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
// FIR_IGNORE
|
||||
package org.jetbrains.kotlin.test
|
||||
|
||||
abstract class Base<T>(var x: T) {
|
||||
abstract fun replace(newValue: T)
|
||||
}
|
||||
|
||||
// constructor Base<T>(T)
|
||||
// │ Derived.<init>.x: Int
|
||||
// │ │
|
||||
class Derived(var x: Int): Base<Int>(x) {
|
||||
// constructor Base<T>(T)
|
||||
// │ Derived.<init>.x: Int
|
||||
// │ │
|
||||
class Derived(x: Int): Base<Int>(x) {
|
||||
override fun replace(newValue: Int) {
|
||||
// var (Derived).x: Int
|
||||
// var (Base<T>).x: T
|
||||
// │ Derived.replace.newValue: Int
|
||||
// │ │
|
||||
x = newValue
|
||||
|
||||
@@ -14,7 +14,7 @@ interface Comparable<in T> {
|
||||
|
||||
fun demo(x: Comparable<Number>) {
|
||||
// demo.x: Comparable<Number>
|
||||
// │ fun (Comparable<Number>).compareTo(Number): Int
|
||||
// │ fun (Comparable<T>).compareTo(T): Int
|
||||
// │ │ Double
|
||||
// │ │ │
|
||||
x.compareTo(1.0)
|
||||
|
||||
@@ -4,7 +4,7 @@ abstract class Base<T>(var x: T) {
|
||||
abstract fun replace(newValue: T)
|
||||
}
|
||||
|
||||
class Derived(var x: Int): Base<Int>(x) {
|
||||
class Derived(x: Int): Base<Int>(x) {
|
||||
override fun replace(newValue: Int) {
|
||||
x = newValue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user