[Analysis API] Remove components of obsolete on-air analysis
On-air analysis only worked correctly inside declaration bodies, and
required special handling ('analyzeInDependedAnalysisSession()').
Dangling files, the on-air replacement, works seamlessly, and it is
available in all contexts.
This commit is contained in:
-5
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProviderByJavaPsi
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
@OptIn(KtAnalysisApiInternals::class, KtAnalysisNonPublicApi::class)
|
||||
@Suppress("LeakingThis")
|
||||
@@ -79,8 +78,4 @@ class KtFe10AnalysisSession(
|
||||
@Suppress("AnalysisApiMissingLifetimeCheck")
|
||||
override val substitutorProviderImpl: KtSubstitutorProvider
|
||||
get() = throw NotSupportedForK1Exception()
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession =
|
||||
KtFe10AnalysisSession(originalKtFile.project, elementToReanalyze, token)
|
||||
}
|
||||
|
||||
-23
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.analysis.api.impl.base.components.KtAnalysisScopePro
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionTool
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.llResolveExtensionTool
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
@@ -35,8 +34,6 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@OptIn(KtAnalysisApiInternals::class, KtAnalysisNonPublicApi::class)
|
||||
@@ -135,26 +132,6 @@ private constructor(
|
||||
|
||||
override val substitutorProviderImpl: KtSubstitutorProvider = KtFirSubstitutorProvider(this)
|
||||
|
||||
@Suppress("AnalysisApiMissingLifetimeCheck", "OVERRIDE_DEPRECATION")
|
||||
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
|
||||
check(mode == AnalysisSessionMode.REGULAR) {
|
||||
"Cannot create context-dependent copy of KtAnalysis session from a context dependent one"
|
||||
}
|
||||
|
||||
val contextFirResolveSession = LowLevelFirApiFacadeForResolveOnAir.getFirResolveSessionForDependentCopy(
|
||||
originalFirResolveSession = firResolveSession,
|
||||
originalKtFile = originalKtFile,
|
||||
elementToAnalyze = elementToReanalyze
|
||||
)
|
||||
|
||||
return KtFirAnalysisSession(
|
||||
project,
|
||||
contextFirResolveSession,
|
||||
token,
|
||||
AnalysisSessionMode.DEPENDENT_COPY
|
||||
)
|
||||
}
|
||||
|
||||
internal val useSiteSession: FirSession get() = firResolveSession.useSiteFirSession
|
||||
internal val firSymbolProvider: FirSymbolProvider get() = useSiteSession.symbolProvider
|
||||
internal val targetPlatform: TargetPlatform get() = useSiteSession.moduleData.platform
|
||||
|
||||
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
/**
|
||||
* [KtAnalysisSession] is the entry point to all frontend-related work. It has the following contracts:
|
||||
@@ -100,15 +98,6 @@ public abstract class KtAnalysisSession(final override val token: KtLifetimeToke
|
||||
|
||||
override val analysisSession: KtAnalysisSession get() = this
|
||||
|
||||
/**
|
||||
* Creates a new [KtAnalysisSession] which depends on this analysis session, but additionally provides its own symbols derived from
|
||||
* analyzing [elementToReanalyze].
|
||||
*
|
||||
* @see analyzeInDependedAnalysisSession
|
||||
*/
|
||||
@Deprecated("On-air analysis is obsolete. Use 'analyzeCopy()' instead")
|
||||
public abstract fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession
|
||||
|
||||
internal val smartCastProvider: KtSmartCastProvider get() = smartCastProviderImpl
|
||||
protected abstract val smartCastProviderImpl: KtSmartCastProvider
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
|
||||
import org.jetbrains.kotlin.analysis.project.structure.withDanglingFileResolutionMode
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
/**
|
||||
* Executes the given [action] in a [KtAnalysisSession] context.
|
||||
@@ -46,32 +45,6 @@ public inline fun <R> analyze(
|
||||
return sessionProvider.analyze(useSiteKtModule, action)
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given [action] in the context of a [KtAnalysisSession] that depends on an original analysis session determined by
|
||||
* [originalFile]. In addition to the symbols provided by the original analysis session, the dependent analysis session provides its own
|
||||
* symbols derived from analyzing [elementToReanalyze]. This allows analyzing some new or copied (and modified) element in the larger
|
||||
* context of the original analysis session.
|
||||
*
|
||||
* @see KtAnalysisSession.createContextDependentCopy
|
||||
*/
|
||||
@Deprecated(
|
||||
"On-air analysis is obsolete. Use 'analyzeCopy()' instead",
|
||||
ReplaceWith(
|
||||
"analyzeCopy(elementToReanalyze, DanglingFileResolutionMode.IGNORE.SELF)",
|
||||
imports = [
|
||||
"org.jetbrains.kotlin.analysis.api.analyzeCopy",
|
||||
"org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode"
|
||||
]
|
||||
)
|
||||
)
|
||||
public inline fun <R> analyzeInDependedAnalysisSession(
|
||||
@Suppress("unused", "UNUSED_PARAMETER") originalFile: KtFile,
|
||||
elementToReanalyze: KtElement,
|
||||
crossinline action: KtAnalysisSession.() -> R
|
||||
): R {
|
||||
return analyzeCopy(elementToReanalyze, DanglingFileResolutionMode.IGNORE_SELF, action)
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given [action] in a [KtAnalysisSession] context.
|
||||
* Depending on the passed [resolutionMode], declarations inside a file copy will be treated in a specific way.
|
||||
|
||||
-18
@@ -39,24 +39,6 @@ public abstract class KtAnalysisSessionProvider(public val project: Project) : D
|
||||
|
||||
public abstract fun getAnalysisSessionByUseSiteKtModule(useSiteKtModule: KtModule): KtAnalysisSession
|
||||
|
||||
@Deprecated(
|
||||
"On-air analysis is obsolete. Use 'analyzeCopy()' instead",
|
||||
replaceWith = ReplaceWith(
|
||||
"analyzeCopy(elementToReanalyze, DanglingFileAnalysisMode.IGNORE_SELF, action)",
|
||||
imports = [
|
||||
"org.jetbrains.kotlin.analysis.api.analyzeCopy",
|
||||
"org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode"
|
||||
]
|
||||
)
|
||||
)
|
||||
public inline fun <R> analyseInDependedAnalysisSession(
|
||||
@Suppress("unused", "UNUSED_PARAMETER") originalFile: KtFile,
|
||||
elementToReanalyze: KtElement,
|
||||
crossinline action: KtAnalysisSession.() -> R,
|
||||
): R {
|
||||
return analyzeCopy(elementToReanalyze, DanglingFileResolutionMode.IGNORE_SELF, action)
|
||||
}
|
||||
|
||||
public inline fun <R> analyse(
|
||||
useSiteKtElement: KtElement,
|
||||
action: KtAnalysisSession.() -> R,
|
||||
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.analysis.low.level.api.fir
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLDiagnosticProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLScopeSessionProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.TowerProviderForElementForState
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirScopeSessionProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration
|
||||
import org.jetbrains.kotlin.analysis.utils.caches.*
|
||||
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
/**
|
||||
* An [LLFirResolveSession] which *depends* on an [originalFirResolveSession], but can provide its own FIR elements and symbols selectively.
|
||||
* The dependent session mostly provides FIR elements and symbols from the original resolve session, but additionally provides FIR elements
|
||||
* (and their associated symbols) from its own [ktToFirMapping].
|
||||
*
|
||||
* [LLFirResolveSessionDepended] is used by on-air resolve to provide FIR elements for a copied declaration in the larger context of the
|
||||
* original resolve session.
|
||||
*/
|
||||
internal class LLFirResolveSessionDepended(
|
||||
val originalFirResolveSession: LLFirResolvableResolveSession,
|
||||
val towerProviderBuiltUponElement: FirTowerContextProvider,
|
||||
private val ktToFirMapping: KtToFirMapping?,
|
||||
) : LLFirResolveSession(
|
||||
originalFirResolveSession.moduleProvider,
|
||||
originalFirResolveSession.resolutionStrategyProvider,
|
||||
originalFirResolveSession.sessionProvider,
|
||||
LLDependedScopeSessionProvider(originalFirResolveSession.project),
|
||||
LLDependedDiagnosticProvider
|
||||
) {
|
||||
override fun getOrBuildFirFor(element: KtElement): FirElement? {
|
||||
val psi = FirElementBuilder.getPsiAsFirElementSource(element) ?: return null
|
||||
ktToFirMapping?.getFir(psi)?.let { return it }
|
||||
return originalFirResolveSession.getOrBuildFirFor(element = element)
|
||||
}
|
||||
|
||||
override fun getOrBuildFirFile(ktFile: KtFile): FirFile =
|
||||
originalFirResolveSession.getOrBuildFirFile(ktFile)
|
||||
|
||||
override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) {
|
||||
originalFirResolveSession.resolveFirToPhase(declaration, toPhase)
|
||||
}
|
||||
|
||||
override fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> {
|
||||
val declarationToResolve = ktDeclaration.originalDeclaration ?: ktDeclaration
|
||||
ktToFirMapping?.getElement(declarationToResolve)?.let { it as? FirDeclaration }?.symbol?.let { return it }
|
||||
|
||||
return originalFirResolveSession.resolveToFirSymbol(declarationToResolve, phase)
|
||||
}
|
||||
|
||||
override fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider =
|
||||
TowerProviderForElementForState(this)
|
||||
}
|
||||
|
||||
private object LLDependedDiagnosticProvider : LLDiagnosticProvider {
|
||||
override fun collectDiagnostics(file: KtFile, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> {
|
||||
throw NotImplementedError("Diagnostics are not implemented for depended state")
|
||||
}
|
||||
|
||||
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> {
|
||||
throw NotImplementedError("Diagnostics are not implemented for depended state")
|
||||
}
|
||||
}
|
||||
|
||||
private class LLDependedScopeSessionProvider(private val project: Project) : LLScopeSessionProvider {
|
||||
private val scopeSessionProviderCache = SoftCachedMap.create<FirSession, LLFirScopeSessionProvider>(
|
||||
project,
|
||||
SoftCachedMap.Kind.SOFT_KEYS_SOFT_VALUES,
|
||||
listOf(
|
||||
PsiModificationTracker.MODIFICATION_COUNT,
|
||||
ProjectRootModificationTracker.getInstance(project)
|
||||
)
|
||||
)
|
||||
|
||||
override fun getScopeSession(session: LLFirSession): ScopeSession {
|
||||
return scopeSessionProviderCache
|
||||
.getOrPut(session) { LLFirScopeSessionProvider.create(project, invalidationTrackers = emptyList()) }
|
||||
.getScopeSession()
|
||||
}
|
||||
}
|
||||
-2
@@ -82,8 +82,6 @@ abstract class LLFirResolveSession(
|
||||
abstract fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*>
|
||||
|
||||
internal abstract fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase)
|
||||
|
||||
abstract fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider
|
||||
}
|
||||
|
||||
fun LLFirResolveSession.getModule(element: PsiElement): KtModule {
|
||||
|
||||
-485
@@ -1,485 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.analysis.low.level.api.fir.api
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionDepended
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerDataContextAllElementsCollector
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.isAutonomousDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirNonLocalDeclarationBuilder
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirReplacement
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.buildFileFirAnnotation
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.codeFragment
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isElementWhichShouldBeResolvedAsPartOfScript
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.builder.buildFileAnnotationsContainer
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.realPsi
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirResolveContextCollector
|
||||
import org.jetbrains.kotlin.fir.scopes.createImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
|
||||
|
||||
object LowLevelFirApiFacadeForResolveOnAir {
|
||||
private fun KtDeclaration.isApplicableForOnAirResolve(): Boolean = when (this) {
|
||||
is KtDestructuringDeclaration -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
private fun PsiElement.getNonLocalContainingOrThisDeclarationCodeFragmentAware(predicate: (KtDeclaration) -> Boolean): KtAnnotated? {
|
||||
return getNonLocalContainingOrThisDeclaration(predicate) ?: containingFile as? KtCodeFragment
|
||||
}
|
||||
|
||||
private fun PsiElement.onAirGetNonLocalContainingOrThisDeclaration(): KtElement? {
|
||||
return getNonLocalContainingOrThisDeclarationCodeFragmentAware { declaration ->
|
||||
declaration.isApplicableForOnAirResolve() && declaration.isAutonomousDeclaration
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordOriginalDeclaration(targetDeclaration: KtDeclaration, originalDeclaration: KtDeclaration) {
|
||||
require(originalDeclaration.containingKtFile !== targetDeclaration.containingKtFile)
|
||||
val originalDeclarationParents = originalDeclaration.parentsOfType<KtDeclaration>().toList()
|
||||
val fakeDeclarationParents = targetDeclaration.parentsOfType<KtDeclaration>().toList()
|
||||
originalDeclarationParents.zip(fakeDeclarationParents) { original, fake ->
|
||||
fake.originalDeclaration = original
|
||||
}
|
||||
|
||||
/**
|
||||
* We assume that [targetDeclaration] should have the same number of declarations
|
||||
*
|
||||
* @see restoreOriginalDeclarationsInScript
|
||||
*/
|
||||
if (targetDeclaration is KtScript && originalDeclaration is KtScript) {
|
||||
val originalStatements = originalDeclaration.declarationSequence()
|
||||
val newStatements = targetDeclaration.declarationSequence()
|
||||
originalStatements.zip(newStatements) { original, fake ->
|
||||
fake.originalDeclaration = original
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtScript.declarationSequence(): Sequence<KtDeclaration> {
|
||||
val sequence = blockExpression.statements.asSequence().filter { it !is KtScriptInitializer && it is KtDeclaration }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return sequence as Sequence<KtDeclaration>
|
||||
}
|
||||
|
||||
fun <T : KtElement> onAirResolveElement(
|
||||
firResolveSession: LLFirResolveSession,
|
||||
place: T,
|
||||
elementToResolve: T,
|
||||
): FirElement {
|
||||
require(firResolveSession is LLFirResolvableResolveSession)
|
||||
|
||||
val declaration = runBodyResolveOnAir(
|
||||
firResolveSession = firResolveSession,
|
||||
originalPlace = place,
|
||||
replacementElement = elementToResolve,
|
||||
collector = null,
|
||||
)
|
||||
|
||||
val expressionLocator = object : FirVisitorVoid() {
|
||||
var result: FirElement? = null
|
||||
private set
|
||||
|
||||
override fun visitElement(element: FirElement) {
|
||||
if (element.realPsi == elementToResolve) result = element
|
||||
if (result != null) return
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
}
|
||||
|
||||
declaration.accept(expressionLocator)
|
||||
return expressionLocator.result ?: errorWithFirSpecificEntries("Resolved on-air element was not found in containing declaration") {
|
||||
withPsiEntry("place", place)
|
||||
withPsiEntry("elementToResolve", elementToResolve)
|
||||
}
|
||||
}
|
||||
|
||||
fun getOnAirTowerDataContextProviderForTheWholeFile(
|
||||
firResolveSession: LLFirResolveSession,
|
||||
ktFile: KtFile,
|
||||
): FirTowerContextProvider {
|
||||
val ktModule = firResolveSession.getModule(ktFile)
|
||||
val session = firResolveSession.getSessionFor(ktModule) as LLFirResolvableModuleSession
|
||||
val moduleComponents = session.moduleComponents
|
||||
|
||||
val onAirFirFile = RawFirNonLocalDeclarationBuilder.buildNewFile(session, session.kotlinScopeProvider, ktFile)
|
||||
val collector = FirTowerDataContextAllElementsCollector()
|
||||
moduleComponents.firModuleLazyDeclarationResolver.runLazyDesignatedOnAirResolve(
|
||||
FirDesignationWithFile(emptyList(), onAirFirFile, onAirFirFile),
|
||||
collector,
|
||||
)
|
||||
|
||||
return collector
|
||||
}
|
||||
|
||||
fun getOnAirGetTowerContextProvider(
|
||||
firResolveSession: LLFirResolveSession,
|
||||
place: KtElement,
|
||||
): FirTowerContextProvider {
|
||||
require(firResolveSession is LLFirResolvableResolveSession)
|
||||
|
||||
return if (place is KtFile) {
|
||||
FileTowerProvider(place, onAirGetTowerContextForFile(firResolveSession, place))
|
||||
} else {
|
||||
val validPlace = PsiTreeUtil.findFirstParent(place, false) {
|
||||
it is KtElement && RawFirReplacement.isApplicableForReplacement(it)
|
||||
} as KtElement
|
||||
|
||||
FirTowerDataContextAllElementsCollector().also {
|
||||
runBodyResolveOnAir(
|
||||
firResolveSession = firResolveSession,
|
||||
collector = it,
|
||||
originalPlace = validPlace,
|
||||
replacementElement = validPlace,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAirGetTowerContextForFile(
|
||||
firResolveSession: LLFirResolvableResolveSession,
|
||||
file: KtFile,
|
||||
): FirTowerDataContext {
|
||||
val module = firResolveSession.getModule(file)
|
||||
val session = firResolveSession.getSessionFor(module) as LLFirResolvableModuleSession
|
||||
val moduleComponents = session.moduleComponents
|
||||
|
||||
val firFile = moduleComponents.firFileBuilder.buildRawFirFileWithCaching(file)
|
||||
|
||||
val scopeSession = firResolveSession.getScopeSessionFor(session)
|
||||
return firFile.createTowerDataContext(scopeSession)
|
||||
}
|
||||
|
||||
private fun FirFile.createTowerDataContext(scopeSession: ScopeSession): FirTowerDataContext {
|
||||
val importingScopes = createImportingScopes(this, moduleData.session, scopeSession)
|
||||
val fileScopeElements = importingScopes.map { it.asTowerDataElement(isLocal = false) }
|
||||
return FirTowerDataContext().addNonLocalTowerDataElements(fileScopeElements)
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a copy of the original fir declaration and resolves it to the minimum required phase
|
||||
* depends on [elementToAnalyze] position inside a non-local containing declaration.
|
||||
*
|
||||
* If [elementToAnalyze] is non-local declaration then resolves it to [FirResolvePhase.BODY_RESOLVE].
|
||||
*
|
||||
* Resulted [LLFirResolveSession] have [FirTowerDataContext] for elements from the copy.
|
||||
*/
|
||||
fun getFirResolveSessionForDependentCopy(
|
||||
originalFirResolveSession: LLFirResolveSession,
|
||||
originalKtFile: KtFile,
|
||||
elementToAnalyze: KtElement,
|
||||
): LLFirResolveSession {
|
||||
require(originalFirResolveSession is LLFirResolvableResolveSession)
|
||||
require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" }
|
||||
|
||||
elementToAnalyze.containingKtFile.originalKtFile = originalKtFile
|
||||
|
||||
val minimalCopiedDeclaration = elementToAnalyze.getNonLocalContainingOrThisDeclarationCodeFragmentAware {
|
||||
it.isApplicableForOnAirResolve()
|
||||
}
|
||||
|
||||
val copiedNonLocalDeclaration = minimalCopiedDeclaration?.onAirGetNonLocalContainingOrThisDeclaration()
|
||||
if (copiedNonLocalDeclaration == null) {
|
||||
val towerDataContext = onAirGetTowerContextForFile(originalFirResolveSession, originalKtFile)
|
||||
val fileTowerProvider = FileTowerProvider(elementToAnalyze.containingKtFile, towerDataContext)
|
||||
return LLFirResolveSessionDepended(originalFirResolveSession, fileTowerProvider, ktToFirMapping = null)
|
||||
}
|
||||
|
||||
val originalNonLocalDeclaration = PsiTreeUtil.findSameElementInCopy(copiedNonLocalDeclaration, originalKtFile)
|
||||
?: errorWithAttachment("Cannot find original function matching") {
|
||||
withPsiEntry("matchingPsi", elementToAnalyze)
|
||||
withPsiEntry("originalFile", originalKtFile)
|
||||
}
|
||||
|
||||
if (copiedNonLocalDeclaration is KtNamedDeclaration && originalNonLocalDeclaration is KtNamedDeclaration) {
|
||||
recordOriginalDeclaration(
|
||||
targetDeclaration = copiedNonLocalDeclaration,
|
||||
originalDeclaration = originalNonLocalDeclaration
|
||||
)
|
||||
}
|
||||
|
||||
val collector = FirTowerDataContextAllElementsCollector()
|
||||
val copiedFirDeclaration = runBodyResolveOnAir(
|
||||
originalFirResolveSession,
|
||||
originalPlace = originalNonLocalDeclaration,
|
||||
replacementElement = copiedNonLocalDeclaration,
|
||||
collector = collector,
|
||||
forcedResolvePhase = requiredResolvePhase(minimalCopiedDeclaration, elementToAnalyze),
|
||||
)
|
||||
|
||||
val mapping = KtToFirMapping(copiedFirDeclaration)
|
||||
return LLFirResolveSessionDepended(originalFirResolveSession, collector, mapping)
|
||||
}
|
||||
|
||||
private fun tryResolveAsFileAnnotation(
|
||||
annotationEntry: KtAnnotationEntry,
|
||||
replacement: RawFirReplacement,
|
||||
firFile: FirFile,
|
||||
collector: FirResolveContextCollector? = null,
|
||||
firResolveSession: LLFirResolvableResolveSession,
|
||||
): FirAnnotation {
|
||||
val annotationCall = buildFileFirAnnotation(
|
||||
firFile = firFile,
|
||||
fileAnnotation = annotationEntry,
|
||||
replacement = replacement,
|
||||
)
|
||||
|
||||
val fileAnnotationsContainer = buildFileAnnotationsContainer {
|
||||
moduleData = firFile.moduleData
|
||||
containingFileSymbol = firFile.symbol
|
||||
annotations += annotationCall
|
||||
}
|
||||
|
||||
val llFirResolvableSession = firFile.llFirResolvableSession
|
||||
?: errorWithAttachment("FirFile session expected to be a resolvable session but was ${firFile.llFirSession::class.java}") {
|
||||
withEntry("firSession", firFile.llFirSession) { it.toString() }
|
||||
}
|
||||
|
||||
val declarationResolver = llFirResolvableSession.moduleComponents.firModuleLazyDeclarationResolver
|
||||
declarationResolver.runLazyDesignatedOnAirResolve(
|
||||
FirDesignationWithFile(path = emptyList(), target = fileAnnotationsContainer, firFile),
|
||||
collector,
|
||||
)
|
||||
|
||||
collector?.addFileContext(firFile, firFile.createTowerDataContext(firResolveSession.getScopeSessionFor(llFirResolvableSession)))
|
||||
|
||||
// We should return annotation from fileAnnotationsContainer because the original annotation can be replaced
|
||||
return fileAnnotationsContainer.annotations.single()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new fir declaration from closer non-local declaration based on [originalPlace] position.
|
||||
* The resulted [FirResolvePhase] depends on [forcedResolvePhase] or the position of [originalPlace] inside the non-local declaration.
|
||||
*
|
||||
* Note: the new declaration and its content won't be rebinded to the original.
|
||||
*
|
||||
* @see requiredResolvePhase
|
||||
*/
|
||||
private fun runBodyResolveOnAir(
|
||||
firResolveSession: LLFirResolvableResolveSession,
|
||||
originalPlace: KtElement,
|
||||
replacementElement: KtElement,
|
||||
collector: FirResolveContextCollector?,
|
||||
forcedResolvePhase: FirResolvePhase? = null,
|
||||
): FirElement {
|
||||
val minimalOriginalDeclarationToReplace = originalPlace.getNonLocalContainingOrThisDeclarationCodeFragmentAware {
|
||||
it.isApplicableForOnAirResolve()
|
||||
}
|
||||
|
||||
val originalFirFile = firResolveSession.getOrBuildFirFile(originalPlace.containingKtFile)
|
||||
|
||||
val originalDeclaration = minimalOriginalDeclarationToReplace?.onAirGetNonLocalContainingOrThisDeclaration()
|
||||
if (originalDeclaration == null) {
|
||||
//It is possible that it is file annotation is going to resolve
|
||||
val annotationCall = originalPlace.parentOfType<KtAnnotationEntry>(withSelf = true)
|
||||
if (annotationCall != null) {
|
||||
return tryResolveAsFileAnnotation(
|
||||
annotationEntry = annotationCall,
|
||||
replacement = RawFirReplacement(from = originalPlace, to = replacementElement),
|
||||
firFile = originalFirFile,
|
||||
collector = collector,
|
||||
firResolveSession = firResolveSession,
|
||||
)
|
||||
} else {
|
||||
errorWithFirSpecificEntries(
|
||||
"Cannot find enclosing declaration for ${originalPlace::class.simpleName}",
|
||||
psi = originalPlace,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val originalDesignationPath = computeDesignation(originalDeclaration, originalFirFile)
|
||||
?: errorWithFirSpecificEntries(message = "Impossible to collect designation", fir = originalFirFile, psi = originalDeclaration)
|
||||
|
||||
val originalFirDeclaration = originalDesignationPath.target
|
||||
val session = originalFirDeclaration.llFirResolvableSession
|
||||
?: errorWithAttachment("Expected resolvable session, found ${originalFirDeclaration.llFirSession::class}") {
|
||||
withFirEntry("sessionOwner", originalFirDeclaration)
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case for [getOnAirGetTowerContextProvider]. Can be dropped after KT-59498
|
||||
*/
|
||||
val replacement = if (originalPlace === replacementElement) {
|
||||
RawFirReplacement(from = originalDeclaration, to = originalDeclaration)
|
||||
} else {
|
||||
RawFirReplacement(from = originalPlace, to = replacementElement)
|
||||
}
|
||||
|
||||
val newFirDeclaration = RawFirNonLocalDeclarationBuilder.buildWithReplacement(
|
||||
session = session,
|
||||
scopeProvider = session.kotlinScopeProvider,
|
||||
designation = FirDesignation(originalDesignationPath.path, originalFirDeclaration),
|
||||
rootNonLocalDeclaration = originalDeclaration,
|
||||
replacement = replacement,
|
||||
)
|
||||
|
||||
/**
|
||||
* We shouldn't touch script declarations because they're independent of a script
|
||||
*/
|
||||
if (newFirDeclaration is FirScript && originalFirDeclaration is FirScript) {
|
||||
restoreOriginalDeclarationsInScript(originalScript = originalFirDeclaration, newScript = newFirDeclaration)
|
||||
}
|
||||
|
||||
session.moduleComponents.firModuleLazyDeclarationResolver.runLazyDesignatedOnAirResolve(
|
||||
FirDesignationWithFile(originalDesignationPath.path, newFirDeclaration, originalFirFile),
|
||||
collector,
|
||||
forcedResolvePhase ?: requiredResolvePhase(minimalOriginalDeclarationToReplace, originalPlace),
|
||||
)
|
||||
|
||||
return newFirDeclaration
|
||||
}
|
||||
|
||||
/**
|
||||
* We assume that [newScript] has the same declarations as [originalScript]
|
||||
*/
|
||||
private fun restoreOriginalDeclarationsInScript(originalScript: FirScript, newScript: FirScript) {
|
||||
val updatedDeclarations = ArrayList<FirDeclaration>(newScript.declarations.size)
|
||||
val originalDeclarations = originalScript.declarations.iterator()
|
||||
for (recreatedDeclaration in newScript.declarations) {
|
||||
updatedDeclarations += if (recreatedDeclaration.isElementWhichShouldBeResolvedAsPartOfScript) {
|
||||
recreatedDeclaration
|
||||
} else {
|
||||
originalDeclarations.nextDeclaration() ?: scriptDeclarationInconsistencyError(originalScript, newScript)
|
||||
}
|
||||
}
|
||||
|
||||
val nextDeclaration = originalDeclarations.nextDeclaration()
|
||||
if (nextDeclaration != null) {
|
||||
scriptDeclarationInconsistencyError(originalScript, newScript)
|
||||
}
|
||||
|
||||
newScript.replaceDeclarations(updatedDeclarations)
|
||||
}
|
||||
|
||||
private fun scriptDeclarationInconsistencyError(originalScript: FirScript, newScript: FirScript): Nothing {
|
||||
val originalDeclarations = originalScript.declarations.filterNot(FirDeclaration::isElementWhichShouldBeResolvedAsPartOfScript)
|
||||
val newDeclarations = newScript.declarations.filterNot(FirDeclaration::isElementWhichShouldBeResolvedAsPartOfScript)
|
||||
errorWithAttachment("New script has ${if (newDeclarations.size > originalDeclarations.size) "more" else "less"} declarations") {
|
||||
withFirEntry("originalScript", originalScript)
|
||||
withFirEntry("newScript", newScript)
|
||||
withEntryGroup("originalDeclarations") {
|
||||
for ((index, declaration) in originalDeclarations.withIndex()) {
|
||||
withFirEntry(index.toString(), declaration)
|
||||
}
|
||||
}
|
||||
|
||||
withEntryGroup("newDeclarations") {
|
||||
for ((index, declaration) in newDeclarations.withIndex()) {
|
||||
withFirEntry(index.toString(), declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Iterator<FirDeclaration>.nextDeclaration(): FirDeclaration? {
|
||||
while (hasNext()) {
|
||||
val declaration = next()
|
||||
if (declaration.isElementWhichShouldBeResolvedAsPartOfScript) continue
|
||||
|
||||
return declaration
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun computeDesignation(originalDeclaration: KtElement, originalFirFile: FirFile): FirElementFinder.FirDeclarationDesignation? {
|
||||
if (originalDeclaration is KtCodeFragment) {
|
||||
val firCodeFragment = originalFirFile.codeFragment
|
||||
return FirElementFinder.FirDeclarationDesignation(emptyList(), firCodeFragment)
|
||||
}
|
||||
|
||||
require(originalDeclaration is KtDeclaration)
|
||||
return FirElementFinder.collectDesignationPath(originalFirFile, originalDeclaration)
|
||||
}
|
||||
|
||||
private fun requiredResolvePhase(
|
||||
container: KtAnnotated,
|
||||
elementToReplace: PsiElement,
|
||||
): FirResolvePhase {
|
||||
assert(container is KtDeclaration || container is KtCodeFragment)
|
||||
|
||||
return when {
|
||||
container !is KtDeclaration -> FirResolvePhase.BODY_RESOLVE
|
||||
bodyResolveRequired(container, elementToReplace) -> FirResolvePhase.BODY_RESOLVE
|
||||
annotationMappingRequired(container, elementToReplace) -> FirResolvePhase.ANNOTATION_ARGUMENTS
|
||||
else -> {
|
||||
/** Currently it is a minimal phase there we can collect [FirResolveContextCollector] */
|
||||
FirResolvePhase.CONTRACTS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun annotationMappingRequired(
|
||||
container: KtDeclaration,
|
||||
elementToReplace: PsiElement,
|
||||
): Boolean = elementToReplace.parentsWithSelf.takeWhile { it != container }.any {
|
||||
it is KtAnnotationEntry
|
||||
} || elementToReplace.anyDescendantOfType<KtAnnotationEntry>(
|
||||
canGoInside = {
|
||||
// We shouldn't go inside a class body, because class resolution won't process such elements
|
||||
// In case of container is class, we are interested only in elements outside its body
|
||||
it !is KtClassBody
|
||||
},
|
||||
)
|
||||
|
||||
private fun bodyResolveRequired(container: KtDeclaration, elementToReplace: PsiElement): Boolean = when {
|
||||
container == elementToReplace -> true
|
||||
|
||||
container is KtDeclarationWithBody -> {
|
||||
val bodyExpression = container.bodyExpression
|
||||
val secondaryConstructorSuperCallArgs = (container as? KtSecondaryConstructor)?.getDelegationCallOrNull()?.valueArgumentList
|
||||
|
||||
bodyExpression.isAncestor(elementToReplace) || secondaryConstructorSuperCallArgs.isAncestor(elementToReplace)
|
||||
}
|
||||
|
||||
container is KtProperty -> container.delegateExpressionOrInitializer.isAncestor(elementToReplace)
|
||||
container is KtParameter -> container.defaultValue.isAncestor(elementToReplace)
|
||||
|
||||
container is KtEnumEntry -> {
|
||||
container.initializerList.isAncestor(elementToReplace) || container.body.isAncestor(elementToReplace)
|
||||
}
|
||||
|
||||
container is KtClassOrObject -> {
|
||||
container.superTypeListEntries.any { superTypeEntry ->
|
||||
when (superTypeEntry) {
|
||||
is KtSuperTypeCallEntry -> superTypeEntry.valueArgumentList.isAncestor(elementToReplace)
|
||||
is KtDelegatedSuperTypeEntry -> superTypeEntry.delegateExpression.isAncestor(elementToReplace)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container is KtScript || container is KtAnonymousInitializer -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
-36
@@ -6,14 +6,10 @@
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve
|
||||
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirSingleResolveTarget
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirWholeElementResolveTarget
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyResolverRunner
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.withOnAirDesignation
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolveState
|
||||
@@ -130,38 +126,6 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve on-air created declaration in a context of real [FirDesignationWithFile.firFile] and [FirDesignationWithFile.path].
|
||||
* If target declaration is [FirFile] then the entire file will be resolved.
|
||||
* The same for [FirRegularClass] if [resolvePhase] is [FirResolvePhase.BODY_RESOLVE].
|
||||
*/
|
||||
fun runLazyDesignatedOnAirResolve(
|
||||
designation: FirDesignationWithFile,
|
||||
towerDataContextCollector: FirResolveContextCollector?,
|
||||
resolvePhase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE,
|
||||
) {
|
||||
resolveFileToImportsWithLock(designation.firFile)
|
||||
|
||||
val target = when {
|
||||
designation.target is FirFile -> LLFirWholeElementResolveTarget(designation.firFile)
|
||||
resolvePhase == FirResolvePhase.BODY_RESOLVE && designation.target is FirRegularClass -> {
|
||||
LLFirWholeElementResolveTarget(designation.firFile, designation.path, designation.target)
|
||||
}
|
||||
|
||||
else -> LLFirSingleResolveTarget(designation.firFile, designation.path, designation.target)
|
||||
}
|
||||
|
||||
try {
|
||||
withOnAirDesignation(designation) {
|
||||
// New session to avoid garbage in the original session
|
||||
val scopeSession = ScopeSession()
|
||||
lazyResolveTargets(listOf(target), scopeSession, resolvePhase, towerDataContextCollector)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
handleExceptionFromResolve(e, target, resolvePhase)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveContainingFileToImports(target: FirElementWithResolveState) {
|
||||
if (target.resolvePhase >= FirResolvePhase.IMPORTS) return
|
||||
val firFile = target.getContainingFile() ?: return
|
||||
|
||||
+1
-3
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
|
||||
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
|
||||
@@ -20,8 +19,7 @@ internal class LLFirLibrarySessionProvider(
|
||||
override val symbolProvider: FirSymbolProvider
|
||||
) : FirProvider() {
|
||||
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? {
|
||||
return SyntheticFirClassProvider.getInstance(symbolProvider.session).getFirClassifierByFqName(classId)
|
||||
?: symbolProvider.getClassLikeSymbolByClassId(classId)?.fir
|
||||
return symbolProvider.getClassLikeSymbolByClassId(classId)?.fir
|
||||
}
|
||||
|
||||
override fun getFirClassifierContainerFile(fqName: ClassId): FirFile = shouldNotBeCalled()
|
||||
|
||||
+6
-9
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
||||
import org.jetbrains.kotlin.fir.NoMutableState
|
||||
@@ -62,8 +61,9 @@ internal class LLFirProvider(
|
||||
private fun getFirClassifierByFqNameAndDeclaration(
|
||||
classId: ClassId,
|
||||
classLikeDeclaration: KtClassLikeDeclaration?,
|
||||
): FirClassLikeDeclaration? = SyntheticFirClassProvider.getInstance(session).getFirClassifierByFqName(classId)
|
||||
?: providerHelper.getFirClassifierByFqNameAndDeclaration(classId, classLikeDeclaration)
|
||||
): FirClassLikeDeclaration? {
|
||||
return providerHelper.getFirClassifierByFqNameAndDeclaration(classId, classLikeDeclaration)
|
||||
}
|
||||
|
||||
override fun getFirClassifierContainerFile(fqName: ClassId): FirFile {
|
||||
return getFirClassifierContainerFileIfAny(fqName)
|
||||
@@ -73,8 +73,7 @@ internal class LLFirProvider(
|
||||
}
|
||||
|
||||
override fun getFirClassifierContainerFileIfAny(fqName: ClassId): FirFile? {
|
||||
return SyntheticFirClassProvider.getInstance(session).getFirClassifierContainerFileIfAny(fqName)
|
||||
?: getFirClassifierByFqName(fqName)?.let { moduleComponents.cache.getContainerFirFile(it) }
|
||||
return getFirClassifierByFqName(fqName)?.let { moduleComponents.cache.getContainerFirFile(it) }
|
||||
}
|
||||
|
||||
override fun getFirClassifierContainerFile(symbol: FirClassLikeSymbol<*>): FirFile {
|
||||
@@ -85,13 +84,11 @@ internal class LLFirProvider(
|
||||
}
|
||||
|
||||
override fun getFirClassifierContainerFileIfAny(symbol: FirClassLikeSymbol<*>): FirFile? {
|
||||
return SyntheticFirClassProvider.getInstance(session).getFirClassifierContainerFileIfAny(symbol.classId)
|
||||
?: moduleComponents.cache.getContainerFirFile(symbol.fir)
|
||||
return moduleComponents.cache.getContainerFirFile(symbol.fir)
|
||||
}
|
||||
|
||||
override fun getFirCallableContainerFile(symbol: FirCallableSymbol<*>): FirFile? {
|
||||
return symbol.callableId.classId?.let { SyntheticFirClassProvider.getInstance(session).getFirClassifierContainerFileIfAny(it) }
|
||||
?: moduleComponents.cache.getContainerFirFile(symbol.fir)
|
||||
return moduleComponents.cache.getContainerFirFile(symbol.fir)
|
||||
}
|
||||
|
||||
override fun getFirScriptContainerFile(symbol: FirScriptSymbol): FirFile? {
|
||||
|
||||
-5
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.state
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getModule
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.*
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher
|
||||
@@ -131,8 +130,4 @@ internal class LLFirResolvableResolveSession(
|
||||
override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) {
|
||||
declaration.lazyResolveToPhase(toPhase)
|
||||
}
|
||||
|
||||
override fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider {
|
||||
return TowerProviderForElementForState(this)
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.analysis.low.level.api.fir.state
|
||||
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionDepended
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
|
||||
internal class TowerProviderForElementForState(private val firResolveSession: LLFirResolveSession) : FirTowerContextProvider {
|
||||
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
|
||||
if (firResolveSession is LLFirResolveSessionDepended) {
|
||||
firResolveSession.towerProviderBuiltUponElement
|
||||
.getClosestAvailableParentContext(ktElement)
|
||||
?.let { return it }
|
||||
|
||||
return LowLevelFirApiFacadeForResolveOnAir
|
||||
.getOnAirGetTowerContextProvider(firResolveSession.originalFirResolveSession, ktElement)
|
||||
.getClosestAvailableParentContext(ktElement)
|
||||
}
|
||||
return LowLevelFirApiFacadeForResolveOnAir
|
||||
.getOnAirGetTowerContextProvider(firResolveSession, ktElement)
|
||||
.getClosestAvailableParentContext(ktElement)
|
||||
}
|
||||
}
|
||||
-36
@@ -5,12 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolveState
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
|
||||
@DslMarker
|
||||
internal annotation class StateKeeperDsl
|
||||
@@ -264,15 +259,6 @@ internal inline fun <Target : FirElementWithResolveState, Context : Any, Result>
|
||||
prepareTarget: (Target) -> Unit = {},
|
||||
action: () -> Result,
|
||||
): Result {
|
||||
val onAirAnalysisTarget = target.moduleData.session.onAirAnalysisTarget
|
||||
if (onAirAnalysisTarget != null && target in onAirAnalysisTarget) {
|
||||
// Several arrangers reset declaration bodies to lazy ones, and then re-construct the FIR tree from the backing PSI.
|
||||
// This won't work for on-air analysis, as the tree is manually modified. However, it doesn't seem that tree guards are needed
|
||||
// in the first place, as results of the on-air analysis aren't going to be shared.
|
||||
prepareTarget(target)
|
||||
return action()
|
||||
}
|
||||
|
||||
var preservedState: PreservedState? = null
|
||||
|
||||
try {
|
||||
@@ -284,26 +270,4 @@ internal inline fun <Target : FirElementWithResolveState, Context : Any, Result>
|
||||
preservedState?.restore()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
private operator fun FirElementWithResolveState.contains(child: FirElementWithResolveState): Boolean {
|
||||
if (this == child) {
|
||||
return true
|
||||
}
|
||||
|
||||
var isFound = false
|
||||
|
||||
accept(object : FirVisitorVoid() {
|
||||
override fun visitElement(element: FirElement) {
|
||||
if (!isFound) {
|
||||
if (element == child) {
|
||||
isFound = true
|
||||
} else if (element is FirDeclaration || element !is FirStatement) {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return isFound
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.analysis.low.level.api.fir.transformers
|
||||
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolveState
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
internal interface SyntheticFirClassProvider {
|
||||
fun getFirClassifierContainerFileIfAny(classId: ClassId): FirFile?
|
||||
fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration?
|
||||
|
||||
companion object {
|
||||
fun getInstance(session: FirSession): SyntheticFirClassProvider {
|
||||
return onAirProviderForThread.get()?.takeIf { it.session == session } ?: EmptySyntheticFirClassProvider
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal val FirSession.onAirAnalysisTarget: FirElementWithResolveState?
|
||||
get() = onAirProviderForThread.get()?.target
|
||||
|
||||
/**
|
||||
* Injects a designation-based class file provider to 'LLFirProvider'.
|
||||
* Used for on-air analysis.
|
||||
*/
|
||||
internal fun withOnAirDesignation(designation: FirDesignationWithFile, block: () -> Unit) {
|
||||
check(onAirProviderForThread.get() == null) { "Nested on-air analysis is not allowed" }
|
||||
|
||||
try {
|
||||
// Make additional classes available only inside a given `block`.
|
||||
// The provider is stored inside a `ThreadLocal` value to avoid parallel analysis modification.
|
||||
val provider = OnAirSyntheticFirClassProvider.create(designation)
|
||||
onAirProviderForThread.set(provider)
|
||||
block()
|
||||
} finally {
|
||||
onAirProviderForThread.remove()
|
||||
}
|
||||
}
|
||||
|
||||
private class OnAirSyntheticFirClassProvider private constructor(
|
||||
private val firFile: FirFile,
|
||||
val target: FirElementWithResolveState,
|
||||
private val classes: Map<ClassId, FirClassLikeDeclaration>
|
||||
) : SyntheticFirClassProvider {
|
||||
val session: FirSession
|
||||
get() = firFile.moduleData.session
|
||||
|
||||
override fun getFirClassifierContainerFileIfAny(classId: ClassId): FirFile? {
|
||||
return if (classId in classes) firFile else null
|
||||
}
|
||||
|
||||
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? {
|
||||
return classes[classId]
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(designation: FirDesignationWithFile): OnAirSyntheticFirClassProvider {
|
||||
val firFile = designation.firFile
|
||||
val firElement = designation.target
|
||||
|
||||
val nodeInfoCollector = object : FirVisitorVoid() {
|
||||
val classes = mutableMapOf<ClassId, FirClassLikeDeclaration>()
|
||||
override fun visitElement(element: FirElement) {
|
||||
if (element is FirClassLikeDeclaration) {
|
||||
classes[element.symbol.classId] = element
|
||||
}
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
}
|
||||
|
||||
nodeInfoCollector.visitElement(firElement)
|
||||
return OnAirSyntheticFirClassProvider(firFile, designation.target, nodeInfoCollector.classes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object EmptySyntheticFirClassProvider : SyntheticFirClassProvider {
|
||||
override fun getFirClassifierContainerFileIfAny(classId: ClassId) = null
|
||||
override fun getFirClassifierByFqName(classId: ClassId) = null
|
||||
}
|
||||
|
||||
private val onAirProviderForThread: ThreadLocal<OnAirSyntheticFirClassProvider?> = ThreadLocal()
|
||||
Reference in New Issue
Block a user