FIR IDE: Add building completion context for properties
This commit is contained in:
+28
@@ -90,3 +90,31 @@ inline fun buildProperty(init: FirPropertyBuilder.() -> Unit): FirProperty {
|
|||||||
}
|
}
|
||||||
return FirPropertyBuilder().apply(init).build()
|
return FirPropertyBuilder().apply(init).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
inline fun buildPropertyCopy(original: FirProperty, init: FirPropertyBuilder.() -> Unit): FirProperty {
|
||||||
|
contract {
|
||||||
|
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
val copyBuilder = FirPropertyBuilder()
|
||||||
|
copyBuilder.source = original.source
|
||||||
|
copyBuilder.session = original.session
|
||||||
|
copyBuilder.resolvePhase = original.resolvePhase
|
||||||
|
copyBuilder.origin = original.origin
|
||||||
|
copyBuilder.returnTypeRef = original.returnTypeRef
|
||||||
|
copyBuilder.receiverTypeRef = original.receiverTypeRef
|
||||||
|
copyBuilder.name = original.name
|
||||||
|
copyBuilder.initializer = original.initializer
|
||||||
|
copyBuilder.delegate = original.delegate
|
||||||
|
copyBuilder.delegateFieldSymbol = original.delegateFieldSymbol
|
||||||
|
copyBuilder.isVar = original.isVar
|
||||||
|
copyBuilder.getter = original.getter
|
||||||
|
copyBuilder.setter = original.setter
|
||||||
|
copyBuilder.annotations.addAll(original.annotations)
|
||||||
|
copyBuilder.typeParameters.addAll(original.typeParameters)
|
||||||
|
copyBuilder.containerSource = original.containerSource
|
||||||
|
copyBuilder.symbol = original.symbol
|
||||||
|
copyBuilder.isLocal = original.isLocal
|
||||||
|
copyBuilder.status = original.status
|
||||||
|
return copyBuilder.apply(init).build()
|
||||||
|
}
|
||||||
|
|||||||
+1
@@ -172,6 +172,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
|
|||||||
parents += typeParametersOwnerBuilder
|
parents += typeParametersOwnerBuilder
|
||||||
defaultNull("getter", "setter", "containerSource", "delegateFieldSymbol")
|
defaultNull("getter", "setter", "containerSource", "delegateFieldSymbol")
|
||||||
default("resolvePhase", "FirResolvePhase.RAW_FIR")
|
default("resolvePhase", "FirResolvePhase.RAW_FIR")
|
||||||
|
withCopy()
|
||||||
}
|
}
|
||||||
|
|
||||||
builder(typeOperatorCall) {
|
builder(typeOperatorCall) {
|
||||||
|
|||||||
+4
-5
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirElement
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||||
@@ -46,8 +45,8 @@ abstract class FirModuleResolveState {
|
|||||||
abstract fun <D : FirDeclaration> resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D
|
abstract fun <D : FirDeclaration> resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D
|
||||||
|
|
||||||
// todo temporary, used only in completion
|
// todo temporary, used only in completion
|
||||||
internal abstract fun lazyResolveFunctionForCompletion(
|
internal abstract fun lazyResolveDeclarationForCompletion(
|
||||||
firFunction: FirFunction<*>,
|
firFunction: FirDeclaration,
|
||||||
containerFirFile: FirFile,
|
containerFirFile: FirFile,
|
||||||
firIdeProvider: FirIdeProvider,
|
firIdeProvider: FirIdeProvider,
|
||||||
toPhase: FirResolvePhase,
|
toPhase: FirResolvePhase,
|
||||||
@@ -91,8 +90,8 @@ internal open class FirModuleResolveStateImpl(
|
|||||||
override fun getCachedMappingForCompletion(element: KtElement): FirElement? =
|
override fun getCachedMappingForCompletion(element: KtElement): FirElement? =
|
||||||
psiToFirCache.getCachedMapping(element)
|
psiToFirCache.getCachedMapping(element)
|
||||||
|
|
||||||
override fun lazyResolveFunctionForCompletion(
|
override fun lazyResolveDeclarationForCompletion(
|
||||||
firFunction: FirFunction<*>,
|
firFunction: FirDeclaration,
|
||||||
containerFirFile: FirFile,
|
containerFirFile: FirFile,
|
||||||
firIdeProvider: FirIdeProvider,
|
firIdeProvider: FirIdeProvider,
|
||||||
toPhase: FirResolvePhase,
|
toPhase: FirResolvePhase,
|
||||||
|
|||||||
+3
-4
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirElement
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
|
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
|
||||||
@@ -55,14 +54,14 @@ internal class FirModuleResolveStateForCompletion(
|
|||||||
return originalState.resolvedFirToPhase(declaration, toPhase)
|
return originalState.resolvedFirToPhase(declaration, toPhase)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lazyResolveFunctionForCompletion(
|
override fun lazyResolveDeclarationForCompletion(
|
||||||
firFunction: FirFunction<*>,
|
firFunction: FirDeclaration,
|
||||||
containerFirFile: FirFile,
|
containerFirFile: FirFile,
|
||||||
firIdeProvider: FirIdeProvider,
|
firIdeProvider: FirIdeProvider,
|
||||||
toPhase: FirResolvePhase,
|
toPhase: FirResolvePhase,
|
||||||
towerDataContextCollector: FirTowerDataContextCollector
|
towerDataContextCollector: FirTowerDataContextCollector
|
||||||
) {
|
) {
|
||||||
originalState.lazyResolveFunctionForCompletion(firFunction, containerFirFile, firIdeProvider, toPhase, towerDataContextCollector)
|
originalState.lazyResolveDeclarationForCompletion(firFunction, containerFirFile, firIdeProvider, toPhase, towerDataContextCollector)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDiagnostics(element: KtElement): List<Diagnostic> {
|
override fun getDiagnostics(element: KtElement): List<Diagnostic> {
|
||||||
|
|||||||
+37
-1
@@ -10,9 +10,11 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
|||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
|
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
|
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
|
||||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
|
||||||
@@ -22,6 +24,7 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
|
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
|
||||||
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
|
||||||
object LowLevelFirApiFacade {
|
object LowLevelFirApiFacade {
|
||||||
fun getResolveStateFor(element: KtElement): FirModuleResolveState =
|
fun getResolveStateFor(element: KtElement): FirModuleResolveState =
|
||||||
@@ -82,7 +85,40 @@ object LowLevelFirApiFacade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val function = frankensteinFunction.apply {
|
val function = frankensteinFunction.apply {
|
||||||
state.lazyResolveFunctionForCompletion(this, firFile, firIdeProvider, phase, contextCollector)
|
state.lazyResolveDeclarationForCompletion(this, firFile, firIdeProvider, phase, contextCollector)
|
||||||
|
state.recordPsiToFirMappingsForCompletionFrom(this, firFile, element.containingKtFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
return FirCompletionContext(
|
||||||
|
function.session,
|
||||||
|
contextCollector,
|
||||||
|
state
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildCompletionContextForProperty(
|
||||||
|
firFile: FirFile,
|
||||||
|
element: KtProperty,
|
||||||
|
originalElement: KtProperty,
|
||||||
|
state: FirModuleResolveState,
|
||||||
|
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
|
||||||
|
): FirCompletionContext {
|
||||||
|
val firIdeProvider = firFile.session.firIdeProvider
|
||||||
|
val originalProperty = state.getOrBuildFirFor(originalElement, phase) as FirProperty
|
||||||
|
val builtProperty = firIdeProvider.buildPropertyWithBody(element)
|
||||||
|
val contextCollector = FirTowerDataContextCollector()
|
||||||
|
|
||||||
|
val frankensteinProperty = buildPropertyCopy(originalProperty) {
|
||||||
|
symbol = builtProperty.symbol
|
||||||
|
getter = builtProperty.getter
|
||||||
|
setter = builtProperty.setter
|
||||||
|
resolvePhase = minOf(originalProperty.resolvePhase, FirResolvePhase.DECLARATIONS)
|
||||||
|
source = builtProperty.source
|
||||||
|
session = state.firIdeSourcesSession
|
||||||
|
}
|
||||||
|
|
||||||
|
val function = frankensteinProperty.apply {
|
||||||
|
state.lazyResolveDeclarationForCompletion(this, firFile, firIdeProvider, phase, contextCollector)
|
||||||
state.recordPsiToFirMappingsForCompletionFrom(this, firFile, element.containingKtFile)
|
state.recordPsiToFirMappingsForCompletionFrom(this, firFile, element.containingKtFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
|
||||||
@ThreadSafeMutableState
|
@ThreadSafeMutableState
|
||||||
internal class FirIdeProvider(
|
internal class FirIdeProvider(
|
||||||
@@ -103,6 +104,10 @@ internal class FirIdeProvider(
|
|||||||
return RawFirBuilder(session, kotlinScopeProvider, stubMode = false).buildFunctionWithBody(ktNamedFunction)
|
return RawFirBuilder(session, kotlinScopeProvider, stubMode = false).buildFunctionWithBody(ktNamedFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildPropertyWithBody(ktNamedFunction: KtProperty): FirProperty {
|
||||||
|
return RawFirBuilder(session, kotlinScopeProvider, stubMode = false).buildPropertyWithBody(ktNamedFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@FirProviderInternals
|
@FirProviderInternals
|
||||||
override fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass) {
|
override fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass) {
|
||||||
|
|||||||
+40
-15
@@ -6,7 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.idea.frontend.api.fir.components
|
package org.jetbrains.kotlin.idea.frontend.api.fir.components
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.util.parentsOfType
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
|||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -108,18 +109,7 @@ internal class KtFirScopeProvider(
|
|||||||
originalFile: KtFile,
|
originalFile: KtFile,
|
||||||
positionInFakeFile: KtElement
|
positionInFakeFile: KtElement
|
||||||
): KtScopeContext = withValidityAssertion {
|
): KtScopeContext = withValidityAssertion {
|
||||||
val originalFirFile = originalFile.getOrBuildFirOfType<FirFile>(firResolveState)
|
val completionContext = buildCompletionContextForEnclosingDeclaration(originalFile, positionInFakeFile)
|
||||||
val fakeEnclosingFunction = positionInFakeFile.getNonStrictParentOfType<KtNamedFunction>()
|
|
||||||
?: error("Cannot find enclosing function for ${positionInFakeFile.getElementTextInContext()}")
|
|
||||||
val originalEnclosingFunction = originalFile.findFunctionDeclarationAt(fakeEnclosingFunction.textOffset)
|
|
||||||
?: error("Cannot find original function matching to ${fakeEnclosingFunction.getElementTextInContext()} in $originalFile")
|
|
||||||
|
|
||||||
val completionContext = LowLevelFirApiFacade.buildCompletionContextForFunction(
|
|
||||||
originalFirFile,
|
|
||||||
fakeEnclosingFunction,
|
|
||||||
originalEnclosingFunction,
|
|
||||||
state = firResolveState
|
|
||||||
)
|
|
||||||
|
|
||||||
val towerDataContext = completionContext.getTowerDataContext(positionInFakeFile)
|
val towerDataContext = completionContext.getTowerDataContext(positionInFakeFile)
|
||||||
|
|
||||||
@@ -143,9 +133,44 @@ internal class KtFirScopeProvider(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtFile.findFunctionDeclarationAt(offset: Int): KtNamedFunction? =
|
private fun buildCompletionContextForEnclosingDeclaration(
|
||||||
|
originalFile: KtFile,
|
||||||
|
positionInFakeFile: KtElement
|
||||||
|
): LowLevelFirApiFacade.FirCompletionContext {
|
||||||
|
val originalFirFile = originalFile.getOrBuildFirOfType<FirFile>(firResolveState)
|
||||||
|
val fakeEnclosingFunction = positionInFakeFile.getNonStrictParentOfType<KtNamedFunction>()
|
||||||
|
|
||||||
|
if (fakeEnclosingFunction != null) {
|
||||||
|
val originalEnclosingFunction = originalFile.findDeclarationOfTypeAt<KtNamedFunction>(fakeEnclosingFunction.textOffset)
|
||||||
|
?: error("Cannot find original function matching to ${fakeEnclosingFunction.getElementTextInContext()} in $originalFile")
|
||||||
|
|
||||||
|
return LowLevelFirApiFacade.buildCompletionContextForFunction(
|
||||||
|
originalFirFile,
|
||||||
|
fakeEnclosingFunction,
|
||||||
|
originalEnclosingFunction,
|
||||||
|
state = firResolveState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val fakeEnclosingProperty = positionInFakeFile.parentsOfType<KtProperty>().firstOrNull { !it.isLocal }
|
||||||
|
if (fakeEnclosingProperty != null) {
|
||||||
|
val originalEnclosingProperty = originalFile.findDeclarationOfTypeAt<KtProperty>(fakeEnclosingProperty.textOffset)
|
||||||
|
?: error("Cannot find original property matching to ${fakeEnclosingProperty.getElementTextInContext()} in $originalFile")
|
||||||
|
|
||||||
|
return LowLevelFirApiFacade.buildCompletionContextForProperty(
|
||||||
|
originalFirFile,
|
||||||
|
fakeEnclosingProperty,
|
||||||
|
originalEnclosingProperty,
|
||||||
|
state = firResolveState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun<reified T: KtElement> KtFile.findDeclarationOfTypeAt(offset: Int): T? =
|
||||||
findElementAt(offset)
|
findElementAt(offset)
|
||||||
?.getNonStrictParentOfType<KtNamedFunction>()
|
?.getNonStrictParentOfType<T>()
|
||||||
?.takeIf { it.textOffset == offset }
|
?.takeIf { it.textOffset == offset }
|
||||||
|
|
||||||
private fun convertToKtScope(firScope: FirScope): KtScope {
|
private fun convertToKtScope(firScope: FirScope): KtScope {
|
||||||
|
|||||||
Reference in New Issue
Block a user