[Analysis API] Support dangling file copies in 'KtFirVisibilityChecker'

Dangling files are copies of files in the context module, or just
depend on it. In any way, dangling file modules see all internals of
the context module.
This commit is contained in:
Yan Zhulanow
2023-11-22 20:31:26 +09:00
committed by Space Team
parent b7c774b9e5
commit 297920fde9
2 changed files with 27 additions and 16 deletions
@@ -16,7 +16,9 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.collectContainingDeclarationsIfNonLocal import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.collectUseSiteContainers
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
@@ -48,22 +50,31 @@ internal class KtFirVisibilityChecker(
candidateSymbol.isVisibleByPsi(useSiteFile)?.let { return it } candidateSymbol.isVisibleByPsi(useSiteFile)?.let { return it }
} }
val useSiteFirFile = useSiteFile.firSymbol.fir
val containers = position.collectContainingDeclarationsIfNonLocal(analysisSession.firResolveSession).orEmpty()
val dispatchReceiverCanBeExplicit = candidateSymbol is KtCallableSymbol && !candidateSymbol.isExtension val dispatchReceiverCanBeExplicit = candidateSymbol is KtCallableSymbol && !candidateSymbol.isExtension
val explicitDispatchReceiver = runIf(dispatchReceiverCanBeExplicit) { val explicitDispatchReceiver = runIf(dispatchReceiverCanBeExplicit) {
receiverExpression?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession) receiverExpression?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession)
} }
val candidateFirSymbol = candidateSymbol.firSymbol.fir as FirMemberDeclaration val candidateDeclaration = candidateSymbol.firSymbol.fir as FirMemberDeclaration
val rootModuleSession = rootModuleSession val positionModule = firResolveSession.moduleProvider.getModule(position)
return rootModuleSession.visibilityChecker.isVisible( val candidateModule = candidateDeclaration.llFirModuleData.ktModule
candidateFirSymbol,
rootModuleSession, val effectiveSession = if (positionModule is KtDanglingFileModule && candidateModule != positionModule) {
useSiteFirFile, @Suppress("USELESS_CAST") // Smart cast is only available in K2
containers, val contextModule = (positionModule as KtDanglingFileModule).contextModule
firResolveSession.getSessionFor(contextModule)
} else {
firResolveSession.getSessionFor(positionModule)
}
val effectiveContainers = collectUseSiteContainers(position, firResolveSession).orEmpty()
return effectiveSession.visibilityChecker.isVisible(
candidateDeclaration,
effectiveSession,
useSiteFile.firSymbol.fir,
effectiveContainers,
explicitDispatchReceiver explicitDispatchReceiver
) )
} }
@@ -90,11 +90,11 @@ internal fun KtDeclaration.findSourceNonLocalFirDeclaration(firFile: FirFile, pr
} }
@KtAnalysisApiInternals @KtAnalysisApiInternals
fun PsiElement.collectContainingDeclarationsIfNonLocal(session: LLFirResolveSession): List<FirDeclaration>? { fun collectUseSiteContainers(element: PsiElement, resolveSession: LLFirResolveSession): List<FirDeclaration>? {
val ktFile = containingFile as? KtFile ?: return null val containingDeclaration = element.getNonLocalContainingOrThisDeclaration { !it.canBePartOfParentDeclaration } ?: return null
val ktDeclaration = getNonLocalContainingOrThisDeclaration { !it.canBePartOfParentDeclaration } ?: return null val containingFile = containingDeclaration.containingKtFile
val firFile = session.getOrBuildFirFile(ktFile) val firFile = resolveSession.getOrBuildFirFile(containingFile)
return FirElementFinder.findPathToDeclarationWithTarget(firFile, ktDeclaration) return FirElementFinder.findPathToDeclarationWithTarget(firFile, containingDeclaration)
} }
internal fun KtElement.findSourceByTraversingWholeTree( internal fun KtElement.findSourceByTraversingWholeTree(