Introduce FirIdeModuleDependenciesSymbolProvider #KT-35424 In Progress

This solves problems with inter-module dependencies, at least in small projects.
However, Kotlin project still does not see stdlib.
Also, we often have problems with untouched types during expected type checks
(FirUserTypeRef instead of FirResolvedTypeRef)
This commit is contained in:
Mikhail Glukhikh
2019-12-16 13:44:48 +03:00
parent befcfad898
commit 37839a181c
6 changed files with 72 additions and 42 deletions
@@ -124,7 +124,7 @@ class FirLibrarySession private constructor(
}
}
class FirProjectSessionProvider(val project: Project) : FirSessionProvider {
class FirProjectSessionProvider(override val project: Project) : FirSessionProvider {
override fun getSession(moduleInfo: ModuleInfo): FirSession? {
return sessionCache[moduleInfo]
}
@@ -19,8 +19,8 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider<FirClassLikeSymbol<*>>() {
private val dependencyProviders by lazy {
open class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider<FirClassLikeSymbol<*>>() {
protected open val dependencyProviders by lazy {
val moduleInfo = session.moduleInfo ?: return@lazy emptyList()
moduleInfo.dependenciesWithoutSelf().mapNotNull {
session.sessionProvider?.getSession(it)?.firSymbolProvider
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.*
@@ -53,6 +54,8 @@ class BuiltinTypes {
}
interface FirSessionProvider {
val project: Project
fun getSession(moduleInfo: ModuleInfo): FirSession?
}
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
@@ -38,7 +37,7 @@ class FirIdeJavaModuleBasedSession(
listOf(
firProvider,
JavaSymbolProvider(this, sessionProvider.project, scope),
FirDependenciesSymbolProviderImpl(this)
FirIdeModuleDependenciesSymbolProvider(this)
)
) as FirSymbolProvider
)
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.fir.java.FirLibrarySession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
import org.jetbrains.kotlin.idea.caches.resolve.IDEPackagePartProvider
class FirIdeModuleDependenciesSymbolProvider(
session: FirIdeJavaModuleBasedSession
) : FirDependenciesSymbolProviderImpl(session) {
override val dependencyProviders: List<FirSymbolProvider> by lazy {
val moduleInfo = session.moduleInfo
val sessionProvider = session.sessionProvider ?: return@lazy emptyList<FirSymbolProvider>()
val project = sessionProvider.project
val stateService = FirIdeResolveStateService.getInstance(project)
moduleInfo.dependenciesWithoutSelf().filterIsInstance<IdeaModuleInfo>().mapNotNull { dependencyInfo ->
val resolveState = stateService.getResolveState(dependencyInfo)
val dependencySession = when {
dependencyInfo is ModuleSourceInfo -> {
resolveState.getSession(project, dependencyInfo)
}
dependencyInfo.isLibraryClasses() -> {
val dependencyScope = dependencyInfo.contentScope()
FirLibrarySession.create(
dependencyInfo, sessionProvider as FirProjectSessionProvider,
dependencyScope, project, IDEPackagePartProvider(dependencyScope)
)
}
else -> return@mapNotNull null
}
dependencySession.firSymbolProvider
}.toList()
}
}
@@ -9,54 +9,34 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.java.FirLibrarySession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnostic
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.caches.project.isLibraryClasses
import org.jetbrains.kotlin.idea.caches.resolve.IDEPackagePartProvider
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.addToStdlib.cast
private fun createLibrarySession(moduleInfo: IdeaModuleInfo, project: Project, provider: FirProjectSessionProvider): FirLibrarySession {
val contentScope = moduleInfo.contentScope()
return FirLibrarySession.create(moduleInfo, provider, contentScope, project, IDEPackagePartProvider(contentScope))
}
private fun getOrCreateIdeSession(
sessionProvider: FirProjectSessionProvider,
project: Project,
moduleInfo: ModuleSourceInfo
): FirSession {
sessionProvider.getSession(moduleInfo)?.let { return it }
return synchronized(moduleInfo.module) {
sessionProvider.getSession(moduleInfo) ?: FirIdeJavaModuleBasedSession(
project, moduleInfo, sessionProvider, moduleInfo.contentScope()
).also { moduleBasedSession ->
val ideaModuleInfo = moduleInfo.cast<IdeaModuleInfo>()
ideaModuleInfo.dependenciesWithoutSelf().forEach {
if (it is IdeaModuleInfo && it.isLibraryClasses()) {
// TODO: consider caching / synchronization here
createLibrarySession(it, project, sessionProvider)
}
}
sessionProvider.sessionCache[moduleInfo] = moduleBasedSession
}
}
}
interface FirModuleResolveState {
val sessionProvider: FirSessionProvider
val sessionProvider: FirProjectSessionProvider
fun getSession(psi: KtElement): FirSession {
val sessionProvider = sessionProvider as FirProjectSessionProvider
val moduleInfo = psi.getModuleInfo() as ModuleSourceInfo
return getOrCreateIdeSession(sessionProvider, psi.project, moduleInfo)
return getSession(psi.project, moduleInfo)
}
fun getSession(project: Project, moduleInfo: ModuleSourceInfo): FirSession {
sessionProvider.getSession(moduleInfo)?.let { return it }
return synchronized(moduleInfo.module) {
sessionProvider.getSession(moduleInfo) ?: FirIdeJavaModuleBasedSession(
project, moduleInfo, sessionProvider, moduleInfo.contentScope()
).also { moduleBasedSession ->
sessionProvider.sessionCache[moduleInfo] = moduleBasedSession
}
}
}
operator fun get(psi: KtElement): FirElement?
@@ -72,7 +52,7 @@ interface FirModuleResolveState {
fun setDiagnosticsForFile(file: KtFile, fir: FirFile, diagnostics: Iterable<ConeDiagnostic> = emptyList())
}
class FirModuleResolveStateImpl(override val sessionProvider: FirSessionProvider) : FirModuleResolveState {
class FirModuleResolveStateImpl(override val sessionProvider: FirProjectSessionProvider) : FirModuleResolveState {
private val cache = mutableMapOf<KtElement, FirElement>()
private val diagnosticCache = mutableMapOf<KtElement, MutableList<Diagnostic>>()