FIR IDE: introduce withFirDeclaration function

This commit is contained in:
Ilya Kirillov
2020-09-22 13:52:11 +03:00
parent ebc2ea59cd
commit a516264923
8 changed files with 66 additions and 16 deletions
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
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.fir.low.level.api.file.structure.FirElementsRecorder import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FirElementsRecorder
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -23,6 +24,7 @@ internal class FirModuleResolveStateForCompletion(
private val originalState: FirModuleResolveStateImpl private val originalState: FirModuleResolveStateImpl
) : FirModuleResolveState() { ) : FirModuleResolveState() {
override val moduleInfo: IdeaModuleInfo get() = originalState.moduleInfo override val moduleInfo: IdeaModuleInfo get() = originalState.moduleInfo
override val rootModuleSession get() = originalState.rootModuleSession override val rootModuleSession get() = originalState.rootModuleSession
override val firTransformerProvider: FirTransformerProvider get() = originalState.firTransformerProvider override val firTransformerProvider: FirTransformerProvider get() = originalState.firTransformerProvider
private val fileStructureCache = originalState.fileStructureCache private val fileStructureCache = originalState.fileStructureCache
@@ -69,4 +71,8 @@ internal class FirModuleResolveStateForCompletion(
override fun collectDiagnosticsForFile(ktFile: KtFile): Collection<Diagnostic> { override fun collectDiagnosticsForFile(ktFile: KtFile): Collection<Diagnostic> {
error("Diagnostics should not be retrieved in completion") error("Diagnostics should not be retrieved in completion")
} }
override fun findNonLocalSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration {
error("Should not be used in completion")
}
} }
@@ -13,6 +13,8 @@ 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.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.DiagnosticsCollector import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.DiagnosticsCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirElementBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirElementBuilder
@@ -20,8 +22,11 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataC
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureCache
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver 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.idea.fir.low.level.api.sessions.FirIdeSessionProvider import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSessionProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession
import org.jetbrains.kotlin.idea.fir.low.level.api.util.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -56,6 +61,14 @@ internal class FirModuleResolveStateImpl(
error("Should be called only from FirModuleResolveStateForCompletion") error("Should be called only from FirModuleResolveStateForCompletion")
} }
override fun findNonLocalSourceFirDeclaration(
ktDeclaration: KtDeclaration,
): FirDeclaration = ktDeclaration.findSourceNonLocalFirDeclaration(
firFileBuilder,
rootModuleSession.firIdeProvider.symbolProvider,
sessionProvider.getModuleCache(ktDeclaration.getModuleInfo() as ModuleSourceInfo)
)
override fun <D : FirDeclaration> resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D { override fun <D : FirDeclaration> resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D {
val fileCache = when (val session = declaration.session) { val fileCache = when (val session = declaration.session) {
is FirIdeSourcesSession -> session.cache is FirIdeSourcesSession -> session.cache
@@ -12,11 +12,15 @@ 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.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
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
import org.jetbrains.kotlin.idea.fir.low.level.api.FirIdeResolveStateService import org.jetbrains.kotlin.idea.fir.low.level.api.FirIdeResolveStateService
import org.jetbrains.kotlin.idea.fir.low.level.api.FirTransformerProvider import org.jetbrains.kotlin.idea.fir.low.level.api.FirTransformerProvider
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.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -37,6 +41,10 @@ abstract class FirModuleResolveState {
internal abstract fun collectDiagnosticsForFile(ktFile: KtFile): Collection<Diagnostic> internal abstract fun collectDiagnosticsForFile(ktFile: KtFile): Collection<Diagnostic>
abstract fun findNonLocalSourceFirDeclaration(
ktDeclaration: KtDeclaration,
): FirDeclaration
// todo temporary, used only in completion // todo temporary, used only in completion
internal abstract fun recordPsiToFirMappingsForCompletionFrom(fir: FirDeclaration, firFile: FirFile, ktFile: KtFile) internal abstract fun recordPsiToFirMappingsForCompletionFrom(fir: FirDeclaration, firFile: FirFile, ktFile: KtFile)
@@ -14,6 +14,7 @@ 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
import org.jetbrains.kotlin.idea.fir.low.level.api.FirIdeResolveStateService import org.jetbrains.kotlin.idea.fir.low.level.api.FirIdeResolveStateService
import org.jetbrains.kotlin.psi.KtDeclaration
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 kotlin.reflect.KClass import kotlin.reflect.KClass
@@ -44,6 +45,25 @@ object LowLevelFirApiFacade {
inline fun <R> withFirFile(ktFile: KtFile, resolveState: FirModuleResolveState, action: (FirFile) -> R): R = inline fun <R> withFirFile(ktFile: KtFile, resolveState: FirModuleResolveState, action: (FirFile) -> R): R =
action(getFirFile(ktFile, resolveState)) action(getFirFile(ktFile, resolveState))
/**
* Creates [FirDeclaration] by [KtDeclaration] and runs an [action] with it
* [FirDeclaration] passed to [action] should not be leaked outside [action] lambda
* [FirDeclaration] passed to [action] will be resolved at least to [phase]
* Otherwise, some threading problems may arise,
*
* [ktDeclaration] should be non-local declaration (should have fully qualified name)
*/
inline fun <R> withFirDeclaration(
ktDeclaration: KtDeclaration,
resolveState: FirModuleResolveState,
phase: FirResolvePhase = FirResolvePhase.RAW_FIR,
action: (FirDeclaration) -> R
): R {
val firDeclaration = resolveState.findNonLocalSourceFirDeclaration(ktDeclaration)
resolvedFirToPhase(firDeclaration, phase, resolveState)
return action(firDeclaration)
}
fun getDiagnosticsFor(element: KtElement, resolveState: FirModuleResolveState): Collection<Diagnostic> = fun getDiagnosticsFor(element: KtElement, resolveState: FirModuleResolveState): Collection<Diagnostic> =
resolveState.getDiagnostics(element) resolveState.getDiagnostics(element)
@@ -12,7 +12,7 @@ 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.builder.ModuleFileCache
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver 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.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.util.findNonLocalFirDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.util.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.idea.fir.low.level.api.util.hasExplicitTypeOrUnit import org.jetbrains.kotlin.idea.fir.low.level.api.util.hasExplicitTypeOrUnit
import org.jetbrains.kotlin.idea.fir.low.level.api.util.replaceFirst import org.jetbrains.kotlin.idea.fir.low.level.api.util.replaceFirst
import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.idea.util.getElementTextInContext
@@ -111,7 +111,7 @@ internal class FileStructure(
} }
private fun createDeclarationStructure(declaration: KtDeclaration): FileStructureElement { private fun createDeclarationStructure(declaration: KtDeclaration): FileStructureElement {
val firDeclaration = declaration.findNonLocalFirDeclaration(firFileBuilder, firIdeProvider, moduleFileCache) val firDeclaration = declaration.findSourceNonLocalFirDeclaration(firFileBuilder, firIdeProvider, moduleFileCache)
firLazyDeclarationResolver.lazyResolveDeclaration( firLazyDeclarationResolver.lazyResolveDeclaration(
firDeclaration, firDeclaration,
moduleFileCache, moduleFileCache,
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
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.fir.low.level.api.element.builder.FirDesignatedBodyResolveTransformerForIDE import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirDesignatedBodyResolveTransformerForIDE
@@ -19,7 +18,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
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.fir.low.level.api.util.checkCanceled import org.jetbrains.kotlin.idea.fir.low.level.api.util.checkCanceled
import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE
import org.jetbrains.kotlin.idea.fir.low.level.api.util.findNonLocalFirDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.util.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.idea.fir.low.level.api.util.getContainingFile import org.jetbrains.kotlin.idea.fir.low.level.api.util.getContainingFile
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -145,7 +144,7 @@ internal class FirLazyDeclarationResolver(
if (!KtPsiUtil.isLocal(ktDeclaration)) return this if (!KtPsiUtil.isLocal(ktDeclaration)) return this
val nonLocalPsi = ktDeclaration.getNonLocalContainingOrThisDeclaration() val nonLocalPsi = ktDeclaration.getNonLocalContainingOrThisDeclaration()
?: error("Container for local declaration cannot be null") ?: error("Container for local declaration cannot be null")
return nonLocalPsi.findNonLocalFirDeclaration(firFileBuilder, provider, moduleFileCache) return nonLocalPsi.findSourceNonLocalFirDeclaration(firFileBuilder, provider.symbolProvider, moduleFileCache)
} }
} }
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.Immutable import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.Immutable
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.ThreadSafe import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.ThreadSafe
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
@Immutable @Immutable
class FirIdeSessionProvider internal constructor( class FirIdeSessionProvider internal constructor(
@@ -23,4 +24,7 @@ class FirIdeSessionProvider internal constructor(
) : FirSessionProvider { ) : FirSessionProvider {
override fun getSession(moduleInfo: ModuleInfo): FirSession? = override fun getSession(moduleInfo: ModuleInfo): FirSession? =
sessions[moduleInfo] sessions[moduleInfo]
internal fun getModuleCache(moduleSourceInfo: ModuleSourceInfo): ModuleFileCache =
(sessions.getValue(moduleSourceInfo) as FirIdeSourcesSession).cache
} }
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder 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.builder.ModuleFileCache
import org.jetbrains.kotlin.idea.util.classIdIfNonLocal import org.jetbrains.kotlin.idea.util.classIdIfNonLocal
@@ -17,18 +17,18 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
internal fun KtDeclaration.findNonLocalFirDeclaration( internal fun KtDeclaration.findSourceNonLocalFirDeclaration(
firFileBuilder: FirFileBuilder, firFileBuilder: FirFileBuilder,
provider: FirProvider, firSymbolProvider: FirSymbolProvider,
moduleFileCache: ModuleFileCache moduleFileCache: ModuleFileCache
): FirDeclaration { ): FirDeclaration {
require(!KtPsiUtil.isLocal(this)) require(!KtPsiUtil.isLocal(this))
return when { return when {
this is KtClassOrObject -> findFir(provider) this is KtClassOrObject -> findFir(firSymbolProvider)
this is KtNamedDeclaration && (this is KtProperty || this is KtNamedFunction) -> { this is KtNamedDeclaration && (this is KtProperty || this is KtNamedFunction) -> {
val containerClass = containingClassOrObject val containerClass = containingClassOrObject
val declarations = if (containerClass != null) { val declarations = if (containerClass != null) {
val containerClassFir = containerClass.findFir(provider) val containerClassFir = containerClass.findFir(firSymbolProvider)
containerClassFir.declarations containerClassFir.declarations
} else { } else {
val ktFile = containingKtFile val ktFile = containingKtFile
@@ -39,11 +39,11 @@ internal fun KtDeclaration.findNonLocalFirDeclaration(
declarations.first { it.psi === this || it.psi == original } declarations.first { it.psi === this || it.psi == original }
} }
this is KtConstructor<*> -> { this is KtConstructor<*> -> {
val containerClassFir = containingClassOrObject?.findFir(provider) val containerClassFir = containingClassOrObject?.findFir(firSymbolProvider)
?: error("Container class should be not null for KtConstructor") ?: error("Container class should be not null for KtConstructor")
containerClassFir.declarations.first { it.psi === this } containerClassFir.declarations.first { it.psi === this }
} }
this is KtTypeAlias -> findFir(provider) this is KtTypeAlias -> findFir(firSymbolProvider)
else -> error("Invalid container $this::class") else -> error("Invalid container $this::class")
} }
} }
@@ -53,19 +53,19 @@ val ORIGINAL_DECLARATION_KEY = com.intellij.openapi.util.Key<KtDeclaration>("ORI
var KtDeclaration.originalDeclaration by UserDataProperty(ORIGINAL_DECLARATION_KEY) var KtDeclaration.originalDeclaration by UserDataProperty(ORIGINAL_DECLARATION_KEY)
private fun KtClassOrObject.findFir(provider: FirProvider): FirRegularClass { private fun KtClassOrObject.findFir(firSymbolProvider: FirSymbolProvider): FirRegularClass {
val classId = classIdIfNonLocal() val classId = classIdIfNonLocal()
?: error("Container classId should not be null for non-local declaration") ?: error("Container classId should not be null for non-local declaration")
return executeWithoutPCE { return executeWithoutPCE {
provider.getFirClassifierByFqName(classId) as? FirRegularClass firSymbolProvider.getClassLikeSymbolByFqName(classId)?.fir as? FirRegularClass
?: error("Could not find class $classId") ?: error("Could not find class $classId")
} }
} }
private fun KtTypeAlias.findFir(provider: FirProvider): FirTypeAlias { private fun KtTypeAlias.findFir(firSymbolProvider: FirSymbolProvider): FirTypeAlias {
val typeAlias = ClassId(containingKtFile.packageFqName, nameAsSafeName) val typeAlias = ClassId(containingKtFile.packageFqName, nameAsSafeName)
return executeWithoutPCE { return executeWithoutPCE {
provider.getFirClassifierByFqName(typeAlias) as? FirTypeAlias firSymbolProvider.getClassLikeSymbolByFqName(typeAlias)?.fir as? FirTypeAlias
?: error("Could not find type alias $typeAlias") ?: error("Could not find type alias $typeAlias")
} }
} }