FIR IDE: rewrite low level API

- Cache ModuleResolveState for module till the world changes
- Resolve every file under a lock
- All creation of raw fir files and resolve of them happens in FirFileBuilder
- Lazy resolve of fir elements happens in FirElementBuilder

Caching works like the following:
- FirModuleResolveState holds PsiToFirCache & DiagnosticsCollector & FileCacheForModuleProvider
- FileCacheForModuleProvider holds a mapping from ModuleInfo to ModuleFileCache
- ModuleFileCache caches
    - KtFile -> FirFile mapping
    - ClassId -> FirClassLikeDeclaration, CallableId -> FirCallableSymbol
        which used in corresponding FirProvider
    - mapping from declaration to it's file
        which used in corresponding FirProvider
    - locks for fir file resolving
- PsiToFirCache provides mapping from KtElement to  FirElement
- DiagnosticsCollector collects diagnostics for file and caches them
This commit is contained in:
Ilya Kirillov
2020-07-16 13:58:57 +03:00
parent 1957be8757
commit 5f424ed1ec
47 changed files with 1492 additions and 920 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -65,7 +65,7 @@ class FirJavaModuleBasedSession private constructor(
init {
sessionProvider.sessionCache[moduleInfo] = this
sessionProvider.registerSession(moduleInfo, this)
}
}
@@ -118,14 +118,18 @@ class FirLibrarySession private constructor(
}
init {
sessionProvider.sessionCache[moduleInfo] = this
sessionProvider.registerSession(moduleInfo, this)
}
}
class FirProjectSessionProvider(override val project: Project) : FirSessionProvider {
open class FirProjectSessionProvider(override val project: Project) : FirSessionProvider {
override fun getSession(moduleInfo: ModuleInfo): FirSession? {
return sessionCache[moduleInfo]
}
val sessionCache = mutableMapOf<ModuleInfo, FirSession>()
fun registerSession(moduleInfo: ModuleInfo, session: FirSession) {
sessionCache[moduleInfo] = session
}
protected open val sessionCache: MutableMap<ModuleInfo, FirSession> = mutableMapOf()
}
@@ -55,8 +55,6 @@ abstract class FirSymbolProvider : FirSessionComponent {
open fun getNestedClassesNamesInClass(classId: ClassId): Set<Name> = emptySet()
abstract fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime
open fun getAllCallableNamesInPackage(): Set<Name> = emptySet()
}
fun FirSession.getNestedClassifierScope(lookupTag: ConeClassLikeLookupTag): FirScope? =
@@ -46,8 +46,4 @@ class FirCompositeSymbolProvider(val providers: List<FirSymbolProvider>) : FirSy
override fun getNestedClassesNamesInClass(classId: ClassId): Set<Name> {
return providers.flatMapTo(mutableSetOf()) { it.getNestedClassesNamesInClass(classId) }
}
override fun getAllCallableNamesInPackage(): Set<Name> {
return providers.flatMapTo(mutableSetOf()) { it.getAllCallableNamesInPackage() }
}
}
@@ -76,12 +76,6 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc
klass.accept(FirRecorder, state to owner.file)
}
override fun getAllCallableNamesInPackage(): Set<Name> {
return state.callableMap.keys.asSequence()
.filter { it.className == null }
.mapTo(mutableSetOf()) { it.callableName }
}
private val FirAnnotatedDeclaration.file: FirFile
get() = when (this) {
is FirFile -> this
@@ -92,7 +86,6 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc
private fun recordFile(file: FirFile, state: State) {
val packageName = file.packageFqName
state.fileMap.merge(packageName, listOf(file)) { a, b -> a + b }
file.acceptChildren(FirRecorder, state to file)
}
@@ -237,7 +237,7 @@ private class FirSupertypeResolverVisitor(
val outerClassFir = classId.outerClassId?.let(session.firProvider::getFirClassifierByFqName) as? FirRegularClass
prepareScopeForNestedClasses(outerClassFir ?: return ImmutableList.empty())
}
else -> prepareFileScopes(session.firProvider.getFirClassifierContainerFile(classId))
else -> prepareFileScopes(session.firProvider.getFirClassifierContainerFile(classLikeDeclaration.symbol))
}
return result.pushIfNotNull(classLikeDeclaration.typeParametersScope())
@@ -1,10 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.fir.resolve.transformers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSymbolOwner
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
@@ -33,7 +34,11 @@ fun <D> AbstractFirBasedSymbol<D>.phasedFir(
else -> null
}
?: throw AssertionError("Cannot get container file by symbol: $this (${result.render()})")
containingFile.runResolve(toPhase = requiredPhase, fromPhase = availablePhase)
val resolver = fir.session.phasedFirFileResolver
?: error("phasedFirFileResolver should be defined when working with FIR in phased mode")
resolver.resolveFile(containingFile, fromPhase = availablePhase, toPhase = requiredPhase)
}
return result
}
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2020 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.fir.resolve.transformers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
abstract class PhasedFirFileResolver : FirSessionComponent {
abstract fun resolveFile(firFile: FirFile, fromPhase: FirResolvePhase, toPhase: FirResolvePhase)
}
internal val FirSession.phasedFirFileResolver: PhasedFirFileResolver? by FirSession.nullableSessionComponentAccessor()
@@ -58,6 +58,6 @@ class FirPackageMemberScope(val fqName: FqName, val session: FirSession) : FirSc
}
override fun getCallableNames(): Set<Name> {
return symbolProvider.getAllCallableNamesInPackage()
return symbolProvider.getAllCallableNamesInPackage(fqName)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.types.impl.*
import org.jetbrains.kotlin.fir.utils.ArrayMapAccessor
import org.jetbrains.kotlin.fir.utils.ComponentArrayOwner
import org.jetbrains.kotlin.fir.utils.NullableArrayMapAccessor
import org.jetbrains.kotlin.fir.utils.TypeRegistry
import org.jetbrains.kotlin.utils.Jsr305State
import kotlin.reflect.KClass
@@ -21,6 +22,10 @@ abstract class FirSession(val sessionProvider: FirSessionProvider?) : ComponentA
inline fun <reified T : FirSessionComponent> sessionComponentAccessor(): ArrayMapAccessor<FirSessionComponent, FirSessionComponent, T> {
return generateAccessor(T::class)
}
inline fun <reified T : FirSessionComponent> nullableSessionComponentAccessor(): NullableArrayMapAccessor<FirSessionComponent, FirSessionComponent, T> {
return generateNullableAccessor(T::class)
}
}
open val moduleInfo: ModuleInfo? get() = null