From 37839a181c9dd95d38efe5addfb6204a41c87df8 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 16 Dec 2019 13:44:48 +0300 Subject: [PATCH] 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) --- .../fir/java/FirJavaModuleBasedSession.kt | 2 +- .../impl/FirDependenciesSymbolProviderImpl.kt | 4 +- .../org/jetbrains/kotlin/fir/FirSession.kt | 3 ++ .../idea/fir/FirIdeJavaModuleBasedSession.kt | 3 +- .../FirIdeModuleDependenciesSymbolProvider.kt | 48 +++++++++++++++++ .../kotlin/idea/fir/FirModuleResolveState.kt | 54 ++++++------------- 6 files changed, 72 insertions(+), 42 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeModuleDependenciesSymbolProvider.kt diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt index 5d507eb0690..78477ed3cf4 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaModuleBasedSession.kt @@ -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] } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt index 46c1a4b12d5..f77aa96ad0b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt @@ -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>() { - private val dependencyProviders by lazy { +open class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider>() { + protected open val dependencyProviders by lazy { val moduleInfo = session.moduleInfo ?: return@lazy emptyList() moduleInfo.dependenciesWithoutSelf().mapNotNull { session.sessionProvider?.getSession(it)?.firSymbolProvider diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt index 35bb04b6033..8c3d1d36718 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSession.kt @@ -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? } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeJavaModuleBasedSession.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeJavaModuleBasedSession.kt index faaf32ddce8..90b6db4c95b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeJavaModuleBasedSession.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeJavaModuleBasedSession.kt @@ -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 ) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeModuleDependenciesSymbolProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeModuleDependenciesSymbolProvider.kt new file mode 100644 index 00000000000..5d08b5951c9 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirIdeModuleDependenciesSymbolProvider.kt @@ -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 by lazy { + val moduleInfo = session.moduleInfo + val sessionProvider = session.sessionProvider ?: return@lazy emptyList() + val project = sessionProvider.project + val stateService = FirIdeResolveStateService.getInstance(project) + moduleInfo.dependenciesWithoutSelf().filterIsInstance().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() + } +} + diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirModuleResolveState.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirModuleResolveState.kt index 23a05183973..60bdb9e6ea3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirModuleResolveState.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/fir/FirModuleResolveState.kt @@ -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.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 = emptyList()) } -class FirModuleResolveStateImpl(override val sessionProvider: FirSessionProvider) : FirModuleResolveState { +class FirModuleResolveStateImpl(override val sessionProvider: FirProjectSessionProvider) : FirModuleResolveState { private val cache = mutableMapOf() private val diagnosticCache = mutableMapOf>()