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? { override fun getSession(moduleInfo: ModuleInfo): FirSession? {
return sessionCache[moduleInfo] return sessionCache[moduleInfo]
} }
@@ -19,8 +19,8 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider<FirClassLikeSymbol<*>>() { open class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider<FirClassLikeSymbol<*>>() {
private val dependencyProviders by lazy { protected open val dependencyProviders by lazy {
val moduleInfo = session.moduleInfo ?: return@lazy emptyList() val moduleInfo = session.moduleInfo ?: return@lazy emptyList()
moduleInfo.dependenciesWithoutSelf().mapNotNull { moduleInfo.dependenciesWithoutSelf().mapNotNull {
session.sessionProvider?.getSession(it)?.firSymbolProvider session.sessionProvider?.getSession(it)?.firSymbolProvider
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir package org.jetbrains.kotlin.fir
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.* import org.jetbrains.kotlin.fir.types.impl.*
@@ -53,6 +54,8 @@ class BuiltinTypes {
} }
interface FirSessionProvider { interface FirSessionProvider {
val project: Project
fun getSession(moduleInfo: ModuleInfo): FirSession? 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.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
@@ -38,7 +37,7 @@ class FirIdeJavaModuleBasedSession(
listOf( listOf(
firProvider, firProvider,
JavaSymbolProvider(this, sessionProvider.project, scope), JavaSymbolProvider(this, sessionProvider.project, scope),
FirDependenciesSymbolProviderImpl(this) FirIdeModuleDependenciesSymbolProvider(this)
) )
) as FirSymbolProvider ) 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.PsiElement
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.diagnostics.Diagnostic 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.declarations.FirFile
import org.jetbrains.kotlin.fir.java.FirLibrarySession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider 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.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.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo 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.KtElement
import org.jetbrains.kotlin.psi.KtFile 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 { interface FirModuleResolveState {
val sessionProvider: FirSessionProvider val sessionProvider: FirProjectSessionProvider
fun getSession(psi: KtElement): FirSession { fun getSession(psi: KtElement): FirSession {
val sessionProvider = sessionProvider as FirProjectSessionProvider
val moduleInfo = psi.getModuleInfo() as ModuleSourceInfo 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? operator fun get(psi: KtElement): FirElement?
@@ -72,7 +52,7 @@ interface FirModuleResolveState {
fun setDiagnosticsForFile(file: KtFile, fir: FirFile, diagnostics: Iterable<ConeDiagnostic> = emptyList()) 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 cache = mutableMapOf<KtElement, FirElement>()
private val diagnosticCache = mutableMapOf<KtElement, MutableList<Diagnostic>>() private val diagnosticCache = mutableMapOf<KtElement, MutableList<Diagnostic>>()