[FIR IDE] Make KtSmartcastProvider report resolved smartcast type

This commit is contained in:
Tianyu Geng
2021-02-04 11:59:23 -08:00
committed by Ilya Kirillov
parent d97a2b13c0
commit 58d903c638
5 changed files with 28 additions and 32 deletions
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.idea.fir.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -18,25 +18,23 @@ internal class ExpressionsSmartcastHighlightingVisitor(
holder: AnnotationHolder holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) { ) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitExpression(expression: KtExpression) = with(analysisSession) { override fun visitExpression(expression: KtExpression) = with(analysisSession) {
expression.getImplicitReceiverSmartCasts().forEach { (types, kind) -> expression.getImplicitReceiverSmartCast().forEach { (type, kind) ->
val receiverName = when (kind) { val receiverName = when (kind) {
ImplicitReceiverSmartcastKind.EXTENSION -> KotlinIdeaAnalysisBundle.message("extension.implicit.receiver") ImplicitReceiverSmartcastKind.EXTENSION -> KotlinIdeaAnalysisBundle.message("extension.implicit.receiver")
ImplicitReceiverSmartcastKind.DISPATCH -> KotlinIdeaAnalysisBundle.message("implicit.receiver") ImplicitReceiverSmartcastKind.DISPATCH -> KotlinIdeaAnalysisBundle.message("implicit.receiver")
} }
types.forEach { type -> createInfoAnnotation(
createInfoAnnotation( expression,
expression, KotlinIdeaAnalysisBundle.message(
KotlinIdeaAnalysisBundle.message( "0.smart.cast.to.1",
"0.smart.cast.to.1", receiverName,
receiverName, type.asStringForDebugging()
type.asStringForDebugging() ),
), KotlinHighlightingColors.SMART_CAST_RECEIVER
KotlinHighlightingColors.SMART_CAST_RECEIVER )
)
}
} }
expression.getSmartCasts()?.forEach { type -> expression.getSmartCast()?.let { type ->
createInfoAnnotation( createInfoAnnotation(
getSmartCastTarget(expression), getSmartCastTarget(expression),
KotlinIdeaAnalysisBundle.message( KotlinIdeaAnalysisBundle.message(
@@ -47,8 +45,6 @@ internal class ExpressionsSmartcastHighlightingVisitor(
) )
} }
//todo smartcast to null
super.visitExpression(expression) super.visitExpression(expression)
} }
} }
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api
import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.idea.frontend.api.types.KtType
data class ImplicitReceiverSmartCast(val types: Collection<KtType>, val kind: ImplicitReceiverSmartcastKind) data class ImplicitReceiverSmartCast(val type: KtType, val kind: ImplicitReceiverSmartcastKind)
enum class ImplicitReceiverSmartcastKind { enum class ImplicitReceiverSmartcastKind {
DISPATCH, EXTENSION DISPATCH, EXTENSION
@@ -61,10 +61,10 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
fun KtCallableSymbol.getIntersectionOverriddenSymbols(): Collection<KtCallableSymbol> = fun KtCallableSymbol.getIntersectionOverriddenSymbols(): Collection<KtCallableSymbol> =
symbolDeclarationOverridesProvider.getIntersectionOverriddenSymbols(this) symbolDeclarationOverridesProvider.getIntersectionOverriddenSymbols(this)
fun KtExpression.getSmartCasts(): Collection<KtType> = smartCastProvider.getSmartCastedToTypes(this) fun KtExpression.getSmartCast(): KtType? = smartCastProvider.getSmartCastedToType(this)
fun KtExpression.getImplicitReceiverSmartCasts(): Collection<ImplicitReceiverSmartCast> = fun KtExpression.getImplicitReceiverSmartCast(): Collection<ImplicitReceiverSmartCast> =
smartCastProvider.getImplicitReceiverSmartCasts(this) smartCastProvider.getImplicitReceiverSmartCast(this)
fun KtExpression.getKtType(): KtType = expressionTypeProvider.getKtExpressionType(this) fun KtExpression.getKtType(): KtType = expressionTypeProvider.getKtExpressionType(this)
@@ -10,6 +10,6 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
abstract class KtSmartCastProvider : KtAnalysisSessionComponent() { abstract class KtSmartCastProvider : KtAnalysisSessionComponent() {
abstract fun getSmartCastedToTypes(expression: KtExpression): Collection<KtType> abstract fun getSmartCastedToType(expression: KtExpression): KtType?
abstract fun getImplicitReceiverSmartCasts(expression: KtExpression): Collection<ImplicitReceiverSmartCast> abstract fun getImplicitReceiverSmartCast(expression: KtExpression): Collection<ImplicitReceiverSmartCast>
} }
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirSafe import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirSafe
import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartCast import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartCast
import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind
@@ -20,18 +22,16 @@ import org.jetbrains.kotlin.psi.KtExpression
internal class KtFirSmartcastProvider( internal class KtFirSmartcastProvider(
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken, override val token: ValidityToken,
) : KtSmartCastProvider(), KtFirAnalysisSessionComponent { ) : KtSmartCastProvider(), KtFirAnalysisSessionComponent {
override fun getSmartCastedToTypes(expression: KtExpression): Collection<KtType> = withValidityAssertion { override fun getSmartCastedToType(expression: KtExpression): KtType? = withValidityAssertion {
// TODO filter out not used smartcasts
expression.getOrBuildFirSafe<FirExpressionWithSmartcast>(analysisSession.firResolveState) expression.getOrBuildFirSafe<FirExpressionWithSmartcast>(analysisSession.firResolveState)
?.typesFromSmartCast ?.typeRef
?.map { it.asKtType() } ?.coneTypeSafe<ConeKotlinType>()
?: emptyList() ?.asKtType()
} }
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
override fun getImplicitReceiverSmartCasts(expression: KtExpression): Collection<ImplicitReceiverSmartCast> = withValidityAssertion { override fun getImplicitReceiverSmartCast(expression: KtExpression): Collection<ImplicitReceiverSmartCast> = withValidityAssertion {
// TODO filter out not used smartcasts
val qualifiedExpression = val qualifiedExpression =
expression.getOrBuildFirSafe<FirQualifiedAccessExpression>(analysisSession.firResolveState) ?: return emptyList() expression.getOrBuildFirSafe<FirQualifiedAccessExpression>(analysisSession.firResolveState) ?: return emptyList()
if (qualifiedExpression.dispatchReceiver !is FirExpressionWithSmartcast if (qualifiedExpression.dispatchReceiver !is FirExpressionWithSmartcast
@@ -40,13 +40,13 @@ internal class KtFirSmartcastProvider(
buildList { buildList {
(qualifiedExpression.dispatchReceiver as? FirExpressionWithSmartcast)?.let { smartCasted -> (qualifiedExpression.dispatchReceiver as? FirExpressionWithSmartcast)?.let { smartCasted ->
ImplicitReceiverSmartCast( ImplicitReceiverSmartCast(
smartCasted.typesFromSmartCast.map { it.asKtType() }, smartCasted.typeRef.coneTypeSafe<ConeKotlinType>()?.asKtType() ?: return@let null,
ImplicitReceiverSmartcastKind.DISPATCH ImplicitReceiverSmartcastKind.DISPATCH
) )
}?.let(::add) }?.let(::add)
(qualifiedExpression.extensionReceiver as? FirExpressionWithSmartcast)?.let { smartCasted -> (qualifiedExpression.extensionReceiver as? FirExpressionWithSmartcast)?.let { smartCasted ->
ImplicitReceiverSmartCast( ImplicitReceiverSmartCast(
smartCasted.typesFromSmartCast.map { it.asKtType() }, smartCasted.typeRef.coneTypeSafe<ConeKotlinType>()?.asKtType() ?: return@let null,
ImplicitReceiverSmartcastKind.EXTENSION ImplicitReceiverSmartcastKind.EXTENSION
) )
}?.let(::add) }?.let(::add)