diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt index ee2b4a98665..4b00e788862 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache +import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.KtToFirMapping import org.jetbrains.kotlin.idea.fir.low.level.api.util.containingKtFileIfAny import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile import org.jetbrains.kotlin.psi.KtDeclaration @@ -29,7 +30,7 @@ import org.jetbrains.kotlin.psi.KtLambdaExpression internal class FirModuleResolveStateDepended( private val originalState: FirModuleResolveStateImpl, val towerProviderBuiltUponElement: FirTowerContextProvider, - private val ktToFirMapping: Map, + private val ktToFirMapping: KtToFirMapping?, ) : FirModuleResolveState() { override val project: Project get() = originalState.project @@ -43,18 +44,14 @@ internal class FirModuleResolveStateDepended( override fun getOrBuildFirFor(element: KtElement): FirElement { val psi = originalState.elementBuilder.getPsiAsFirElementSource(element) - //TODO It return invalid elements for elements with invalid code, but try to return the most closest ones - var currentElement: PsiElement = psi - while (currentElement !is KtFile) { - ktToFirMapping[currentElement]?.let { return it } - currentElement = currentElement.parent - } + ktToFirMapping?.getFirOfClosestParent(psi, this)?.let { return it } return originalState.elementBuilder.getOrBuildFirFor( - element, - originalState.firFileBuilder, - originalState.rootModuleSession.cache, - fileStructureCache, + element = element, + firFileBuilder = originalState.firFileBuilder, + moduleFileCache = originalState.rootModuleSession.cache, + fileStructureCache = fileStructureCache, + state = this, ) } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt index 2acdbd5955c..e1daee5bd9c 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.util.FirElementFinder import org.jetbrains.kotlin.idea.fir.low.level.api.util.findSourceNonLocalFirDeclaration import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType internal class FirModuleResolveStateImpl( override val project: Project, @@ -43,6 +44,7 @@ internal class FirModuleResolveStateImpl( ) : FirModuleResolveState() { override val rootModuleSession: FirIdeSourcesSession get() = sessionProvider.rootModuleSession + /** * WARNING! This object contains scopes for all statements and declarations that were ever resolved. * It can grow unbounded if you never edit the files in the opened project. @@ -57,7 +59,7 @@ internal class FirModuleResolveStateImpl( sessionProvider.getSession(moduleInfo)!! override fun getOrBuildFirFor(element: KtElement): FirElement = - elementBuilder.getOrBuildFirFor(element, firFileBuilder, rootModuleSession.cache, fileStructureCache) + elementBuilder.getOrBuildFirFor(element, firFileBuilder, rootModuleSession.cache, fileStructureCache, this) override fun getOrBuildFirFile(ktFile: KtFile): FirFile = firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache, lazyBodiesMode = false) diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt index 332c3869205..1bcf3b0a2c1 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt @@ -10,15 +10,13 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession import org.jetbrains.kotlin.idea.util.getElementTextInContext -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtLambdaExpression +import org.jetbrains.kotlin.psi.* abstract class FirModuleResolveState { abstract val project: Project diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt index 81a03e7702c..eb7f8861650 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForResolveOnAir.kt @@ -10,15 +10,25 @@ import com.intellij.psi.util.parentOfType import com.intellij.psi.util.parentsOfType import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.asTowerDataElement +import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector +import org.jetbrains.kotlin.fir.resolve.typeResolver +import org.jetbrains.kotlin.fir.scopes.FirCompositeScope import org.jetbrains.kotlin.fir.scopes.createImportingScopes +import org.jetbrains.kotlin.fir.toFirPsiSourceElement +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateDepended @@ -27,8 +37,10 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FileTowerProv import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextAllElementsCollector import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FirElementsRecorder +import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.KtToFirMapping import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.RawFirReplacement import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.buildFileFirAnnotation +import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.buildFirUserTypeRef import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration @@ -129,7 +141,7 @@ object LowLevelFirApiFacadeForResolveOnAir { checkPCE = false ) - val importingScopes = createImportingScopes(firFile, firFile.declarationSiteSession, ScopeSession(), useCaching = false) + val importingScopes = createImportingScopes(firFile, firFile.moduleData.session, ScopeSession(), useCaching = false) val fileScopeElements = importingScopes.map { it.asTowerDataElement(isLocal = false) } return FirTowerDataContext().addNonLocalTowerDataElements(fileScopeElements) } @@ -147,7 +159,7 @@ object LowLevelFirApiFacadeForResolveOnAir { ?: return FirModuleResolveStateDepended( originalState, FileTowerProvider(elementToAnalyze.containingKtFile, onAirGetTowerContextForFile(originalState, originalKtFile)), - emptyMap() + ktToFirMapping = null ) @@ -167,8 +179,8 @@ object LowLevelFirApiFacadeForResolveOnAir { collector = collector, ) - val recordedMap = FirElementsRecorder.recordElementsFrom(copiedFirDeclaration, FirElementsRecorder()) - return FirModuleResolveStateDepended(originalState, collector, recordedMap) + val mapping = KtToFirMapping(copiedFirDeclaration, FirElementsRecorder()) + return FirModuleResolveStateDepended(originalState, collector, mapping) } private fun tryResolveAsFileAnnotation( @@ -176,10 +188,11 @@ object LowLevelFirApiFacadeForResolveOnAir { state: FirModuleResolveStateImpl, replacement: RawFirReplacement, firFile: FirFile, + collector: FirTowerDataContextCollector? = null, ): FirAnnotationCall { val annotationCall = buildFileFirAnnotation( - firFile.declarationSiteSession, - firFile.declarationSiteSession.firIdeProvider.kotlinScopeProvider, + firFile.moduleData.session, + firFile.moduleData.session.firIdeProvider.kotlinScopeProvider, annotationEntry, replacement ) @@ -187,7 +200,8 @@ object LowLevelFirApiFacadeForResolveOnAir { firFile, listOf(annotationCall), state.rootModuleSession.cache, - ScopeSession() + ScopeSession(), + collector ) return annotationCall @@ -211,7 +225,8 @@ object LowLevelFirApiFacadeForResolveOnAir { annotationEntry = annotationCall, state = state, replacement = replacement, - firFile = originalFirFile + firFile = originalFirFile, + collector = collector, ) } else { error("Cannot find enclosing declaration for ${replacement.from.getElementTextInContext()}") @@ -228,7 +243,7 @@ object LowLevelFirApiFacadeForResolveOnAir { firDeclarationToResolve = copiedFirDeclaration, moduleFileCache = state.rootModuleSession.cache, containerFirFile = originalFirFile, - provider = originalFirFile.declarationSiteSession.firIdeProvider, + provider = originalFirFile.moduleData.session.firIdeProvider, toPhase = FirResolvePhase.BODY_RESOLVE, checkPCE = true, isOnAirResolve = isOnAirResolve, @@ -238,6 +253,28 @@ object LowLevelFirApiFacadeForResolveOnAir { return copiedFirDeclaration } + fun onAirResolveTypeInPlace( + place: KtElement, + typeReference: KtTypeReference, + state: FirModuleResolveState + ): FirResolvedTypeRef { + val context = state.getTowerContextProvider().getClosestAvailableParentContext(place) + ?: error("TowerContext not found for ${place.getElementTextInContext()}") + + val session = state.rootModuleSession + val firTypeReference = buildFirUserTypeRef( + typeReference = typeReference, + session = session, + baseScopeProvider = session.firIdeProvider.kotlinScopeProvider + ) + + return FirTypeResolveTransformer( + session = session, + scopeSession = ScopeSession(), + initialScopes = context.towerDataElements.asReversed().mapNotNull { it.scope } + ).transformTypeRef(firTypeReference, null) + } + private class TowerProviderForElementForState(private val state: FirModuleResolveState) : FirTowerContextProvider { override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? { return if (ktElement.isPhysical) { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt index d7e9e933a16..0a2f2e090bb 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt @@ -12,10 +12,12 @@ import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.ThreadSafe +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureElement +import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.KtToFirMapping import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.util.isNonAnonymousClassOrObject import org.jetbrains.kotlin.idea.util.getElementTextInContext @@ -51,9 +53,10 @@ internal class FirElementBuilder { firFileBuilder: FirFileBuilder, moduleFileCache: ModuleFileCache, fileStructureCache: FileStructureCache, + state: FirModuleResolveState, ): FirElement = when (element) { is KtFile -> getOrBuildFirForKtFile(element, firFileBuilder, moduleFileCache) - else -> getOrBuildFirForNonKtFileElement(element, fileStructureCache, moduleFileCache) + else -> getOrBuildFirForNonKtFileElement(element, fileStructureCache, moduleFileCache, state) } private fun getOrBuildFirForKtFile(ktFile: KtFile, firFileBuilder: FirFileBuilder, moduleFileCache: ModuleFileCache): FirFile = @@ -68,16 +71,17 @@ internal class FirElementBuilder { private fun getOrBuildFirForNonKtFileElement( element: KtElement, fileStructureCache: FileStructureCache, - moduleFileCache: ModuleFileCache + moduleFileCache: ModuleFileCache, + state: FirModuleResolveState, ): FirElement { require(element !is KtFile) - val fileStructure = fileStructureCache.getFileStructure(element.containingKtFile, moduleFileCache) + val firFile = element.containingKtFile + val fileStructure = fileStructureCache.getFileStructure(firFile, moduleFileCache) val mappings = fileStructure.getStructureElementFor(element).mappings val psi = getPsiAsFirElementSource(element) - mappings[psi]?.let { return it } - return psi.getFirOfClosestParent(mappings)?.second - ?: error("FirElement is not found for:\n${element.getElementTextInContext()}") + return mappings.getFirOfClosestParent(psi, state) + ?: state.getOrBuildFirFile(firFile) } @TestOnly @@ -91,20 +95,6 @@ internal class FirElementBuilder { } } -private fun KtElement.getFirOfClosestParent(cache: Map): Pair? { - var current: PsiElement? = this - while (current is KtElement) { - val mappedFir = cache[current] - if (mappedFir != null) { - return current to mappedFir - } - current = current.parent - } - - return null -} - - // TODO: simplify internal inline fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDeclaration) -> Boolean = { true }): KtNamedDeclaration? { var container: PsiElement? = this diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt index b3ffa51c351..4fefaeda9bd 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt @@ -5,13 +5,17 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.file.structure +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.idea.fir.low.level.api.api.DeclarationCopyBuilder +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState +import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForResolveOnAir import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileDiagnosticRetriever import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever @@ -20,13 +24,49 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider import org.jetbrains.kotlin.psi.* +import java.util.concurrent.ConcurrentHashMap internal sealed class FileStructureElement(val firFile: FirFile, protected val lockProvider: LockProvider) { abstract val psi: KtAnnotated - abstract val mappings: Map + abstract val mappings: KtToFirMapping abstract val diagnostics: FileStructureElementDiagnostics } +internal class KtToFirMapping(firElement: FirElement, recorder: FirElementsRecorder) { + + private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder) + + private val userTypeMapping = ConcurrentHashMap() + fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? { + mapping[ktElement]?.let { return it } + + val userType = when (ktElement) { + is KtUserType -> ktElement + is KtNameReferenceExpression -> ktElement as? KtUserType + else -> null + } ?: return null + + //This is for not inner KtUserType + if (userType.parent is KtTypeReference) return null + + return userTypeMapping.getOrPut(userType) { + val typeReference = KtPsiFactory(ktElement.project).createType(userType) + LowLevelFirApiFacadeForResolveOnAir.onAirResolveTypeInPlace(ktElement, typeReference, state) + } + } + + fun getFirOfClosestParent(element: KtElement, state: FirModuleResolveState): FirElement? { + var current: PsiElement? = element + while (current != null && current !is KtFile) { + if (current is KtElement) { + getElement(current, state)?.let { return it } + } + current = current.parent + } + return null + } +} + internal sealed class ReanalyzableStructureElement>( firFile: FirFile, val firSymbol: S, @@ -66,8 +106,7 @@ internal class ReanalyzableFunctionStructureElement( override val timestamp: Long, lockProvider: LockProvider, ) : ReanalyzableStructureElement>(firFile, firSymbol, lockProvider) { - override val mappings: Map = - FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) + override val mappings = KtToFirMapping(firSymbol.fir, recorder) override fun reanalyze( newKtDeclaration: KtNamedFunction, @@ -106,8 +145,7 @@ internal class ReanalyzablePropertyStructureElement( override val timestamp: Long, lockProvider: LockProvider, ) : ReanalyzableStructureElement(firFile, firSymbol, lockProvider) { - override val mappings: Map = - FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) + override val mappings = KtToFirMapping(firSymbol.fir, recorder) override fun reanalyze( newKtDeclaration: KtProperty, @@ -145,8 +183,7 @@ internal class NonReanalyzableDeclarationStructureElement( override val psi: KtDeclaration, lockProvider: LockProvider, ) : FileStructureElement(firFile, lockProvider) { - override val mappings: Map = - FirElementsRecorder.recordElementsFrom(fir, recorder) + override val mappings = KtToFirMapping(fir, recorder) override val diagnostics = FileStructureElementDiagnostics(firFile, lockProvider, SingleNonLocalDeclarationDiagnosticRetriever(fir)) @@ -176,8 +213,7 @@ internal class RootStructureElement( override val psi: KtFile, lockProvider: LockProvider, ) : FileStructureElement(firFile, lockProvider) { - override val mappings: Map = - FirElementsRecorder.recordElementsFrom(firFile, recorder) + override val mappings = KtToFirMapping(firFile, recorder) override val diagnostics = FileStructureElementDiagnostics(firFile, lockProvider, FileDiagnosticRetriever) diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FirElementsRecorder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FirElementsRecorder.kt index 504f88de8f5..6ba32fd5d00 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FirElementsRecorder.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FirElementsRecorder.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.file.structure import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.references.* diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt index c63f85c19b3..46ac0e1ae20 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt @@ -40,6 +40,7 @@ internal class FirLazyDeclarationResolver( annotations: List, moduleFileCache: ModuleFileCache, scopeSession: ScopeSession, + collector: FirTowerDataContextCollector? = null, ) { lazyResolveDeclaration( declaration = firFile, @@ -49,7 +50,7 @@ internal class FirLazyDeclarationResolver( reresolveFile = false ) firFileBuilder.runCustomResolveUnderLock(firFile, moduleFileCache) { - resolveFileAnnotationsWithoutLock(firFile, annotations, scopeSession) + resolveFileAnnotationsWithoutLock(firFile, annotations, scopeSession, collector) } } @@ -61,12 +62,14 @@ internal class FirLazyDeclarationResolver( firFile: FirFile, annotations: List, scopeSession: ScopeSession, + collector: FirTowerDataContextCollector? = null, ) { FirFileAnnotationsResolveTransformer( firFile = firFile, annotations = annotations, session = firFile.moduleData.session, - scopeSession = scopeSession + scopeSession = scopeSession, + firTowerDataContextCollector = collector, ).transformDeclaration() } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirReplacement.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirReplacement.kt index b6b1299b346..89e54ec9c03 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirReplacement.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirReplacement.kt @@ -28,7 +28,7 @@ internal data class RawFirReplacement(val from: KtElement, val to: KtElement) { private var replacementApplied = false private fun ensureReplacementIsValid() { - require(isApplicableForReplacement(from)) { + require(from == to || isApplicableForReplacement(from)) { "Replacement is possible for applicable type but given ${from::class.simpleName}" } require(from::class == to::class) { @@ -44,7 +44,7 @@ internal data class RawFirReplacement(val from: KtElement, val to: KtElement) { } fun ensureApplied() { - check(replacementApplied) { + check(from == to || replacementApplied) { "Replacement requested but was not applied for ${from::class.simpleName}" } } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirUserTypeRefBuilder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirUserTypeRefBuilder.kt new file mode 100644 index 00000000000..0d17f612f7d --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirUserTypeRefBuilder.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2021 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.lazy.resolve + +import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.builder.RawFirBuilder +import org.jetbrains.kotlin.fir.scopes.FirScopeProvider +import org.jetbrains.kotlin.fir.types.FirUserTypeRef +import org.jetbrains.kotlin.psi.KtTypeReference + +internal fun buildFirUserTypeRef( + typeReference: KtTypeReference, + session: FirSession, + baseScopeProvider: FirScopeProvider +): FirUserTypeRef { + val builder = object : RawFirBuilder(session, baseScopeProvider) { + fun build(): FirUserTypeRef = Visitor().visitTypeReference(typeReference, Unit) as FirUserTypeRef + } + builder.context.packageFqName = typeReference.containingKtFile.packageFqName + return builder.build() +} diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt index 7cf3adf475f..ab45bd83feb 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/FirReferenceResolveHelper.kt @@ -6,15 +6,10 @@ package org.jetbrains.kotlin.idea.references import com.intellij.psi.tree.TokenSet -import com.intellij.psi.util.PsiTreeUtil -import com.intellij.psi.util.parentOfType -import org.jetbrains.kotlin.fir.FirFakeSourceElementKind -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertySymbol import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError @@ -29,8 +24,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.fir.getCandidateSymbols import org.jetbrains.kotlin.idea.fir.isImplicitFunctionCall -import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForResolveOnAir import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirSafe import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession @@ -169,7 +162,7 @@ internal object FirReferenceResolveHelper { val fir = expression.getOrBuildFir(analysisSession.firResolveState) val session = analysisSession.firResolveState.rootModuleSession return when (fir) { - is FirResolvedTypeRef -> getSymbolsForResolvedTypeRef(fir, expression, session, symbolBuilder, analysisSession.firResolveState) + is FirResolvedTypeRef -> getSymbolsForResolvedTypeRef(fir, expression, session, symbolBuilder) is FirResolvedQualifier -> getSymbolsForResolvedQualifier(fir, expression, session, symbolBuilder, analysisSession) is FirAnnotationCall -> getSymbolsForAnnotationCall(fir, session, symbolBuilder) @@ -349,41 +342,20 @@ internal object FirReferenceResolveHelper { } } - private fun tryResolvePartiallyCorrectReference( - expression: KtSimpleNameExpression, - resolveState: FirModuleResolveState - ): FirResolvedTypeRef? { - val expressionUserType = expression.parent as? KtUserType ?: return null - val typeReference = expressionUserType.parentOfType(withSelf = false) ?: return null - return LowLevelFirApiFacadeForResolveOnAir.onAirResolveElement( - state = resolveState, - place = typeReference, - elementToResolve = KtPsiFactory(expression.project).createType(expressionUserType), - ) as? FirResolvedTypeRef - } - private fun getSymbolsForResolvedTypeRef( fir: FirResolvedTypeRef, expression: KtSimpleNameExpression, session: FirSession, symbolBuilder: KtSymbolByFirBuilder, - resolveState: FirModuleResolveState, ): Collection { - if (expression.isPartOfUserTypeRefQualifier()) { - val typeQualifier = findPossibleTypeQualifier(expression, fir)?.toTargetPsi(session, symbolBuilder) - val typeOrPackageQualifier = - typeQualifier ?: getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = true) - if (typeOrPackageQualifier != null) return listOf(typeOrPackageQualifier) + val isPossiblyPackage = fir is FirErrorTypeRef && expression.isPartOfUserTypeRefQualifier() - val resolvedPartType = tryResolvePartiallyCorrectReference( - expression, - resolveState - )?.toTargetSymbol(session, symbolBuilder) + val resultSymbol = + if (isPossiblyPackage) getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = true) + else fir.toTargetSymbol(session, symbolBuilder) - return listOfNotNull(resolvedPartType) - } - return listOfNotNull(fir.toTargetSymbol(session, symbolBuilder)) + return listOfNotNull(resultSymbol) } private fun getSymbolsForResolvedQualifier( diff --git a/idea/testData/resolve/references/ClassNameBeforeDot.kt b/idea/testData/resolve/references/ClassNameBeforeDot.kt index 7303789a510..7e3e29b0bbd 100644 --- a/idea/testData/resolve/references/ClassNameBeforeDot.kt +++ b/idea/testData/resolve/references/ClassNameBeforeDot.kt @@ -1,4 +1,3 @@ -// IGNORE_FIR class Foo