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 fd4ebc4b738..e76e6ec735e 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 @@ -5,157 +5,22 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api -import com.intellij.psi.PsiElement import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyAccessorCopy -import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy -import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy -import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext import org.jetbrains.kotlin.idea.caches.project.getModuleInfo -import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateForCompletion -import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl -import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector -import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider -import org.jetbrains.kotlin.idea.util.getElementTextInContext -import org.jetbrains.kotlin.psi.KtProperty object LowLevelFirApiFacade { fun getResolveStateFor(element: KtElement): FirModuleResolveState = element.firResolveState() - fun getResolveStateForCompletion(element: KtElement, originalState: FirModuleResolveState): FirModuleResolveState { - check(originalState is FirModuleResolveStateImpl) - return FirModuleResolveStateForCompletion(originalState) - } - fun getSessionFor(element: KtElement): FirSession = getResolveStateFor(element).getSessionFor(element.getModuleInfo()) fun getOrBuildFirFor(element: KtElement, resolveState: FirModuleResolveState): FirElement = resolveState.getOrBuildFirFor(element) - class FirCompletionContext internal constructor( - val session: FirSession, - private val towerDataContextCollector: FirTowerDataContextCollector, - ) { - fun getTowerDataContext(element: KtElement): FirTowerDataContext { - var current: PsiElement? = element - while (current is KtElement) { - towerDataContextCollector.getContext(current)?.let { return it } - current = current.parent - } - - error("No context for ${element.getElementTextInContext()}") - } - } - - fun buildCompletionContextForFunction( - firFile: FirFile, - fakeElement: KtNamedFunction, - originalElement: KtNamedFunction, - state: FirModuleResolveState, - ): FirCompletionContext { - val firIdeProvider = firFile.session.firIdeProvider - - val originalFunction = state.getOrBuildFirFor(originalElement) as FirSimpleFunction - val copyFunction = buildFunctionCopyForCompletion(firIdeProvider, fakeElement, originalFunction, state) - - val contextCollector = FirTowerDataContextCollector() - state.lazyResolveDeclarationForCompletion(copyFunction, firFile, firIdeProvider, FirResolvePhase.BODY_RESOLVE, contextCollector) - state.recordPsiToFirMappingsForCompletionFrom(copyFunction, firFile, fakeElement.containingKtFile) - - return FirCompletionContext( - copyFunction.session, - contextCollector - ) - } - - fun buildCompletionContextForProperty( - firFile: FirFile, - fakeElement: KtProperty, - originalElement: KtProperty, - state: FirModuleResolveState, - ): FirCompletionContext { - val firIdeProvider = firFile.session.firIdeProvider - - val originalProperty = state.getOrBuildFirFor(originalElement) as FirProperty - val copyProperty = buildPropertyCopyForCompletion(firIdeProvider, fakeElement, originalProperty, state) - - val contextCollector = FirTowerDataContextCollector() - state.lazyResolveDeclarationForCompletion(copyProperty, firFile, firIdeProvider, FirResolvePhase.BODY_RESOLVE, contextCollector) - state.recordPsiToFirMappingsForCompletionFrom(copyProperty, firFile, fakeElement.containingKtFile) - - return FirCompletionContext( - copyProperty.session, - contextCollector - ) - } - - private fun buildFunctionCopyForCompletion( - firIdeProvider: FirIdeProvider, - element: KtNamedFunction, - originalFunction: FirSimpleFunction, - state: FirModuleResolveState - ): FirSimpleFunction { - val builtFunction = firIdeProvider.buildFunctionWithBody(element) - - // 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 - // take original function header (which is resolved) and copy replacing body with body from builtFunction - return buildSimpleFunctionCopy(originalFunction) { - body = builtFunction.body - symbol = builtFunction.symbol as FirNamedFunctionSymbol - resolvePhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS) - source = builtFunction.source - session = state.rootModuleSession - } - } - - - private fun buildPropertyCopyForCompletion( - firIdeProvider: FirIdeProvider, - element: KtProperty, - originalProperty: FirProperty, - state: FirModuleResolveState - ): FirProperty { - val builtProperty = firIdeProvider.buildPropertyWithBody(element) - - val originalSetter = originalProperty.setter - val builtSetter = builtProperty.setter - - // setter has a header with `value` parameter, and we want it type to be resolved - val copySetter = if (originalSetter != null && builtSetter != null) { - buildPropertyAccessorCopy(originalSetter) { - body = builtSetter.body - symbol = builtSetter.symbol - resolvePhase = minOf(builtSetter.resolvePhase, FirResolvePhase.DECLARATIONS) - source = builtSetter.source - session = state.rootModuleSession - } - } else { - builtSetter - } - - return buildPropertyCopy(originalProperty) { - symbol = builtProperty.symbol - initializer = builtProperty.initializer - - getter = builtProperty.getter - setter = copySetter - - resolvePhase = minOf(originalProperty.resolvePhase, FirResolvePhase.DECLARATIONS) - source = builtProperty.source - session = state.rootModuleSession - } - } - fun getDiagnosticsFor(element: KtElement, resolveState: FirModuleResolveState): Collection { return resolveState.getDiagnostics(element) } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt new file mode 100644 index 00000000000..824ce66aee5 --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt @@ -0,0 +1,149 @@ +/* + * 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.idea.fir.low.level.api.api + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyAccessorCopy +import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy +import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy +import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateForCompletion +import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl +import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector +import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider +import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider +import org.jetbrains.kotlin.idea.util.getElementTextInContext +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtProperty + +object LowLevelFirApiFacadeForCompletion { + fun getResolveStateForCompletion(element: KtElement, originalState: FirModuleResolveState): FirModuleResolveState { + check(originalState is FirModuleResolveStateImpl) + return FirModuleResolveStateForCompletion(originalState) + } + + class FirCompletionContext internal constructor( + val session: FirSession, + private val towerDataContextCollector: FirTowerDataContextCollector, + ) { + fun getTowerDataContext(element: KtElement): FirTowerDataContext { + var current: PsiElement? = element + while (current is KtElement) { + towerDataContextCollector.getContext(current)?.let { return it } + current = current.parent + } + + error("No context for ${element.getElementTextInContext()}") + } + } + + fun buildCompletionContextForFunction( + firFile: FirFile, + fakeElement: KtNamedFunction, + originalElement: KtNamedFunction, + state: FirModuleResolveState, + ): FirCompletionContext { + val firIdeProvider = firFile.session.firIdeProvider + + val originalFunction = state.getOrBuildFirFor(originalElement) as FirSimpleFunction + val copyFunction = buildFunctionCopyForCompletion(firIdeProvider, fakeElement, originalFunction, state) + + val contextCollector = FirTowerDataContextCollector() + state.lazyResolveDeclarationForCompletion(copyFunction, firFile, firIdeProvider, FirResolvePhase.BODY_RESOLVE, contextCollector) + state.recordPsiToFirMappingsForCompletionFrom(copyFunction, firFile, fakeElement.containingKtFile) + + return FirCompletionContext( + copyFunction.session, + contextCollector + ) + } + + fun buildCompletionContextForProperty( + firFile: FirFile, + fakeElement: KtProperty, + originalElement: KtProperty, + state: FirModuleResolveState, + ): FirCompletionContext { + val firIdeProvider = firFile.session.firIdeProvider + + val originalProperty = state.getOrBuildFirFor(originalElement) as FirProperty + val copyProperty = buildPropertyCopyForCompletion(firIdeProvider, fakeElement, originalProperty, state) + + val contextCollector = FirTowerDataContextCollector() + state.lazyResolveDeclarationForCompletion(copyProperty, firFile, firIdeProvider, FirResolvePhase.BODY_RESOLVE, contextCollector) + state.recordPsiToFirMappingsForCompletionFrom(copyProperty, firFile, fakeElement.containingKtFile) + + return FirCompletionContext( + copyProperty.session, + contextCollector + ) + } + + private fun buildFunctionCopyForCompletion( + firIdeProvider: FirIdeProvider, + element: KtNamedFunction, + originalFunction: FirSimpleFunction, + state: FirModuleResolveState + ): FirSimpleFunction { + val builtFunction = firIdeProvider.buildFunctionWithBody(element) + + // 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 + // take original function header (which is resolved) and copy replacing body with body from builtFunction + return buildSimpleFunctionCopy(originalFunction) { + body = builtFunction.body + symbol = builtFunction.symbol as FirNamedFunctionSymbol + resolvePhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS) + source = builtFunction.source + session = state.rootModuleSession + } + } + + + private fun buildPropertyCopyForCompletion( + firIdeProvider: FirIdeProvider, + element: KtProperty, + originalProperty: FirProperty, + state: FirModuleResolveState + ): FirProperty { + val builtProperty = firIdeProvider.buildPropertyWithBody(element) + + val originalSetter = originalProperty.setter + val builtSetter = builtProperty.setter + + // setter has a header with `value` parameter, and we want it type to be resolved + val copySetter = if (originalSetter != null && builtSetter != null) { + buildPropertyAccessorCopy(originalSetter) { + body = builtSetter.body + symbol = builtSetter.symbol + resolvePhase = minOf(builtSetter.resolvePhase, FirResolvePhase.DECLARATIONS) + source = builtSetter.source + session = state.rootModuleSession + } + } else { + builtSetter + } + + return buildPropertyCopy(originalProperty) { + symbol = builtProperty.symbol + initializer = builtProperty.initializer + + getter = builtProperty.getter + setter = copySetter + + resolvePhase = minOf(originalProperty.resolvePhase, FirResolvePhase.DECLARATIONS) + source = builtProperty.source + session = state.rootModuleSession + } + } +} diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt index 32336dcaf6d..d2930fdca84 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacade +import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.ReadActionConfinementValidityToken import org.jetbrains.kotlin.idea.frontend.api.ValidityToken @@ -47,7 +48,7 @@ private constructor( override fun createContextDependentCopy(): KtAnalysisSession { check(!isContextSession) { "Cannot create context-dependent copy of KtAnalysis session from a context dependent one" } - val contextResolveState = LowLevelFirApiFacade.getResolveStateForCompletion(element, firResolveState) + val contextResolveState = LowLevelFirApiFacadeForCompletion.getResolveStateForCompletion(element, firResolveState) return KtFirAnalysisSession( element, contextResolveState, 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 0290faea99d..e65a6b492b3 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 @@ -38,7 +38,8 @@ internal class KtFirCompletionCandidateChecker( ) : KtCompletionCandidateChecker(), KtFirAnalysisSessionComponent { override val analysisSession: KtFirAnalysisSession by weakRef(analysisSession) - private val completionContextCache = HashMap, LowLevelFirApiFacade.FirCompletionContext>() + private val completionContextCache = + HashMap, LowLevelFirApiFacadeForCompletion.FirCompletionContext>() override fun checkExtensionFitsCandidate( firSymbolForCandidate: KtCallableSymbol, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt index fe93c49ddd7..50c24078154 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirScopeProvider.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacade +import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner @@ -126,7 +127,7 @@ internal class KtFirScopeProvider( private fun buildCompletionContextForEnclosingDeclaration( originalFile: KtFile, positionInFakeFile: KtElement - ): LowLevelFirApiFacade.FirCompletionContext { + ): LowLevelFirApiFacadeForCompletion.FirCompletionContext { val originalFirFile = firResolveState.getFirFile(originalFile) val declarationContext = EnclosingDeclarationContext.detect(originalFile, positionInFakeFile) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt index 316b82fa72c..2db0bab2634 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt @@ -9,6 +9,7 @@ import com.intellij.psi.util.parentsOfType import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacade +import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.* @@ -57,14 +58,14 @@ internal val EnclosingDeclarationContext.fakeEnclosingDeclaration: KtCallableDec internal fun EnclosingDeclarationContext.buildCompletionContext(originalFirFile: FirFile, firResolveState: FirModuleResolveState) = when (this) { - is FunctionContext -> LowLevelFirApiFacade.buildCompletionContextForFunction( + is FunctionContext -> LowLevelFirApiFacadeForCompletion.buildCompletionContextForFunction( originalFirFile, fakeEnclosingFunction, originalEnclosingFunction, state = firResolveState ) - is PropertyContext -> LowLevelFirApiFacade.buildCompletionContextForProperty( + is PropertyContext -> LowLevelFirApiFacadeForCompletion.buildCompletionContextForProperty( originalFirFile, fakeEnclosingProperty, originalEnclosingProperty,