[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.markers.KtSymbolWithVisibility
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.java.JavaVisibilities
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
@@ -48,22 +50,31 @@ internal class KtFirVisibilityChecker(
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 explicitDispatchReceiver = runIf(dispatchReceiverCanBeExplicit) {
receiverExpression?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession)
}
val candidateFirSymbol = candidateSymbol.firSymbol.fir as FirMemberDeclaration
val candidateDeclaration = candidateSymbol.firSymbol.fir as FirMemberDeclaration
val rootModuleSession = rootModuleSession
return rootModuleSession.visibilityChecker.isVisible(
candidateFirSymbol,
rootModuleSession,
useSiteFirFile,
containers,
val positionModule = firResolveSession.moduleProvider.getModule(position)
val candidateModule = candidateDeclaration.llFirModuleData.ktModule
val effectiveSession = if (positionModule is KtDanglingFileModule && candidateModule != positionModule) {
@Suppress("USELESS_CAST") // Smart cast is only available in K2
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
)
}
@@ -90,11 +90,11 @@ internal fun KtDeclaration.findSourceNonLocalFirDeclaration(firFile: FirFile, pr
}
@KtAnalysisApiInternals
fun PsiElement.collectContainingDeclarationsIfNonLocal(session: LLFirResolveSession): List<FirDeclaration>? {
val ktFile = containingFile as? KtFile ?: return null
val ktDeclaration = getNonLocalContainingOrThisDeclaration { !it.canBePartOfParentDeclaration } ?: return null
val firFile = session.getOrBuildFirFile(ktFile)
return FirElementFinder.findPathToDeclarationWithTarget(firFile, ktDeclaration)
fun collectUseSiteContainers(element: PsiElement, resolveSession: LLFirResolveSession): List<FirDeclaration>? {
val containingDeclaration = element.getNonLocalContainingOrThisDeclaration { !it.canBePartOfParentDeclaration } ?: return null
val containingFile = containingDeclaration.containingKtFile
val firFile = resolveSession.getOrBuildFirFile(containingFile)
return FirElementFinder.findPathToDeclarationWithTarget(firFile, containingDeclaration)
}
internal fun KtElement.findSourceByTraversingWholeTree(