FIR: implements multi-module resolve, add tests #KT-24093 Fixed

This commit introduces FIR session provider, dependency provider,
library session + other infrastructure necessary for multi-module resolve
This commit is contained in:
Mikhail Glukhikh
2018-04-05 19:27:00 +03:00
parent bc82f2f940
commit 6e369e156d
27 changed files with 366 additions and 49 deletions
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
abstract class AbstractFirSymbolProvider : FirSymbolProvider {
protected val classCache = mutableMapOf<ClassId, ConeSymbol?>()
protected val packageCache = mutableMapOf<FqName, FqName?>()
protected inline fun <K, V : Any?> MutableMap<K, V>.lookupCacheOrCalculate(key: K, crossinline l: (K) -> V): V? {
return if (key in this.keys) {
this[key]
} else {
val calculated = l(key)
this[key] = calculated
calculated
}
}
}
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.name.FqName
interface FirSymbolProvider {
val doesLookupInFir: Boolean
fun getSymbolByFqName(classId: ClassId): ConeSymbol?
fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime
@@ -13,9 +13,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class FirCompositeSymbolProvider(val providers: List<FirSymbolProvider>) : FirSymbolProvider {
override val doesLookupInFir: Boolean
get() = providers.any(FirSymbolProvider::doesLookupInFir)
override fun getPackage(fqName: FqName): FqName? {
return providers.firstNotNullResult { it.getPackage(fqName) }
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider() {
private val dependencyProviders by lazy {
val moduleInfo = session.moduleInfo ?: return@lazy emptyList()
moduleInfo.dependenciesWithoutSelf().mapNotNull {
session.sessionProvider?.getSession(it)?.service<FirSymbolProvider>()
}.toList()
}
override fun getSymbolByFqName(classId: ClassId): ConeSymbol? {
return classCache.lookupCacheOrCalculate(classId) {
for (provider in dependencyProviders) {
provider.getSymbolByFqName(classId)?.let {
return@lookupCacheOrCalculate it
}
}
null
}
}
override fun getPackage(fqName: FqName): FqName? {
return packageCache.lookupCacheOrCalculate(fqName) {
for (provider in dependencyProviders) {
provider.getPackage(fqName)?.let {
return@lookupCacheOrCalculate it
}
}
null
}
}
}
@@ -28,13 +28,10 @@ import java.io.InputStream
class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider {
override val doesLookupInFir: Boolean
get() = false
private class BuiltInsPackageFragment(stream: InputStream, val fqName: FqName) {
lateinit var version: BuiltInsBinaryVersion
val packageProto = run {
val packageProto: ProtoBuf.PackageFragment = run {
version = BuiltInsBinaryVersion.readFrom(stream)
@@ -19,9 +19,6 @@ import org.jetbrains.kotlin.name.FqName
class FirProviderImpl(val session: FirSession) : FirProvider {
override val doesLookupInFir: Boolean
get() = true
override fun getFirClassifierBySymbol(symbol: ConeSymbol): FirNamedDeclaration? {
return when (symbol) {
is FirBasedSymbol<*> -> symbol.fir as? FirNamedDeclaration
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.scopes.FirPosition
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
@@ -21,7 +22,7 @@ abstract class FirAbstractStarImportingScope(val session: FirSession, lookupInFi
val provider = FirSymbolProvider.getInstance(session).let {
when {
it is FirCompositeSymbolProvider && !lookupInFir -> FirCompositeSymbolProvider(it.providers.filter { !it.doesLookupInFir })
it is FirCompositeSymbolProvider && !lookupInFir -> it.providers.find { it is FirDependenciesSymbolProviderImpl }!!
else -> it
}
}
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.fir
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.declarations.FirFile
@@ -21,13 +23,16 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas
return createEnvironmentWithMockJdk(ConfigurationKind.JDK_NO_RUNTIME)
}
fun doCreateAndProcessFir(ktFiles: List<KtFile>): List<FirFile> {
val session = createSession()
private fun doCreateAndProcessFir(ktFiles: List<KtFile>): List<FirFile> {
val scope = GlobalSearchScope.filesScope(project, ktFiles.mapNotNull { it.virtualFile })
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
val session = createSession(scope)
val builder = RawFirBuilder(session)
val transformer = FirTotalResolveTransformer()
val firFiles = ktFiles.map {
return ktFiles.map {
val firFile = builder.buildFirFile(it)
(session.service<FirProvider>() as FirProviderImpl).recordFile(firFile)
firFile
@@ -39,8 +44,6 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas
throw e
}
}
return firFiles
}
@@ -5,10 +5,27 @@
package org.jetbrains.kotlin.fir
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
import org.jetbrains.kotlin.fir.java.FirLibrarySession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
abstract class AbstractFirResolveWithSessionTestCase : KotlinTestWithEnvironment() {
open fun createSession(): FirSession = FirJavaModuleBasedSession(FirTestModuleInfo(), project)
open fun createSession(sourceScope: GlobalSearchScope): FirSession {
val moduleInfo = FirTestModuleInfo()
val provider = FirProjectSessionProvider(project)
return FirJavaModuleBasedSession(moduleInfo, provider, sourceScope).also {
createSessionForDependencies(provider, moduleInfo, sourceScope)
}
}
private fun createSessionForDependencies(
provider: FirProjectSessionProvider, moduleInfo: FirTestModuleInfo, sourceScope: GlobalSearchScope
) {
val dependenciesInfo = FirTestModuleInfo()
moduleInfo.dependencies.add(dependenciesInfo)
FirLibrarySession(dependenciesInfo, provider, GlobalSearchScope.notScope(sourceScope))
}
}