[FIR IDE] Add getDispatchReceiverType function and use

This function is under a heavy deprecation and should not be used,
since it will most probably be removed in the future
This commit is contained in:
Roman Golyshev
2021-10-26 16:07:53 +03:00
committed by TeamCityServer
parent 3091269035
commit 4e1e1570df
4 changed files with 58 additions and 7 deletions
@@ -5,21 +5,26 @@
package org.jetbrains.kotlin.analysis.api.descriptors.components package org.jetbrains.kotlin.analysis.api.descriptors.components
import org.jetbrains.kotlin.analysis.api.assertIsValidAndAccessible
import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes
import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode
import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.base.KtFe10Symbol
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.KtFe10DescSymbol
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.classId import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.classId
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.getSymbolDescriptor import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.getSymbolDescriptor
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.isInterfaceLike import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.isInterfaceLike
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtType import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtType
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.KtFe10PsiSymbol
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.getResolutionScope import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.getResolutionScope
import org.jetbrains.kotlin.analysis.api.descriptors.types.base.KtFe10Type import org.jetbrains.kotlin.analysis.api.descriptors.types.base.KtFe10Type
import org.jetbrains.kotlin.analysis.api.descriptors.utils.PublicApproximatorConfiguration import org.jetbrains.kotlin.analysis.api.descriptors.utils.PublicApproximatorConfiguration
import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
@@ -39,7 +44,6 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewCapturedType import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.supertypes
import org.jetbrains.kotlin.util.containingNonLocalDeclaration import org.jetbrains.kotlin.util.containingNonLocalDeclaration
internal class KtFe10TypeProvider( internal class KtFe10TypeProvider(
@@ -115,6 +119,19 @@ internal class KtFe10TypeProvider(
return TypeUtils.getAllSupertypes(type.type).map { it.toKtType(analysisContext) } return TypeUtils.getAllSupertypes(type.type).map { it.toKtType(analysisContext) }
} }
override fun getDispatchReceiverType(symbol: KtPossibleMemberSymbol): KtType? {
assertIsValidAndAccessible()
require(symbol is KtFe10Symbol)
val descriptor = when (symbol) {
is KtFe10DescSymbol<*> -> symbol.descriptor as? CallableDescriptor
is KtFe10PsiSymbol<*, *> -> symbol.descriptor as? CallableDescriptor
else -> error("No callable descriptor on $symbol")
}
return descriptor?.dispatchReceiverParameter?.type?.toKtType(analysisContext)
}
private fun areTypesCompatible(a: KotlinType, b: KotlinType): Boolean { private fun areTypesCompatible(a: KotlinType, b: KotlinType): Boolean {
if (a.isNothing() || b.isNothing() || TypeUtils.equalTypes(a, b) || (a.isNullable() && b.isNullable())) { if (a.isNothing() || b.isNothing() || TypeUtils.equalTypes(a, b) || (a.isNullable() && b.isNullable())) {
return true return true
@@ -9,10 +9,12 @@ import org.jetbrains.kotlin.analysis.api.components.KtBuiltinTypes
import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider import org.jetbrains.kotlin.analysis.api.components.KtTypeProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator
import org.jetbrains.kotlin.analysis.api.fir.utils.toConeNullability import org.jetbrains.kotlin.analysis.api.fir.utils.toConeNullability
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
@@ -25,6 +27,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker
import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.isCompatible import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.isCompatible
import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
@@ -183,5 +186,17 @@ internal class KtFirTypeProvider(
.drop(1) .drop(1)
.mapTo(mutableListOf()) { it.asKtType() } .mapTo(mutableListOf()) { it.asKtType() }
} }
override fun getDispatchReceiverType(symbol: KtPossibleMemberSymbol): KtType? {
require(symbol is KtFirSymbol<*>)
return symbol.firRef.withFir { declaration ->
check(declaration is FirCallableDeclaration) {
"Fir declaration should be FirCallableDeclaration; instead it was ${declaration::class}"
}
declaration.dispatchReceiverType?.asKtType()
}
}
} }
@@ -37,7 +37,7 @@ abstract class AbstractResolveCallTest(configurator: FrontendApiTestConfigurator
val actual = executeOnPooledThreadInReadAction { val actual = executeOnPooledThreadInReadAction {
analyseForTest(expression) { analyseForTest(expression) {
resolveCall(expression)?.stringRepresentation() resolveCall(expression)?.let { stringRepresentation(it) }
} }
} ?: "null" } ?: "null"
testServices.assertions.assertEqualsToTestDataFileSibling(actual) testServices.assertions.assertEqualsToTestDataFileSibling(actual)
@@ -62,8 +62,8 @@ abstract class AbstractResolveCallTest(configurator: FrontendApiTestConfigurator
} }
private fun KtCall.stringRepresentation(): String { private fun KtAnalysisSession.stringRepresentation(call: KtCall): String {
fun KtType.render() = substitutor.substituteOrSelf(this).asStringForDebugging().replace('/', '.') fun KtType.render() = call.substitutor.substituteOrSelf(this).asStringForDebugging().replace('/', '.')
fun Any.stringValue(): String = when (this) { fun Any.stringValue(): String = when (this) {
is KtFunctionLikeSymbol -> buildString { is KtFunctionLikeSymbol -> buildString {
append( append(
@@ -81,7 +81,9 @@ private fun KtCall.stringRepresentation(): String {
append("<extension receiver>: ${receiver.type.render()}") append("<extension receiver>: ${receiver.type.render()}")
if (valueParameters.isNotEmpty()) append(", ") if (valueParameters.isNotEmpty()) append(", ")
} }
(this@stringValue as? KtPossibleMemberSymbol)?.dispatchType?.let { dispatchReceiverType ->
@Suppress("DEPRECATION")
(this@stringValue as? KtPossibleMemberSymbol)?.getDispatchReceiverType()?.let { dispatchReceiverType ->
append("<dispatch receiver>: ${dispatchReceiverType.render()}") append("<dispatch receiver>: ${dispatchReceiverType.render()}")
if (valueParameters.isNotEmpty()) append(", ") if (valueParameters.isNotEmpty()) append(", ")
} }
@@ -108,7 +110,7 @@ private fun KtCall.stringRepresentation(): String {
else -> error("unexpected parameter type ${this::class}") else -> error("unexpected parameter type ${this::class}")
} }
val callInfoClass = this::class val callInfoClass = call::class
return buildString { return buildString {
append(callInfoClass.simpleName!!) append(callInfoClass.simpleName!!)
append(":\n") append(":\n")
@@ -118,7 +120,7 @@ private fun KtCall.stringRepresentation(): String {
.filter { it.name != "token" } .filter { it.name != "token" }
.joinTo(this, separator = "\n") { parameter -> .joinTo(this, separator = "\n") { parameter ->
val name = parameter.name!!.removePrefix("_") val name = parameter.name!!.removePrefix("_")
val value = propertyByName[name]!!.javaGetter!!(this@stringRepresentation)?.stringValue() val value = propertyByName[name]!!.javaGetter!!(call)?.stringValue()
"$name = $value" "$name = $value"
} }
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.components
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
import org.jetbrains.kotlin.analysis.api.types.KtFlexibleType import org.jetbrains.kotlin.analysis.api.types.KtFlexibleType
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
@@ -37,6 +38,7 @@ public abstract class KtTypeProvider : KtAnalysisSessionComponent() {
public abstract fun getAllSuperTypes(type: KtType, shouldApproximate: Boolean): List<KtType> public abstract fun getAllSuperTypes(type: KtType, shouldApproximate: Boolean): List<KtType>
public abstract fun getDispatchReceiverType(symbol: KtPossibleMemberSymbol): KtType?
} }
public interface KtTypeProviderMixIn : KtAnalysisSessionMixIn { public interface KtTypeProviderMixIn : KtAnalysisSessionMixIn {
@@ -118,6 +120,21 @@ public interface KtTypeProviderMixIn : KtAnalysisSessionMixIn {
*/ */
public fun KtType.getAllSuperTypes(shouldApproximate: Boolean = false): List<KtType> = public fun KtType.getAllSuperTypes(shouldApproximate: Boolean = false): List<KtType> =
analysisSession.typeProvider.getAllSuperTypes(this, shouldApproximate) analysisSession.typeProvider.getAllSuperTypes(this, shouldApproximate)
/**
* This function is provided for a few use-cases where it's hard to go without it.
*
* **Please avoid using it**; it will probably be removed in the future.
*
* The function is instantly deprecated, so it's not shown in the completion.
*
* @receiver A target callable symbol.
* @return A dispatch receiver type for this symbol if it has any.
*/
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated("Avoid using this function")
public fun KtPossibleMemberSymbol.getDispatchReceiverType(): KtType? =
analysisSession.typeProvider.getDispatchReceiverType(this)
} }
@Suppress("PropertyName") @Suppress("PropertyName")