diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirPropertyBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirPropertyBuilder.kt index e84ca26a532..63cf35ffcf3 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirPropertyBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirPropertyBuilder.kt @@ -90,3 +90,31 @@ inline fun buildProperty(init: FirPropertyBuilder.() -> Unit): FirProperty { } 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() +} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt index 4b2be9bcb0a..a3b6ffc78bf 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt @@ -172,6 +172,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator(FirTree parents += typeParametersOwnerBuilder defaultNull("getter", "setter", "containerSource", "delegateFieldSymbol") default("resolvePhase", "FirResolvePhase.RAW_FIR") + withCopy() } builder(typeOperatorCall) { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt index ba491e56a3e..6859ab64cc0 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirDeclaration 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.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo @@ -46,8 +45,8 @@ abstract class FirModuleResolveState { abstract fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D // todo temporary, used only in completion - internal abstract fun lazyResolveFunctionForCompletion( - firFunction: FirFunction<*>, + internal abstract fun lazyResolveDeclarationForCompletion( + firFunction: FirDeclaration, containerFirFile: FirFile, firIdeProvider: FirIdeProvider, toPhase: FirResolvePhase, @@ -91,8 +90,8 @@ internal open class FirModuleResolveStateImpl( override fun getCachedMappingForCompletion(element: KtElement): FirElement? = psiToFirCache.getCachedMapping(element) - override fun lazyResolveFunctionForCompletion( - firFunction: FirFunction<*>, + override fun lazyResolveDeclarationForCompletion( + firFunction: FirDeclaration, containerFirFile: FirFile, firIdeProvider: FirIdeProvider, toPhase: FirResolvePhase, diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt index 44a9ad50805..c15e5ac0ba9 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirDeclaration 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.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector @@ -55,14 +54,14 @@ internal class FirModuleResolveStateForCompletion( return originalState.resolvedFirToPhase(declaration, toPhase) } - override fun lazyResolveFunctionForCompletion( - firFunction: FirFunction<*>, + override fun lazyResolveDeclarationForCompletion( + firFunction: FirDeclaration, containerFirFile: FirFile, firIdeProvider: FirIdeProvider, toPhase: FirResolvePhase, towerDataContextCollector: FirTowerDataContextCollector ) { - originalState.lazyResolveFunctionForCompletion(firFunction, containerFirFile, firIdeProvider, toPhase, towerDataContextCollector) + originalState.lazyResolveDeclarationForCompletion(firFunction, containerFirFile, firIdeProvider, toPhase, towerDataContextCollector) } override fun getDiagnostics(element: KtElement): List { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/LowLevelFirApiFacade.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/LowLevelFirApiFacade.kt index 303d4035f63..4b43d62597e 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/LowLevelFirApiFacade.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/LowLevelFirApiFacade.kt @@ -10,9 +10,11 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.FirFile 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.FirSimpleFunction 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.resolve.FirTowerDataContext 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.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.util.getElementTextInContext +import org.jetbrains.kotlin.psi.KtProperty object LowLevelFirApiFacade { fun getResolveStateFor(element: KtElement): FirModuleResolveState = @@ -82,7 +85,40 @@ object LowLevelFirApiFacade { } 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) } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/providers/FirIdeProvider.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/providers/FirIdeProvider.kt index e70c6f32d40..89cf8cc29c9 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/providers/FirIdeProvider.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/providers/FirIdeProvider.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtProperty @ThreadSafeMutableState internal class FirIdeProvider( @@ -103,6 +104,10 @@ internal class FirIdeProvider( return RawFirBuilder(session, kotlinScopeProvider, stubMode = false).buildFunctionWithBody(ktNamedFunction) } + fun buildPropertyWithBody(ktNamedFunction: KtProperty): FirProperty { + return RawFirBuilder(session, kotlinScopeProvider, stubMode = false).buildPropertyWithBody(ktNamedFunction) + } + @FirProviderInternals override fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass) { 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 2398a1599ff..11901bdca61 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 @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components 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.FirResolvePhase 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.KtFile import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import java.util.* @@ -108,18 +109,7 @@ internal class KtFirScopeProvider( originalFile: KtFile, positionInFakeFile: KtElement ): KtScopeContext = withValidityAssertion { - val originalFirFile = originalFile.getOrBuildFirOfType(firResolveState) - val fakeEnclosingFunction = positionInFakeFile.getNonStrictParentOfType() - ?: 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 completionContext = buildCompletionContextForEnclosingDeclaration(originalFile, 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(firResolveState) + val fakeEnclosingFunction = positionInFakeFile.getNonStrictParentOfType() + + if (fakeEnclosingFunction != null) { + val originalEnclosingFunction = originalFile.findDeclarationOfTypeAt(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().firstOrNull { !it.isLocal } + if (fakeEnclosingProperty != null) { + val originalEnclosingProperty = originalFile.findDeclarationOfTypeAt(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 KtFile.findDeclarationOfTypeAt(offset: Int): T? = findElementAt(offset) - ?.getNonStrictParentOfType() + ?.getNonStrictParentOfType() ?.takeIf { it.textOffset == offset } private fun convertToKtScope(firScope: FirScope): KtScope {