From 633e03b710e0b69ed28cb1cfd958705159ea11a3 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Fri, 7 May 2021 17:08:29 +0200 Subject: [PATCH] [FIR IDE] LowLevel api refactoring --- .../transformers/FirSupertypesResolution.kt | 6 +- .../body/resolve/FirBodyResolveTransformer.kt | 4 +- .../body/resolve/LocalClassesResolution.kt | 4 +- .../api/FirModuleResolveStateDepended.kt | 10 +- .../level/api/FirModuleResolveStateImpl.kt | 17 +- .../level/api/api/DeclarationCopyBuilder.kt | 17 +- .../level/api/api/FirModuleResolveState.kt | 25 +- .../low/level/api/api/LowLevelFirApiFacade.kt | 16 +- .../LowLevelFirApiFacadeForResolveOnAir.kt | 56 ++-- .../lazy/resolve/FirLazyBodiesCalculator.kt | 4 +- .../resolve/FirLazyDeclarationResolver.kt | 255 ++++++++++++++---- ...rDesignatedBodyResolveTransformerForIDE.kt | 4 +- ...esignatedStatusResolveTransformerForIDE.kt | 41 +-- ...natedSupertypeResolverTransformerForIDE.kt | 9 +- ...DesignatedTypeResolverTransformerForIDE.kt | 2 +- .../transformers/FirLazyTransformerForIDE.kt | 14 +- .../FirProviderInterceptorForIDE.kt | 6 +- .../AbstractFirLazyDeclarationResolveTest.kt | 4 +- .../based/AbstractCompilerBasedTest.kt | 4 +- .../AbstractFirContextCollectionTest.kt | 4 +- .../KtFirCompletionCandidateChecker.kt | 4 +- .../api/fir/symbols/KtFirSymbolProvider.kt | 4 +- 22 files changed, 303 insertions(+), 207 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index e11c75d589e..1a9c287a31d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -43,7 +43,7 @@ class FirSupertypeResolverProcessor(session: FirSession, scopeSession: ScopeSess /** * Interceptor needed by IDE to resolve in-air created declarations. */ -interface FirProviderInterceptorForSupertypeResolver { +interface FirProviderInterceptor { fun getFirClassifierContainerFileIfAny(symbol: FirClassLikeSymbol<*>): FirFile? fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? } @@ -74,7 +74,7 @@ fun > F.runSupertypeResolvePhaseForLocalClass( scopeSession: ScopeSession, currentScopeList: List, localClassesNavigationInfo: LocalClassesNavigationInfo, - firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?, + firProviderInterceptor: FirProviderInterceptor?, ): F { val supertypeComputationSession = SupertypeComputationSession() val supertypeResolverVisitor = FirSupertypeResolverVisitor( @@ -189,7 +189,7 @@ class FirSupertypeResolverVisitor( private val scopeSession: ScopeSession, private val scopeForLocalClass: PersistentList? = null, private val localClassesNavigationInfo: LocalClassesNavigationInfo? = null, - private val firProviderInterceptor: FirProviderInterceptorForSupertypeResolver? = null, + private val firProviderInterceptor: FirProviderInterceptor? = null, ) : FirDefaultVisitor() { private val supertypeGenerationExtensions = session.extensionService.supertypeGenerators diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index 51fc6c81b90..a87db7c9004 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext import org.jetbrains.kotlin.fir.resolve.dfa.DataFlowAnalyzerContext -import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver +import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve import org.jetbrains.kotlin.fir.scopes.FirCompositeScope @@ -33,7 +33,7 @@ open class FirBodyResolveTransformer( val returnTypeCalculator: ReturnTypeCalculator = ReturnTypeCalculatorForFullBodyResolve(), outerBodyResolveContext: BodyResolveContext? = null, val firTowerDataContextCollector: FirTowerDataContextCollector? = null, - val firProviderInterceptor: FirProviderInterceptorForSupertypeResolver? = null, + val firProviderInterceptor: FirProviderInterceptor? = null, ) : FirAbstractBodyResolveTransformer(phase) { final override val context: BodyResolveContext = diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt index 218e013fd20..bb0da604937 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/LocalClassesResolution.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.ResolutionMode -import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver +import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.resolve.transformers.runStatusResolveForLocalClass import org.jetbrains.kotlin.fir.resolve.transformers.runSupertypeResolvePhaseForLocalClass import org.jetbrains.kotlin.fir.resolve.transformers.runTypeResolvePhaseForLocalClass @@ -20,7 +20,7 @@ fun > F.runAllPhasesForLocalClass( components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents, resolutionMode: ResolutionMode, firTowerDataContextCollector: FirTowerDataContextCollector?, - firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?, + firProviderInterceptor: FirProviderInterceptor?, ): F { if (this.resolvePhase > FirResolvePhase.RAW_FIR) return this if (this is FirRegularClass) { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt index 3e82fd0f069..ee2b4a98665 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt @@ -58,13 +58,13 @@ internal class FirModuleResolveStateDepended( ) } - override fun getFirFile(ktFile: KtFile): FirFile = - originalState.getFirFile(ktFile) + override fun getOrBuildFirFile(ktFile: KtFile): FirFile = + originalState.getOrBuildFirFile(ktFile) - override fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D = - originalState.resolvedFirToPhase(declaration, toPhase) + override fun resolveFirToPhase(declaration: D, toPhase: FirResolvePhase): D = + originalState.resolveFirToPhase(declaration, toPhase) - override fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? { + override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? { val ktFile = declaration.containingKtFileIfAny ?: return null cache.getCachedFirFile(ktFile)?.let { return it } ktFile.originalKtFile?.let(cache::getCachedFirFile)?.let { return it } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt index d89d6171cfd..2acdbd5955c 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.idea.fir.low.level.api import com.intellij.openapi.project.Project -import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic @@ -60,20 +59,18 @@ internal class FirModuleResolveStateImpl( override fun getOrBuildFirFor(element: KtElement): FirElement = elementBuilder.getOrBuildFirFor(element, firFileBuilder, rootModuleSession.cache, fileStructureCache) - override fun getFirFile(ktFile: KtFile): FirFile = + override fun getOrBuildFirFile(ktFile: KtFile): FirFile = firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache, lazyBodiesMode = false) + override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = + cache.getContainerFirFile(declaration) + override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> = diagnosticsCollector.getDiagnosticsFor(element, filter) override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> = diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter) - internal fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? { - val cache = sessionProvider.getModuleCache(ktFile.getModuleInfo() as ModuleSourceInfo) - return firFileBuilder.getBuiltFirFileOrNull(ktFile, cache) - } - @OptIn(InternalForInline::class) override fun findSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration = findSourceFirDeclarationByExpression(ktDeclaration) @@ -117,7 +114,7 @@ internal class FirModuleResolveStateImpl( ?: error("FirDeclaration was not found for\n${ktDeclaration.getElementTextInContext()}") } - override fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D { + override fun resolveFirToPhase(declaration: D, toPhase: FirResolvePhase): D { val fileCache = when (val session = declaration.moduleData.session) { is FirIdeSourcesSession -> session.cache else -> return declaration @@ -127,11 +124,7 @@ internal class FirModuleResolveStateImpl( fileCache, toPhase, checkPCE = true, - towerDataContextCollector = null, ) return declaration } - - override fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = - cache.getContainerFirFile(declaration) } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt index b0a210700e8..02854e2cd4c 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt @@ -58,11 +58,11 @@ object DeclarationCopyBuilder { val originalFunction = rootNonLocalDeclaration.getOrBuildFirOfType(state) val builtFunction = createCopy(rootNonLocalDeclaration, originalFunction, replacement) - //TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers? val functionBlock = rootNonLocalDeclaration.bodyBlockExpression if (functionBlock == null || !PsiTreeUtil.isAncestor(functionBlock, replacement.from, true)) { return builtFunction } + //TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers? // right now we can't resolve builtFunction header properly, as it built right in air, // without file, which is now required for running stages other then body resolve, so we @@ -82,11 +82,11 @@ object DeclarationCopyBuilder { val originalFirClass = rootNonLocalDeclaration.getOrBuildFirOfType(state) val builtClass = createCopy(rootNonLocalDeclaration, originalFirClass, replacement) - //TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers? val classBody = rootNonLocalDeclaration.body if (classBody == null || !PsiTreeUtil.isAncestor(classBody, replacement.from, true)) { return builtClass } + //TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers? return buildRegularClassCopy(originalFirClass) { declarations.clear() @@ -102,16 +102,8 @@ object DeclarationCopyBuilder { state: FirModuleResolveState, replacement: RawFirReplacement, ): FirTypeAlias { - val originalFirTypeAlias = rootNonLocalDeclaration.getOrBuildFirOfType(state) - val builtTypeAlias = createCopy(rootNonLocalDeclaration, originalFirTypeAlias, replacement) - return builtTypeAlias - -// return buildTypeAliasCopy(originalFirTypeAlias) { -// expandedTypeRef = builtTypeAlias.expandedTypeRef -// symbol = builtTypeAlias.symbol -// initDeclaration(originalFirTypeAlias, builtTypeAlias, state) -// } + return createCopy(rootNonLocalDeclaration, originalFirTypeAlias, replacement) } private fun createPropertyCopy( @@ -122,7 +114,6 @@ object DeclarationCopyBuilder { val originalProperty = rootNonLocalDeclaration.getOrBuildFirOfType(state) val builtProperty = createCopy(rootNonLocalDeclaration, originalProperty, replacement) - //TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers? val insideGetterBody = rootNonLocalDeclaration.getter?.bodyBlockExpression?.let { PsiTreeUtil.isAncestor(it, replacement.from, true) } ?: false @@ -133,6 +124,8 @@ object DeclarationCopyBuilder { if (!insideSetterBody) return builtProperty } + //TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers? + val originalSetter = originalProperty.setter val builtSetter = builtProperty.setter diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt index f9bfcd415f7..d9bab1f35dd 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt @@ -29,9 +29,22 @@ abstract class FirModuleResolveState { internal abstract fun getSessionFor(moduleInfo: IdeaModuleInfo): FirSession + /** + * Build fully resolved FIR node for requested element. + * This operation could be performance affective, use + * @see tryGetCachedFirFile to get [FirFile] in undefined phase + */ internal abstract fun getOrBuildFirFor(element: KtElement): FirElement - internal abstract fun getFirFile(ktFile: KtFile): FirFile + /** + * Get or build or get cached [FirFile] for requested file in undefined phase + */ + internal abstract fun getOrBuildFirFile(ktFile: KtFile): FirFile + + /** + * Try get [FirFile] from the cache in undefined phase + */ + internal abstract fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? internal abstract fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> @@ -41,11 +54,9 @@ abstract class FirModuleResolveState { val originalDeclaration = (declaration as? FirCallableDeclaration<*>)?.unwrapFakeOverrides() ?: declaration val session = originalDeclaration.moduleData.session return when { - originalDeclaration.origin == FirDeclarationOrigin.Source - && session is FirIdeSourcesSession - -> { + originalDeclaration.origin == FirDeclarationOrigin.Source && session is FirIdeSourcesSession -> { val cache = session.cache - val file = getFirFile(declaration, cache) + val file = tryGetCachedFirFile(declaration, cache) ?: error("Fir file was not found for\n${declaration.render()}\n${(declaration.psi as? KtElement)?.getElementTextInContext()}") cache.firFileLockProvider.withLock(file, declarationLockType) { action(declaration) } } @@ -63,7 +74,5 @@ abstract class FirModuleResolveState { ktDeclaration: KtLambdaExpression, ): FirDeclaration - internal abstract fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D - - internal abstract fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? + internal abstract fun resolveFirToPhase(declaration: D, toPhase: FirResolvePhase): D } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt index 0ab94cb0e8a..a2ce7f3c822 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacade.kt @@ -8,15 +8,10 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.psi -import org.jetbrains.kotlin.fir.render -import org.jetbrains.kotlin.fir.unwrapFakeOverrides import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.FirIdeResolveStateService import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline -import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession -import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -118,12 +113,14 @@ fun D.withFirDeclarationInWriteLock( /** * Returns a list of Diagnostics compiler finds for given [KtElement] + * This operation could be performance affective */ fun KtElement.getDiagnostics(resolveState: FirModuleResolveState, filter: DiagnosticCheckerFilter): Collection> = resolveState.getDiagnostics(this, filter) /** * Returns a list of Diagnostics compiler finds for given [KtFile] + * This operation could be performance affective */ fun KtFile.collectDiagnosticsForFile( resolveState: FirModuleResolveState, @@ -140,12 +137,13 @@ fun D.resolvedFirToPhase( phase: FirResolvePhase, resolveState: FirModuleResolveState ): D = - resolveState.resolvedFirToPhase(this, phase) + resolveState.resolveFirToPhase(this, phase) /** * Get a [FirElement] which was created by [KtElement] * Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase + * This operation could be performance affective */ fun KtElement.getOrBuildFir( resolveState: FirModuleResolveState, @@ -154,6 +152,7 @@ fun KtElement.getOrBuildFir( /** * Get a [FirElement] which was created by [KtElement], but only if it is subtype of [E], `null` otherwise * Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase + * This operation could be performance affective */ inline fun KtElement.getOrBuildFirSafe( resolveState: FirModuleResolveState, @@ -162,6 +161,7 @@ inline fun KtElement.getOrBuildFirSafe( /** * Get a [FirElement] which was created by [KtElement], but only if it is subtype of [E], throws [InvalidFirElementTypeException] otherwise * Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase + * This operation could be performance affective */ inline fun KtElement.getOrBuildFirOfType( resolveState: FirModuleResolveState, @@ -175,8 +175,8 @@ inline fun KtElement.getOrBuildFirOfType( * Get a [FirFile] which was created by [KtElement] * Returned [FirFile] can be resolved to any phase from [FirResolvePhase.RAW_FIR] to [FirResolvePhase.BODY_RESOLVE] */ -fun KtFile.getFirFile(resolveState: FirModuleResolveState): FirFile = - resolveState.getFirFile(this) +fun KtFile.getOrBuildFirFile(resolveState: FirModuleResolveState): FirFile = + resolveState.getOrBuildFirFile(this) class InvalidFirElementTypeException( ktElement: KtElement, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt index 6885cdd6776..3ec788c067d 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.parentsOfType import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder import org.jetbrains.kotlin.fir.builder.RawFirReplacement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.realPsi @@ -24,7 +25,6 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FileTowerProv import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FirElementsRecorder import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession -import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirProviderInterceptorForIDE import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.* @@ -72,8 +72,7 @@ object LowLevelFirApiFacadeForResolveOnAir { val declaration = runBodyResolveOnAir( state = state, replacement = RawFirReplacement(place, elementToResolve), - collector = null, - useFirProviderInterceptor = true + isOnAirResolve = true, ) val expressionLocator = object : FirVisitorVoid() { @@ -101,8 +100,17 @@ object LowLevelFirApiFacadeForResolveOnAir { return if (place is KtFile) { FileTowerProvider(place, onAirGetTowerContextForFile(state, place)) } else { + val validPlace = PsiTreeUtil.findFirstParent(place, false) { + RawFirFragmentForLazyBodiesBuilder.elementIsApplicable(it as KtElement) + } as KtElement + FirTowerDataContextAllElementsCollector().also { - runBodyResolveOnAir(state, collector = it, replacement = RawFirReplacement(place, place)) + runBodyResolveOnAir( + state = state, + collector = it, + replacement = RawFirReplacement(validPlace, validPlace), + isOnAirResolve = false //isOnAirResolve can be little faster because node resolved in it's context + ) } } } @@ -154,9 +162,9 @@ object LowLevelFirApiFacadeForResolveOnAir { val collector = FirTowerDataContextAllElementsCollector() val copiedFirDeclaration = runBodyResolveOnAir( originalState, - collector = collector, replacement = RawFirReplacement(sameDeclarationInOriginalFile, dependencyNonLocalDeclaration), - useFirProviderInterceptor = true + isOnAirResolve = true, + collector = collector, ) val recordedMap = FirElementsRecorder.recordElementsFrom(copiedFirDeclaration, FirElementsRecorder()) @@ -166,8 +174,8 @@ object LowLevelFirApiFacadeForResolveOnAir { private fun runBodyResolveOnAir( state: FirModuleResolveStateImpl, replacement: RawFirReplacement, + isOnAirResolve: Boolean, collector: FirTowerDataContextCollector? = null, - useFirProviderInterceptor: Boolean = false ): FirDeclaration { val nonLocalDeclaration = findEnclosingNonLocalDeclaration(replacement.from) @@ -179,30 +187,18 @@ object LowLevelFirApiFacadeForResolveOnAir { replacement = replacement, ) - val originalFirFile = state.getBuiltFirFileOrNull(replacement.from.containingKtFile) - ?: error("Original fir file should be already built") + val originalFirFile = state.getOrBuildFirFile(nonLocalDeclaration.containingKtFile) - val firProviderInterceptor = - if (useFirProviderInterceptor) FirProviderInterceptorForIDE.createForFirElement( - session = originalFirFile.declarationSiteSession, - firFile = originalFirFile, - element = copiedFirDeclaration - ) else null - - state.firFileBuilder.runCustomResolveWithPCECheck(originalFirFile, state.rootModuleSession.cache) { - state.firLazyDeclarationResolver.runLazyResolveWithoutLock( - copiedFirDeclaration, - state.rootModuleSession.cache, - originalFirFile, - originalFirFile.declarationSiteSession.firIdeProvider, - fromPhase = copiedFirDeclaration.resolvePhase, - toPhase = FirResolvePhase.BODY_RESOLVE, - towerDataContextCollector = collector, - checkPCE = true, - lastNonLazyPhase = FirResolvePhase.IMPORTS, - firProviderInterceptor = firProviderInterceptor, - ) - } + state.firLazyDeclarationResolver.lazyDesignatedResolveDeclaration( + firDeclarationToResolve = copiedFirDeclaration, + moduleFileCache = state.rootModuleSession.cache, + containerFirFile = originalFirFile, + provider = originalFirFile.declarationSiteSession.firIdeProvider, + toPhase = FirResolvePhase.BODY_RESOLVE, + checkPCE = true, + isOnAirResolve = isOnAirResolve, + towerDataContextCollector = collector, + ) return copiedFirDeclaration } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyBodiesCalculator.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyBodiesCalculator.kt index b402b4328b8..87c5435db2f 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyBodiesCalculator.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyBodiesCalculator.kt @@ -21,8 +21,8 @@ import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtSecondaryConstructor internal object FirLazyBodiesCalculator { - fun calculateLazyBodiesInside(element: FirElement, designation: FirDeclarationDesignation) { - element.transform>( + fun calculateLazyBodiesInside(designation: FirDeclarationDesignation) { + designation.declaration.transform>( FirLazyBodiesCalculatorTransformer, designation.toSequence(includeTarget = true).toMutableList() ) diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt index ac6bd3d604c..94453c7f9aa 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider -import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver +import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile @@ -24,34 +24,39 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.* import org.jetbrains.kotlin.idea.fir.low.level.api.util.* +import org.jetbrains.kotlin.idea.util.ifTrue import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject internal class FirLazyDeclarationResolver( private val firFileBuilder: FirFileBuilder ) { + /** + * Fully resolve file annotations (synchronized) + * @see resolveFileAnnotationsWithoutLock not synchronized + */ fun resolveFileAnnotations( firFile: FirFile, moduleFileCache: ModuleFileCache, scopeSession: ScopeSession, - ) { - check(firFile.resolvePhase >= FirResolvePhase.IMPORTS) - firFileBuilder.runCustomResolveUnderLock(firFile, moduleFileCache) { - val transformer = FirFileAnnotationsResolveTransformer(firFile.moduleData.session, scopeSession) - firFile.accept(transformer, ResolutionMode.ContextDependent) - } + ) = firFileBuilder.runCustomResolveUnderLock(firFile, moduleFileCache) { + resolveFileAnnotationsWithoutLock(firFile, scopeSession) } - fun lazyResolveDeclaration( - declaration: FirDeclaration, - moduleFileCache: ModuleFileCache, - toPhase: FirResolvePhase, - towerDataContextCollector: FirTowerDataContextCollector? = null, - checkPCE: Boolean = false, - reresolveFile: Boolean = false, + /** + * Fully resolve file annotations (not synchronized) + * @see resolveFileAnnotations synchronized version + */ + private fun resolveFileAnnotationsWithoutLock( + firFile: FirFile, + scopeSession: ScopeSession, ) { - if (declaration.resolvePhase >= toPhase) return + check(firFile.resolvePhase >= FirResolvePhase.IMPORTS) + val transformer = FirFileAnnotationsResolveTransformer(firFile.moduleData.session, scopeSession) + firFile.accept(transformer, ResolutionMode.ContextDependent) + } + private fun getResolvableDeclaration(declaration: FirDeclaration, moduleFileCache: ModuleFileCache): FirDeclaration { if (declaration is FirPropertyAccessor || declaration is FirTypeParameter || declaration is FirValueParameter) { val ktContainingResolvableDeclaration = when (val psi = declaration.psi) { is KtPropertyAccessor -> psi.property @@ -66,74 +71,105 @@ internal class FirLazyDeclarationResolver( null -> error("Cannot find containing declaration for KtParameter") else -> error("Invalid source of property accessor ${psi::class}") } - val containingProperty = ktContainingResolvableDeclaration - .findSourceNonLocalFirDeclaration(firFileBuilder, declaration.moduleData.session.symbolProvider, moduleFileCache) - return lazyResolveDeclaration(containingProperty, moduleFileCache, toPhase, towerDataContextCollector) + return ktContainingResolvableDeclaration.findSourceNonLocalFirDeclaration( + firFileBuilder = firFileBuilder, + firSymbolProvider = declaration.moduleData.session.symbolProvider, + moduleFileCache = moduleFileCache + ) } - val firFile = declaration.getContainingFile() - ?: error("FirFile was not found for\n${declaration.render()}") + return declaration + } + + /** + * Run partially designated resolve that resolve declaration into last file-wise resolve and then resolve a designation (synchronized) + * @see LAST_NON_LAZY_PHASE is the last file-wise resolve + * @see lazyDesignatedResolveDeclaration designated resolve + * @see runLazyResolveWithoutLock (not synchronized) + */ + fun lazyResolveDeclaration( + declaration: FirDeclaration, + moduleFileCache: ModuleFileCache, + toPhase: FirResolvePhase, + checkPCE: Boolean = false, + reresolveFile: Boolean = false, + ) { + if (declaration.resolvePhase >= toPhase) return + + val resolvableDeclaration = getResolvableDeclaration(declaration, moduleFileCache) + + val firFile = resolvableDeclaration.getContainingFile() + ?: error("FirFile was not found for\n${resolvableDeclaration.render()}") val provider = firFile.moduleData.session.firIdeProvider + // Lazy since we want to read the resolve phase inside the lock. Otherwise, we may run the same resolve phase multiple times. See // KT-45121 val fromPhase: FirResolvePhase by lazy(LazyThreadSafetyMode.NONE) { - if (reresolveFile) declaration.resolvePhase else minOf(firFile.resolvePhase, declaration.resolvePhase) + if (reresolveFile) resolvableDeclaration.resolvePhase else minOf(firFile.resolvePhase, resolvableDeclaration.resolvePhase) } if (checkPCE) { firFileBuilder.runCustomResolveWithPCECheck(firFile, moduleFileCache) { runLazyResolveWithoutLock( - declaration, - moduleFileCache, - firFile, - provider, - fromPhase, - toPhase, - towerDataContextCollector, - checkPCE = true + firDeclarationToResolve = declaration, + moduleFileCache = moduleFileCache, + containerFirFile = firFile, + provider = provider, + fromPhase = fromPhase, + toPhase = toPhase, + checkPCE = true, ) } } else { firFileBuilder.runCustomResolveUnderLock(firFile, moduleFileCache) { executeWithoutPCE { runLazyResolveWithoutLock( - declaration, - moduleFileCache, - firFile, - provider, - fromPhase, - toPhase, - towerDataContextCollector, - checkPCE = false + firDeclarationToResolve = declaration, + moduleFileCache = moduleFileCache, + containerFirFile = firFile, + provider = provider, + fromPhase = fromPhase, + toPhase = toPhase, + checkPCE = false, ) } } } } - private fun calculateLazyBodies(firDeclaration: FirDeclaration, designation: FirDeclarationDesignation) { - FirLazyBodiesCalculator.calculateLazyBodiesInside(firDeclaration, designation) + private fun createLazyBodiesCalculator(designation: FirDeclarationDesignation): (FirResolvePhase) -> Unit { + var calculated = false + return { phase: FirResolvePhase -> + if (!calculated && phase >= FirResolvePhase.CONTRACTS) { + executeWithoutPCE { + FirLazyBodiesCalculator.calculateLazyBodiesInside(designation) + } + calculated = true + } + } } - fun runLazyResolveWithoutLock( + /** + * Designated resolve (not synchronized) + * @see runLazyDesignatedResolveWithoutLock for designated resolve + * @see lazyResolveDeclaration synchronized version + */ + private fun runLazyResolveWithoutLock( firDeclarationToResolve: FirDeclaration, moduleFileCache: ModuleFileCache, containerFirFile: FirFile, provider: FirProvider, fromPhase: FirResolvePhase, toPhase: FirResolvePhase, - towerDataContextCollector: FirTowerDataContextCollector? = null, checkPCE: Boolean, - lastNonLazyPhase: FirResolvePhase = LAST_NON_LAZY_PHASE, - firProviderInterceptor: FirProviderInterceptorForSupertypeResolver? = null ) { if (fromPhase >= toPhase) return - val nonLazyPhase = minOf(toPhase, lastNonLazyPhase) + val nonLazyPhase = minOf(toPhase, LAST_NON_LAZY_PHASE) val scopeSession = ScopeSession() if (fromPhase < nonLazyPhase) { firFileBuilder.runResolveWithoutLock( - containerFirFile, + firFile = containerFirFile, fromPhase = fromPhase, toPhase = nonLazyPhase, scopeSession = scopeSession, @@ -141,27 +177,130 @@ internal class FirLazyDeclarationResolver( ) } if (toPhase <= nonLazyPhase) return - resolveFileAnnotations(containerFirFile, moduleFileCache, scopeSession) + resolveFileAnnotationsWithoutLock(containerFirFile, scopeSession) + + runLazyDesignatedResolveWithoutLock( + firDeclarationToResolve = firDeclarationToResolve, + moduleFileCache = moduleFileCache, + containerFirFile = containerFirFile, + provider = provider, + fromPhase = LAST_NON_LAZY_PHASE, + toPhase = toPhase, + checkPCE = checkPCE, + isOnAirResolve = false + ) + } + + /** + * Run designated resolve only designation with fully resolved path (synchronized). + * Suitable for body resolve or/and on-air resolve. + * @see lazyResolveDeclaration for ordinary resolve + * @param firDeclarationToResolve target non-local declaration + * @param isOnAirResolve should be true when node does not belong to it's true designation (OnAir resolve in custom context) + */ + fun lazyDesignatedResolveDeclaration( + firDeclarationToResolve: FirDeclaration, + moduleFileCache: ModuleFileCache, + containerFirFile: FirFile, + provider: FirProvider, + toPhase: FirResolvePhase, + checkPCE: Boolean, + isOnAirResolve: Boolean, + towerDataContextCollector: FirTowerDataContextCollector? = null, + ) { + // Lazy since we want to read the resolve phase inside the lock. Otherwise, we may run the same resolve phase multiple times. See + // KT-45121 + val fromPhase: FirResolvePhase by lazy(LazyThreadSafetyMode.NONE) { + minOf(containerFirFile.resolvePhase, firDeclarationToResolve.resolvePhase) + } + + if (checkPCE) { + firFileBuilder.runCustomResolveWithPCECheck(containerFirFile, moduleFileCache) { + runLazyDesignatedResolveWithoutLock( + firDeclarationToResolve = firDeclarationToResolve, + moduleFileCache = moduleFileCache, + containerFirFile = containerFirFile, + provider = provider, + fromPhase = fromPhase, + toPhase = toPhase, + checkPCE = checkPCE, + isOnAirResolve = isOnAirResolve, + towerDataContextCollector = towerDataContextCollector, + ) + } + } else { + firFileBuilder.runCustomResolveUnderLock(containerFirFile, moduleFileCache) { + runLazyDesignatedResolveWithoutLock( + firDeclarationToResolve = firDeclarationToResolve, + moduleFileCache = moduleFileCache, + containerFirFile = containerFirFile, + provider = provider, + fromPhase = fromPhase, + toPhase = toPhase, + checkPCE = checkPCE, + isOnAirResolve = isOnAirResolve, + towerDataContextCollector = towerDataContextCollector, + ) + } + } + } + + /** + * Designated resolve (not synchronized) + * @see runLazyResolveWithoutLock for ordinary resolve + * @see lazyDesignatedResolveDeclaration synchronized version + */ + private fun runLazyDesignatedResolveWithoutLock( + firDeclarationToResolve: FirDeclaration, + moduleFileCache: ModuleFileCache, + containerFirFile: FirFile, + provider: FirProvider, + fromPhase: FirResolvePhase, + toPhase: FirResolvePhase, + checkPCE: Boolean, + isOnAirResolve: Boolean, + towerDataContextCollector: FirTowerDataContextCollector? = null + ) { + var currentPhase = fromPhase + runLazyResolveWithoutLock( + firDeclarationToResolve = firDeclarationToResolve, + moduleFileCache = moduleFileCache, + containerFirFile = containerFirFile, + provider = provider, + fromPhase = currentPhase, + toPhase = FirResolvePhase.IMPORTS, + checkPCE = checkPCE + ) + currentPhase = maxOf(fromPhase, FirResolvePhase.IMPORTS) + if (currentPhase >= toPhase) return val nonLocalDeclarationToResolve = firDeclarationToResolve.getNonLocalDeclarationToResolve(provider, moduleFileCache) val designation = nonLocalDeclarationToResolve.collectDesignation(containerFirFile) + check(!designation.isLocalDesignation) { "Could not resolve local designation" } - executeWithoutPCE { - calculateLazyBodies(firDeclarationToResolve, designation) + val lazyBodiesCalculator = createLazyBodiesCalculator(designation) + val scopeSession = ScopeSession() + + //This needed to override standard symbol resolve in supertype transformer with adding on-air created symbols + val firProviderInterceptor = isOnAirResolve.ifTrue { + FirProviderInterceptorForIDE.createForFirElement( + session = designation.firFile.moduleData.session, + firFile = designation.firFile, + element = designation.declaration + ) } - var currentPhase = nonLazyPhase - while (currentPhase < toPhase) { currentPhase = currentPhase.next if (currentPhase.pluginPhase) continue if (checkPCE) checkCanceled() + lazyBodiesCalculator(currentPhase) runLazyResolvePhase( - currentPhase, - scopeSession, - towerDataContextCollector, - firProviderInterceptor, - designation, + phase = currentPhase, + scopeSession = scopeSession, + designation = designation, + towerDataContextCollector = towerDataContextCollector, + firProviderInterceptor = firProviderInterceptor ) } } @@ -169,9 +308,9 @@ internal class FirLazyDeclarationResolver( private fun runLazyResolvePhase( phase: FirResolvePhase, scopeSession: ScopeSession, + designation: FirDeclarationDesignationWithFile, towerDataContextCollector: FirTowerDataContextCollector?, - firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?, - designation: FirDeclarationDesignationWithFile + firProviderInterceptor: FirProviderInterceptor? ) { if (designation.declaration.resolvePhase >= phase) return @@ -191,7 +330,7 @@ internal class FirLazyDeclarationResolver( designation: FirDeclarationDesignationWithFile, scopeSession: ScopeSession, towerDataContextCollector: FirTowerDataContextCollector?, - firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?, + firProviderInterceptor: FirProviderInterceptor?, ): FirLazyTransformerForIDE = when (this) { FirResolvePhase.SUPER_TYPES -> FirDesignatedSupertypeResolverTransformerForIDE( designation, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedBodyResolveTransformerForIDE.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedBodyResolveTransformerForIDE.kt index 560fe641ca7..f4208077089 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedBodyResolveTransformerForIDE.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedBodyResolveTransformerForIDE.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver +import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.* import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator @@ -23,7 +23,7 @@ internal class FirDesignatedBodyResolveTransformerForIDE( session: FirSession, scopeSession: ScopeSession, towerDataContextCollector: FirTowerDataContextCollector? = null, - firProviderInterceptor: FirProviderInterceptorForSupertypeResolver? = null, + firProviderInterceptor: FirProviderInterceptor? = null, ) : FirLazyTransformerForIDE, FirBodyResolveTransformer( session, phase = FirResolvePhase.BODY_RESOLVE, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedStatusResolveTransformerForIDE.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedStatusResolveTransformerForIDE.kt index 61cbf59afd2..59a508137f4 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedStatusResolveTransformerForIDE.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedStatusResolveTransformerForIDE.kt @@ -17,42 +17,12 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePathPhase import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase -class FirDesignatedStatusResolveTransformerForIDE( +internal class FirDesignatedStatusResolveTransformerForIDE( private val designation: FirDeclarationDesignationWithFile, private val session: FirSession, private val scopeSession: ScopeSession, ) : FirLazyTransformerForIDE { - private val firstItemInDesignation = designation.path.firstOrNull() ?: designation.declaration - - private fun resolveClass(targetClass: FirClass<*>) { - val transformer = FirDesignatedStatusResolveTransformer( - session = session, - scopeSession = scopeSession, - designation = designation.toSequence(includeTarget = true).iterator(), - targetClass = targetClass, - statusComputationSession = StatusComputationSession.Regular(), - designationMapForLocalClasses = emptyMap(), - scopeForLocalClass = null - ) - - firstItemInDesignation.transformSingle(transformer, null) - } - - private fun resolveTypeAlias(targetClass: FirTypeAlias) { - val transformer = FirDesignatedStatusResolveTransformer( - session = session, - scopeSession = scopeSession, - designation = designation.toSequence(includeTarget = true).iterator(), - targetClass = targetClass, - statusComputationSession = StatusComputationSession.Regular(), - designationMapForLocalClasses = emptyMap(), - scopeForLocalClass = null - ) - - firstItemInDesignation.transformSingle(transformer, null) - } - private fun resolveTopLevelDeclaration(declaration: FirDeclaration) { val transformer = FirStatusResolveTransformer( session = session, @@ -62,13 +32,13 @@ class FirDesignatedStatusResolveTransformerForIDE( declaration.transformSingle(transformer, null) } - private fun resolveClassMember(containingClass: FirClass<*>, targetCallable: FirDeclaration) { + private fun resolveClassMember(containingClass: FirClass<*>, targetDeclaration: FirDeclaration) { val transformer = object : FirDesignatedStatusResolveTransformer( session = session, scopeSession = scopeSession, designation = designation.toSequence(includeTarget = true).iterator(), - targetClass = if (targetCallable is FirRegularClass) targetCallable else containingClass, + targetClass = if (targetDeclaration is FirRegularClass) targetDeclaration else containingClass, statusComputationSession = StatusComputationSession.Regular(), designationMapForLocalClasses = emptyMap(), scopeForLocalClass = null @@ -77,12 +47,13 @@ class FirDesignatedStatusResolveTransformerForIDE( override fun > transformClass(klass: FirClass, data: FirResolvedDeclarationStatus?): FirStatement { if (klass != containingClass) return super.transformClass(klass, data) val result = storeClass(klass) { - targetCallable.transformSingle(this, data) + targetDeclaration.transformSingle(this, data) } return result as FirStatement } } + val firstItemInDesignation = designation.path.firstOrNull() ?: designation.declaration firstItemInDesignation.transformSingle(transformer, null) } @@ -95,7 +66,7 @@ class FirDesignatedStatusResolveTransformerForIDE( if (containingClass == null) { resolveTopLevelDeclaration(designation.declaration) } else { - check(containingClass is FirClass<*>) { "Invalid designation - the parent is a class" } + check(containingClass is FirClass<*>) { "Invalid designation - the parent is not a class" } resolveClassMember(containingClass, designation.declaration) } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedSupertypeResolverTransformerForIDE.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedSupertypeResolverTransformerForIDE.kt index c7d16523d3e..c4349012404 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedSupertypeResolverTransformerForIDE.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedSupertypeResolverTransformerForIDE.kt @@ -10,27 +10,26 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.FirApplySupertypesTransformer -import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver +import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverVisitor import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePathPhase -import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhaseIfClass internal class FirDesignatedSupertypeResolverTransformerForIDE( private val designation: FirDeclarationDesignationWithFile, private val session: FirSession, private val scopeSession: ScopeSession, - private val firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?, + private val firProviderInterceptor: FirProviderInterceptor? ) : FirLazyTransformerForIDE { - private val supertypeComputationSession = SupertypeComputationSession() - override fun transformDeclaration() { if (designation.declaration.resolvePhase >= FirResolvePhase.SUPER_TYPES) return designation.ensurePathPhase(FirResolvePhase.SUPER_TYPES) + val supertypeComputationSession = SupertypeComputationSession() + val resolver = FirSupertypeResolverVisitor( session = session, supertypeComputationSession = supertypeComputationSession, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedTypeResolverTransformerForIDE.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedTypeResolverTransformerForIDE.kt index 1e71914402b..7081a28d920 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedTypeResolverTransformerForIDE.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirDesignatedTypeResolverTransformerForIDE.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransform import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhaseIfClass -class FirDesignatedTypeResolverTransformerForIDE( +internal class FirDesignatedTypeResolverTransformerForIDE( private val designation: FirDeclarationDesignationWithFile, session: FirSession, scopeSession: ScopeSession, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirLazyTransformerForIDE.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirLazyTransformerForIDE.kt index 865500f90c9..a5a2de19682 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirLazyTransformerForIDE.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirLazyTransformerForIDE.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.transformers import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation internal interface FirLazyTransformerForIDE { fun transformDeclaration() @@ -16,7 +16,7 @@ internal interface FirLazyTransformerForIDE { override fun transformDeclaration() = Unit } - fun FirDeclarationDesignationWithFile.ensurePathPhase(firResolvePhase: FirResolvePhase) { + fun FirDeclarationDesignation.ensurePathPhase(firResolvePhase: FirResolvePhase) { toSequence(includeTarget = false).forEach { firDeclaration -> check(firDeclaration.resolvePhase >= firResolvePhase) { "Designation element phase required to be $firResolvePhase but element resolved to ${firDeclaration.resolvePhase}" @@ -24,19 +24,13 @@ internal interface FirLazyTransformerForIDE { } } - fun FirDeclarationDesignationWithFile.ensureTargetPhase(firResolvePhase: FirResolvePhase) = + fun FirDeclarationDesignation.ensureTargetPhase(firResolvePhase: FirResolvePhase) = check(declaration.resolvePhase >= firResolvePhase) { "Expected $firResolvePhase but found ${declaration.resolvePhase}" } - fun FirDeclarationDesignationWithFile.ensureTargetPhaseIfClass(firResolvePhase: FirResolvePhase) = when (declaration) { + fun FirDeclarationDesignation.ensureTargetPhaseIfClass(firResolvePhase: FirResolvePhase) = when (declaration) { is FirProperty, is FirSimpleFunction -> Unit is FirClass<*>, is FirTypeAlias -> ensureTargetPhase(firResolvePhase) else -> error("Unexpected target") } - - fun FirDeclarationDesignationWithFile.ensureTargetPhaseIfMember(firResolvePhase: FirResolvePhase) = when (declaration) { - is FirProperty, is FirSimpleFunction -> ensureTargetPhase(firResolvePhase) - is FirClass<*>, is FirTypeAlias -> Unit - else -> error("Unexpected target") - } } } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirProviderInterceptorForIDE.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirProviderInterceptorForIDE.kt index 8690adff5e8..1400e7a730d 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirProviderInterceptorForIDE.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/transformers/FirProviderInterceptorForIDE.kt @@ -10,7 +10,7 @@ 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.resolve.firProvider -import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver +import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.name.ClassId @@ -20,7 +20,7 @@ internal class FirProviderInterceptorForIDE private constructor( private val session: FirSession, private val symbolSet: Set>, private val classIdToElementMap: Map> -) : FirProviderInterceptorForSupertypeResolver { +) : FirProviderInterceptor { override fun getFirClassifierContainerFileIfAny(symbol: FirClassLikeSymbol<*>): FirFile? = if (symbolSet.contains(symbol)) firFile else session.firProvider.getFirClassifierContainerFileIfAny(symbol) @@ -29,7 +29,7 @@ internal class FirProviderInterceptorForIDE private constructor( classIdToElementMap[classId] ?: session.firProvider.getFirClassifierByFqName(classId) companion object { - fun createForFirElement(session: FirSession, firFile: FirFile, element: FirElement): FirProviderInterceptorForSupertypeResolver { + fun createForFirElement(session: FirSession, firFile: FirFile, element: FirElement): FirProviderInterceptor { val nodeInfoCollector = object : FirVisitorVoid() { val symbolSet = mutableSetOf>() val classIdToElementMap = mutableMapOf>() diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt index afe4e072af4..bf93d7c2334 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt @@ -10,6 +10,8 @@ import com.intellij.testFramework.LightProjectDescriptor import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo +import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase @@ -41,7 +43,7 @@ abstract class AbstractFirLazyDeclarationResolveTest : KotlinLightCodeInsightFix firModuleResolveState, FirResolvePhase.BODY_RESOLVE ) @Suppress("UNUSED_ANONYMOUS_PARAMETER") { firDeclaration -> - val firFile = firModuleResolveState.getBuiltFirFileOrNull(ktFile)!! + val firFile = firModuleResolveState.getOrBuildFirFile(ktFile) firFile.render(FirRenderer.RenderMode.WithResolvePhases) } val expectedFileName = testDataFile.name.replace(".kt", ".txt") diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/compiler/based/AbstractCompilerBasedTest.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/compiler/based/AbstractCompilerBasedTest.kt index 60d59db74eb..42e5bb952c4 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/compiler/based/AbstractCompilerBasedTest.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/compiler/based/AbstractCompilerBasedTest.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirFile import org.jetbrains.kotlin.idea.fir.low.level.api.createResolveStateForNoCaching import org.jetbrains.kotlin.idea.project.withLanguageVersionSettings import org.jetbrains.kotlin.idea.test.* @@ -76,7 +76,7 @@ abstract class AbstractCompilerBasedTest : KotlinLightCodeInsightFixtureTestCase val resolveState = createResolveState(moduleInfo, module.languageVersionSettings) val allFirFiles = files.mapNotNull { (testFile, psiFile) -> if (psiFile !is KtFile) return@mapNotNull null - testFile to psiFile.getFirFile(resolveState) + testFile to psiFile.getOrBuildFirFile(resolveState) }.toMap() val diagnosticCheckerFilter = if (FirDiagnosticsDirectives.WITH_EXTENDED_CHECKERS in module.directives) { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/AbstractFirContextCollectionTest.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/AbstractFirContextCollectionTest.kt index d0e11352b9d..ba9ad7afdf4 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/AbstractFirContextCollectionTest.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/AbstractFirContextCollectionTest.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.getDiagnostics -import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirFile import org.jetbrains.kotlin.idea.fir.low.level.api.createResolveStateForNoCaching import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.BeforeElementDiagnosticCollectionHandler import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistenceContextCollector @@ -45,7 +45,7 @@ abstract class AbstractFirContextCollectionTest : KotlinLightCodeInsightFixtureT val fileStructure = resolveState.fileStructureCache.getFileStructure(ktFile, resolveState.rootModuleSession.cache) val allStructureElements = fileStructure.getAllStructureElements() handler.elementsToCheckContext = allStructureElements.map { it.getFirDeclaration() } - handler.firFile = ktFile.getFirFile(resolveState) + handler.firFile = ktFile.getOrBuildFirFile(resolveState) ktFile.getDiagnostics(resolveState, DiagnosticCheckerFilter.ONLY_COMMON_CHECKERS) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompletionCandidateChecker.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompletionCandidateChecker.kt index 9a837b2e9e5..5a87f14c5df 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompletionCandidateChecker.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCompletionCandidateChecker.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider -import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirOfType import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.ResolutionParameters import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolutionMode @@ -61,7 +61,7 @@ internal class KtFirCompletionCandidateChecker( nameExpression: KtSimpleNameExpression, possibleExplicitReceiver: KtExpression?, ): Boolean { - val file = originalFile.getFirFile(firResolveState) + val file = originalFile.getOrBuildFirFile(firResolveState) val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType(firResolveState) val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file) val implicitReceivers = getImplicitReceivers(originalFile, file, nameExpression) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt index 62adb5e4149..6916b9dfdaf 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/symbols/KtFirSymbolProvider.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirOfType import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclarationOfType import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession @@ -41,7 +41,7 @@ internal class KtFirSymbolProvider( } override fun getFileSymbol(psi: KtFile): KtFileSymbol = withValidityAssertion { - firSymbolBuilder.buildFileSymbol(psi.getFirFile(resolveState)) + firSymbolBuilder.buildFileSymbol(psi.getOrBuildFirFile(resolveState)) } override fun getFunctionLikeSymbol(psi: KtNamedFunction): KtFunctionLikeSymbol = withValidityAssertion {