FIR IDE: Add KtVisibilityChecker component

This commit is contained in:
Roman Golyshev
2021-03-26 23:05:05 +03:00
committed by Space
parent 28d8d2d903
commit ff71dda065
4 changed files with 121 additions and 1 deletions
@@ -40,7 +40,8 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
KtSymbolsMixIn,
KtReferenceResolveMixIn,
KtReferenceShortenerMixIn,
KtSymbolDeclarationRendererMixIn {
KtSymbolDeclarationRendererMixIn,
KtVisibilityCheckerMixIn {
override val analysisSession: KtAnalysisSession get() = this
@@ -90,4 +91,7 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
internal val expressionInfoProvider: KtExpressionInfoProvider get() = expressionInfoProviderImpl
protected abstract val expressionInfoProviderImpl: KtExpressionInfoProvider
internal val visibilityChecker: KtVisibilityChecker get() = visibilityCheckerImpl
protected abstract val visibilityCheckerImpl: KtVisibilityChecker
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.frontend.api.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.psi.KtExpression
abstract class KtVisibilityChecker : KtAnalysisSessionComponent() {
abstract fun isVisible(
candidateSymbol: KtSymbolWithVisibility,
useSiteFile: KtFileSymbol,
position: PsiElement,
receiverExpression: KtExpression?
): Boolean
}
interface KtVisibilityCheckerMixIn : KtAnalysisSessionMixIn {
fun isVisible(
candidateSymbol: KtSymbolWithVisibility,
useSiteFile: KtFileSymbol,
receiverExpression: KtExpression? = null,
position: PsiElement
): Boolean =
analysisSession.visibilityChecker.isVisible(candidateSymbol, useSiteFile, position, receiverExpression)
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCo
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile
import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.components.KtVisibilityChecker
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.components.KtSymbolDeclarationRendererProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.components.*
@@ -61,6 +62,8 @@ private constructor(
override val expressionInfoProviderImpl = KtFirExpressionInfoProvider(this, token)
override val visibilityCheckerImpl: KtVisibilityChecker = KtFirVisibilityChecker(this, token)
override val typeProviderImpl = KtFirTypeProvider(this, token)
override val typeInfoProviderImpl = KtFirTypeInfoProvider(this, token)
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.frontend.api.fir.components
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentsOfType
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.idea.fir.low.level.api.api.collectDesignation
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirSafe
import org.jetbrains.kotlin.idea.frontend.api.components.KtVisibilityChecker
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirFileSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
internal class KtFirVisibilityChecker(
override val analysisSession: KtFirAnalysisSession,
override val token: ValidityToken
) : KtVisibilityChecker(), KtFirAnalysisSessionComponent {
override fun isVisible(
candidateSymbol: KtSymbolWithVisibility,
useSiteFile: KtFileSymbol,
position: PsiElement,
receiverExpression: KtExpression?
): Boolean {
require(candidateSymbol is KtFirSymbol<*>)
require(useSiteFile is KtFirFileSymbol)
val nonLocalContainingDeclaration = findContainingNonLocalDeclaration(position)
return useSiteFile.firRef.withFir { useSiteFirFile ->
val containers = nonLocalContainingDeclaration
?.getOrBuildFirSafe<FirCallableDeclaration<*>>(analysisSession.firResolveState)
?.collectDesignation()
?.path
.orEmpty()
val explicitDispatchReceiver = receiverExpression
?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveState)
?.let { ExpressionReceiverValue(it) }
candidateSymbol.firRef.withFir { candidateFirSymbol ->
require(candidateFirSymbol is FirMemberDeclaration && candidateFirSymbol is FirSymbolOwner<*>) {
"$candidateFirSymbol must be a FirMemberDeclaration and FirSymbolOwner; it were ${candidateFirSymbol::class} instead"
}
rootModuleSession.visibilityChecker.isVisible(
candidateFirSymbol,
rootModuleSession,
useSiteFirFile,
containers,
explicitDispatchReceiver
)
}
}
}
private fun findContainingNonLocalDeclaration(element: PsiElement): KtCallableDeclaration? {
return element
.parentsOfType<KtCallableDeclaration>()
.firstOrNull { it.isNotFromLocalClass }
}
private val KtCallableDeclaration.isNotFromLocalClass
get() = this is KtNamedFunction && (isTopLevel || containingClassOrObject?.isLocal == false) ||
this is KtProperty && (isTopLevel || containingClassOrObject?.isLocal == false)
}