FIR IDE: Modify KtFirAnalysisSession for completion
- This is WIP solution for having a specialized `KtFirAnalysisSession` for the completion Co-authored-by: Ilya Kirillov <ilya.kirillov@jetbrains.com>
This commit is contained in:
committed by
Ilya Kirillov
parent
54946a793a
commit
a6dd84a7e4
@@ -35,4 +35,6 @@ abstract class KtAnalysisSession(project: Project) : ValidityOwner {
|
|||||||
|
|
||||||
abstract fun resolveCall(call: KtCallExpression): CallInfo?
|
abstract fun resolveCall(call: KtCallExpression): CallInfo?
|
||||||
abstract fun resolveCall(call: KtBinaryExpression): CallInfo?
|
abstract fun resolveCall(call: KtBinaryExpression): CallInfo?
|
||||||
|
|
||||||
|
abstract fun analyzeInContext(): KtAnalysisSession
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -8,10 +8,19 @@ package org.jetbrains.kotlin.idea.frontend.api.scopes
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
|
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
abstract class KtScopeProvider : ValidityOwner {
|
abstract class KtScopeProvider : ValidityOwner {
|
||||||
abstract fun getMemberScope(classSymbol: KtClassOrObjectSymbol): KtMemberScope
|
abstract fun getMemberScope(classSymbol: KtClassOrObjectSymbol): KtMemberScope
|
||||||
abstract fun getDeclaredMemberScope(classSymbol: KtClassOrObjectSymbol): KtDeclaredMemberScope
|
abstract fun getDeclaredMemberScope(classSymbol: KtClassOrObjectSymbol): KtDeclaredMemberScope
|
||||||
abstract fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope
|
abstract fun getPackageScope(packageSymbol: KtPackageSymbol): KtPackageScope
|
||||||
abstract fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope
|
abstract fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope
|
||||||
}
|
|
||||||
|
abstract fun getScopeForType(type: KtType): KtScope?
|
||||||
|
|
||||||
|
abstract fun getScopeContextForPosition(originalFile: KtFile, positionInFakeFile: KtElement): KtScopeContext
|
||||||
|
}
|
||||||
|
|
||||||
|
data class KtScopeContext(val scopes: KtCompositeScope, val implicitReceiversTypes: List<KtType>)
|
||||||
|
|||||||
+1
-1
@@ -63,9 +63,9 @@ object LowLevelFirApiFacade {
|
|||||||
fun buildCompletionContextForFunction(
|
fun buildCompletionContextForFunction(
|
||||||
firFile: FirFile,
|
firFile: FirFile,
|
||||||
element: KtNamedFunction,
|
element: KtNamedFunction,
|
||||||
|
state: FirModuleResolveState,
|
||||||
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
|
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
|
||||||
): FirCompletionContext {
|
): FirCompletionContext {
|
||||||
val state = element.firResolveState()
|
|
||||||
val firIdeProvider = firFile.session.firIdeProvider
|
val firIdeProvider = firFile.session.firIdeProvider
|
||||||
val builtFunction = firIdeProvider.buildFunctionWithBody(element)
|
val builtFunction = firIdeProvider.buildFunctionWithBody(element)
|
||||||
val towerDataContextForStatement = mutableMapOf<FirStatement, FirTowerDataContext>()
|
val towerDataContextForStatement = mutableMapOf<FirStatement, FirTowerDataContext>()
|
||||||
|
|||||||
+5
-1
@@ -55,7 +55,11 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
|
|||||||
|
|
||||||
val parentFunction = nameExpression.getNonStrictParentOfType<KtNamedFunction>() ?: return
|
val parentFunction = nameExpression.getNonStrictParentOfType<KtNamedFunction>() ?: return
|
||||||
|
|
||||||
val completionContext = LowLevelFirApiFacade.buildCompletionContextForFunction(originalFileFir, parentFunction)
|
val completionContext = LowLevelFirApiFacade.buildCompletionContextForFunction(
|
||||||
|
originalFileFir,
|
||||||
|
parentFunction,
|
||||||
|
LowLevelFirApiFacade.getResolveStateFor(originalFile)
|
||||||
|
)
|
||||||
|
|
||||||
val element = nameExpression.getFirOfClosestParent() as? FirQualifiedAccessExpression ?: return
|
val element = nameExpression.getFirOfClosestParent() as? FirQualifiedAccessExpression ?: return
|
||||||
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
|
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
|
||||||
|
|||||||
+13
-3
@@ -19,6 +19,8 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.idea.fir.*
|
import org.jetbrains.kotlin.idea.fir.*
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.*
|
import org.jetbrains.kotlin.idea.frontend.api.*
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.scopes.KtFirScopeProvider
|
import org.jetbrains.kotlin.idea.frontend.api.fir.scopes.KtFirScopeProvider
|
||||||
@@ -38,11 +40,12 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
class KtFirAnalysisSession
|
class KtFirAnalysisSession
|
||||||
@Deprecated("Please use org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProviderKt.analyze")
|
@Deprecated("Please use org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProviderKt.analyze")
|
||||||
constructor(
|
constructor(
|
||||||
private val element: KtElement
|
private val element: KtElement,
|
||||||
|
resolveState: FirModuleResolveState
|
||||||
) : KtAnalysisSession(element.project) {
|
) : KtAnalysisSession(element.project) {
|
||||||
internal val token get() = validityToken
|
internal val token get() = validityToken
|
||||||
|
|
||||||
internal val firResolveState = LowLevelFirApiFacade.getResolveStateFor(element)
|
internal val firResolveState = resolveState
|
||||||
|
|
||||||
internal val firSession get() = LowLevelFirApiFacade.getSessionFor(element, firResolveState)
|
internal val firSession get() = LowLevelFirApiFacade.getSessionFor(element, firResolveState)
|
||||||
|
|
||||||
@@ -67,7 +70,7 @@ constructor(
|
|||||||
firSymbolBuilder
|
firSymbolBuilder
|
||||||
)
|
)
|
||||||
|
|
||||||
override val scopeProvider: KtScopeProvider = KtFirScopeProvider(token, firSymbolBuilder, firSession)
|
override val scopeProvider: KtScopeProvider = KtFirScopeProvider(token, firSymbolBuilder, firSession, firResolveState)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
assertIsValid()
|
assertIsValid()
|
||||||
@@ -129,6 +132,13 @@ constructor(
|
|||||||
resolveCall(firCall, call)
|
resolveCall(firCall, call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun analyzeInContext(): KtAnalysisSession {
|
||||||
|
return KtFirAnalysisSession(
|
||||||
|
element,
|
||||||
|
LowLevelFirApiFacade.getResolveStateForCompletion(element, firResolveState as FirModuleResolveStateImpl)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun resolveCall(call: KtCallExpression): CallInfo? = withValidityAssertion {
|
override fun resolveCall(call: KtCallExpression): CallInfo? = withValidityAssertion {
|
||||||
val firCall = when (val fir = call.getOrBuildFir(firResolveState)) {
|
val firCall = when (val fir = call.getOrBuildFir(firResolveState)) {
|
||||||
is FirFunctionCall -> fir
|
is FirFunctionCall -> fir
|
||||||
|
|||||||
+2
-1
@@ -11,6 +11,7 @@ import com.intellij.psi.util.CachedValuesManager
|
|||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProvider
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProvider
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
@@ -28,6 +29,6 @@ class KtFirAnalysisSessionProvider(project: Project) : KtAnalysisSessionProvider
|
|||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
override fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession =
|
override fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession =
|
||||||
analysisSessionByModuleInfoCache.value.getOrPut(contextElement.getModuleInfo()) {
|
analysisSessionByModuleInfoCache.value.getOrPut(contextElement.getModuleInfo()) {
|
||||||
KtFirAnalysisSession(contextElement)
|
KtFirAnalysisSession(contextElement, LowLevelFirApiFacade.getResolveStateFor(contextElement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+55
-1
@@ -6,22 +6,37 @@
|
|||||||
package org.jetbrains.kotlin.idea.frontend.api.fir.scopes
|
package org.jetbrains.kotlin.idea.frontend.api.fir.scopes
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.scope
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
|
import org.jetbrains.kotlin.idea.fir.getOrBuildFirOfType
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
|
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwner
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwnerByValidityToken
|
import org.jetbrains.kotlin.idea.frontend.api.ValidityOwnerByValidityToken
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
|
import org.jetbrains.kotlin.idea.frontend.api.fir.KtSymbolByFirBuilder
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirPackageSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirPackageSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
|
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.scopes.*
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.*
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
||||||
|
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class KtFirScopeProvider(
|
internal class KtFirScopeProvider(
|
||||||
override val token: ValidityOwner,
|
override val token: ValidityOwner,
|
||||||
private val builder: KtSymbolByFirBuilder,
|
private val builder: KtSymbolByFirBuilder,
|
||||||
session: FirSession
|
session: FirSession,
|
||||||
|
val firResolveState: FirModuleResolveState
|
||||||
) : KtScopeProvider(), ValidityOwnerByValidityToken {
|
) : KtScopeProvider(), ValidityOwnerByValidityToken {
|
||||||
private val session by weakRef(session)
|
private val session by weakRef(session)
|
||||||
|
|
||||||
@@ -53,4 +68,43 @@ internal class KtFirScopeProvider(
|
|||||||
override fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope = withValidityAssertion {
|
override fun getCompositeScope(subScopes: List<KtScope>): KtCompositeScope = withValidityAssertion {
|
||||||
KtFirCompositeScope(subScopes, token)
|
KtFirCompositeScope(subScopes, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getScopeForType(type: KtType): KtScope? {
|
||||||
|
check(type is KtFirType) { "KtFirScopePriovider can only work with KtFirType, but ${type::class} was provided" }
|
||||||
|
|
||||||
|
val firTypeScope = type.coneType.scope(session, ScopeSession()) ?: return null
|
||||||
|
return convertToKtScope(firTypeScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getScopeContextForPosition(originalFile: KtFile, positionInFakeFile: KtElement): KtScopeContext = withValidityAssertion {
|
||||||
|
val originalFirFile = originalFile.getOrBuildFirOfType<FirFile>(firResolveState)
|
||||||
|
val fakeEnclosingFunction = positionInFakeFile.getNonStrictParentOfType<KtNamedFunction>()
|
||||||
|
?: error("Cannot find enclosing function for ${positionInFakeFile.getElementTextInContext()}")
|
||||||
|
|
||||||
|
val completionContext = LowLevelFirApiFacade.buildCompletionContextForFunction(
|
||||||
|
originalFirFile,
|
||||||
|
fakeEnclosingFunction,
|
||||||
|
state = firResolveState
|
||||||
|
)
|
||||||
|
|
||||||
|
val towerDataContext = completionContext.getTowerDataContext(positionInFakeFile)
|
||||||
|
|
||||||
|
val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }
|
||||||
|
val implicitReceiversTypes = implicitReceivers.map { builder.buildKtType(it.type) }
|
||||||
|
|
||||||
|
val implicitReceiverScopes = implicitReceivers.mapNotNull { it.implicitScope }
|
||||||
|
val nonLocalScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }
|
||||||
|
val firLocalScopes = towerDataContext.localScopes
|
||||||
|
|
||||||
|
val allKtScopes = (implicitReceiverScopes + nonLocalScopes + firLocalScopes).map { convertToKtScope(it) }
|
||||||
|
|
||||||
|
KtScopeContext(getCompositeScope(allKtScopes), implicitReceiversTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertToKtScope(firScope: FirScope): KtScope = KtFirDelegatingScopeImpl(firScope, builder, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KtFirDelegatingScopeImpl(firScope: FirScope, builder: KtSymbolByFirBuilder, override val token: ValidityOwner) :
|
||||||
|
KtFirDelegatingScope(builder), ValidityOwnerByValidityToken {
|
||||||
|
override val firScope: FirScope by weakRef(firScope)
|
||||||
}
|
}
|
||||||
+2
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api
|
|||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import org.jetbrains.kotlin.idea.executeOnPooledThreadInReadAction
|
import org.jetbrains.kotlin.idea.executeOnPooledThreadInReadAction
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.DebugSymbolRenderer
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.DebugSymbolRenderer
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
||||||
@@ -36,7 +37,7 @@ abstract class AbstractSymbolByFqNameTest : KotlinLightCodeInsightFixtureTestCas
|
|||||||
val symbols = createSymbols(symbolData, this)
|
val symbols = createSymbols(symbolData, this)
|
||||||
symbols.map { DebugSymbolRenderer.render(it) }
|
symbols.map { DebugSymbolRenderer.render(it) }
|
||||||
}
|
}
|
||||||
val analysisSession = KtFirAnalysisSession(fakeKtFile)
|
val analysisSession = KtFirAnalysisSession(fakeKtFile, LowLevelFirApiFacade.getResolveStateFor(fakeKtFile))
|
||||||
val symbols = createSymbols(symbolData, analysisSession)
|
val symbols = createSymbols(symbolData, analysisSession)
|
||||||
symbols.map { DebugSymbolRenderer.render(it) }
|
symbols.map { DebugSymbolRenderer.render(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user