FIR IDE: separate LowLevelFirApiFacade from completion
This commit is contained in:
-135
@@ -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<Diagnostic> {
|
||||
return resolveState.getDiagnostics(element)
|
||||
}
|
||||
|
||||
+149
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -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,
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ internal class KtFirCompletionCandidateChecker(
|
||||
) : KtCompletionCandidateChecker(), KtFirAnalysisSessionComponent {
|
||||
override val analysisSession: KtFirAnalysisSession by weakRef(analysisSession)
|
||||
|
||||
private val completionContextCache = HashMap<Pair<FirFile, KtCallableDeclaration>, LowLevelFirApiFacade.FirCompletionContext>()
|
||||
private val completionContextCache =
|
||||
HashMap<Pair<FirFile, KtCallableDeclaration>, LowLevelFirApiFacadeForCompletion.FirCompletionContext>()
|
||||
|
||||
override fun checkExtensionFitsCandidate(
|
||||
firSymbolForCandidate: KtCallableSymbol,
|
||||
|
||||
+2
-1
@@ -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)
|
||||
|
||||
|
||||
+3
-2
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user