From 678b931ba3d6dc0ac2b087caf29d7ac34566272e Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 16 Sep 2021 00:21:28 +0200 Subject: [PATCH] Analysis API: introduce Project Structure --- .../analysis/api/fir/KtSymbolByFirBuilder.kt | 2 +- .../api/fir/symbols/KtFirPackageSymbol.kt | 2 +- .../analysis-api-providers/build.gradle.kts | 1 + .../KotlinModificationTrackerFactory.kt | 6 +- .../providers/KotlinModuleInfoProvider.kt | 17 -- .../providers/KotlinPackageProvider.kt | 2 +- ...BlockModificationTrackerFactoryTestImpl.kt | 8 +- .../impl/KotlinStaticPackageProvider.kt | 2 +- analysis/low-level-api-fir/build.gradle.kts | 1 + .../api/fir/FirIdeResolveStateService.kt | 30 +-- .../api/fir/FirModuleResolveStateDepended.kt | 20 +- .../api/fir/FirModuleResolveStateImpl.kt | 20 +- .../api/fir/api/FirModuleResolveState.kt | 6 +- .../api/FirModuleResolveStateConfigurator.kt | 37 --- .../level/api/fir/api/LowLevelFirApiFacade.kt | 12 +- .../LowLevelFirApiFacadeForResolveOnAir.kt | 4 +- .../level/api/fir/api/ModuleInfoProvider.kt | 19 -- .../low/level/api/fir/api/firSessionUtils.kt | 19 -- .../services/PackagePartProviderFactory.kt | 23 ++ .../SealedInheritorsProviderFactory.kt | 27 ++ .../AbstractFirIdeDiagnosticsCollector.kt | 6 +- .../api/fir/file/builder/ModuleFileCache.kt | 2 +- .../level/api/fir/providers/FirIdeProvider.kt | 8 +- .../api/fir/providers/FirProviderHelper.kt | 2 +- .../api/fir/sessions/FirIdeLibrarySession.kt | 4 +- .../level/api/fir/sessions/FirIdeSession.kt | 3 +- .../api/fir/sessions/FirIdeSessionFactory.kt | 109 ++++---- .../api/fir/sessions/FirIdeSessionProvider.kt | 20 +- .../sessions/FirIdeSessionProviderStorage.kt | 42 ++-- .../api/fir/sessions/FirIdeSourcesSession.kt | 10 +- .../fir/sessions/KtModuleBasedModuleData.kt | 34 +++ .../level/api/fir/sessions/LibrariesCache.kt | 11 +- .../analysis/low/level/api/fir/util/utils.kt | 11 - .../based/AbstractCompilerBasedTest.kt | 232 +++++++++--------- .../based/TestProjectModuleProvider.kt | 33 +++ .../based/TestSourceSetProjectModule.kt | 109 ++++++++ .../api/fir/compiler/based/testServices.kt | 105 ++++++++ .../low/level/api/fir/firTestUtils.kt | 5 +- .../fir/test/base/AbstractLowLevelApiTest.kt | 12 +- analysis/project-structure/build.gradle.kts | 23 ++ .../analysis/project/structure/KtModule.kt | 159 ++++++++++++ .../structure/KtModuleScopeProvider.kt | 41 ++++ .../structure/ProjectStructureProvider.kt | 40 +++ .../project/structure/ktModuleUtils.kt | 38 +++ .../symbol-light-classes/build.gradle.kts | 1 + .../symbol/IDEKotlinAsJavaFirSupport.kt | 15 +- build.gradle.kts | 1 + .../build.gradle.kts | 5 + settings.gradle | 4 +- 49 files changed, 952 insertions(+), 391 deletions(-) delete mode 100644 analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModuleInfoProvider.kt delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveStateConfigurator.kt delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/ModuleInfoProvider.kt delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/firSessionUtils.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/PackagePartProviderFactory.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/SealedInheritorsProviderFactory.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/KtModuleBasedModuleData.kt create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestProjectModuleProvider.kt create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestSourceSetProjectModule.kt create mode 100644 analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/testServices.kt create mode 100644 analysis/project-structure/build.gradle.kts create mode 100644 analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt create mode 100644 analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModuleScopeProvider.kt create mode 100644 analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt create mode 100644 analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ktModuleUtils.kt create mode 100644 prepare/ide-plugin-dependencies/analysis-project-structure-for-ide/build.gradle.kts diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt index 1fea0fa75e5..099e598491d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt @@ -119,7 +119,7 @@ internal class KtSymbolByFirBuilder private constructor( fun createPackageSymbolIfOneExists(packageFqName: FqName): KtFirPackageSymbol? { val exists = - packageProvider.isPackageExists(packageFqName) + packageProvider.doKotlinPackageExists(packageFqName) || JavaPsiFacade.getInstance(project).findPackage(packageFqName.asString()) != null if (!exists) { return null diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPackageSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPackageSymbol.kt index 2b97f638f60..e6e213ab6e9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPackageSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPackageSymbol.kt @@ -65,5 +65,5 @@ class KtPackage( ) : PsiPackageImpl(manager, fqName.asString().replace('/', '.')) { override fun copy() = KtPackage(manager, fqName, scope) - override fun isValid(): Boolean = project.createPackageProvider(scope).isPackageExists(fqName) + override fun isValid(): Boolean = project.createPackageProvider(scope).doKotlinPackageExists(fqName) } diff --git a/analysis/analysis-api-providers/build.gradle.kts b/analysis/analysis-api-providers/build.gradle.kts index 408ed3fe5d4..048fbd4edcd 100644 --- a/analysis/analysis-api-providers/build.gradle.kts +++ b/analysis/analysis-api-providers/build.gradle.kts @@ -7,6 +7,7 @@ dependencies { implementation(project(":compiler:psi")) implementation(project(":compiler:frontend.java")) implementation(project(":core:compiler.common")) + implementation(project(":analysis:project-structure")) implementation(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) } } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModificationTrackerFactory.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModificationTrackerFactory.kt index 5dde7c0073b..8ecc2ca8d7f 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModificationTrackerFactory.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModificationTrackerFactory.kt @@ -9,11 +9,11 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.openapi.util.ModificationTracker import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule public abstract class KotlinModificationTrackerFactory { public abstract fun createProjectWideOutOfBlockModificationTracker(): ModificationTracker - public abstract fun createModuleWithoutDependenciesOutOfBlockModificationTracker(moduleInfo: ModuleSourceInfoBase): ModificationTracker + public abstract fun createModuleWithoutDependenciesOutOfBlockModificationTracker(module: KtSourceModule): ModificationTracker public abstract fun createLibrariesModificationTracker(): ModificationTracker @TestOnly @@ -29,6 +29,6 @@ public fun Project.createLibrariesModificationTracker(): ModificationTracker = .createLibrariesModificationTracker() -public fun ModuleSourceInfoBase.createModuleWithoutDependenciesOutOfBlockModificationTracker(project: Project): ModificationTracker = +public fun KtSourceModule.createModuleWithoutDependenciesOutOfBlockModificationTracker(project: Project): ModificationTracker = ServiceManager.getService(project, KotlinModificationTrackerFactory::class.java) .createModuleWithoutDependenciesOutOfBlockModificationTracker(this) \ No newline at end of file diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModuleInfoProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModuleInfoProvider.kt deleted file mode 100644 index a0feee91a2b..00000000000 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinModuleInfoProvider.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2010-2021 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.analysis.providers - -import com.intellij.openapi.components.ServiceManager -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.psi.KtElement - -public abstract class KotlinModuleInfoProvider { - public abstract fun getModuleInfo(element: KtElement): ModuleInfo -} - -public fun KtElement.getModuleInfo(): ModuleInfo = - ServiceManager.getService(project, KotlinModuleInfoProvider::class.java).getModuleInfo(this) \ No newline at end of file diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt index a13973c54a2..5ee9da3c4ab 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name public abstract class KotlinPackageProvider { - public abstract fun isPackageExists(packageFqName: FqName): Boolean + public abstract fun doKotlinPackageExists(packageFqName: FqName): Boolean public abstract fun getKotlinSubPackageFqNames(packageFqName: FqName): Set } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinOutOfBlockModificationTrackerFactoryTestImpl.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinOutOfBlockModificationTrackerFactoryTestImpl.kt index 4f3d370ea24..955a6472a41 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinOutOfBlockModificationTrackerFactoryTestImpl.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinOutOfBlockModificationTrackerFactoryTestImpl.kt @@ -8,21 +8,21 @@ package org.jetbrains.kotlin.analysis.providers.impl import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.SimpleModificationTracker import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase public class KotlinStaticModificationTrackerFactory : KotlinModificationTrackerFactory() { private val projectWide = SimpleModificationTracker() private val library = SimpleModificationTracker() - private val forModule = mutableMapOf() + private val forModule = mutableMapOf() override fun createProjectWideOutOfBlockModificationTracker(): ModificationTracker { return projectWide } - override fun createModuleWithoutDependenciesOutOfBlockModificationTracker(moduleInfo: ModuleSourceInfoBase): ModificationTracker { - return forModule.getOrPut(moduleInfo) { SimpleModificationTracker() } + override fun createModuleWithoutDependenciesOutOfBlockModificationTracker(module: KtSourceModule): ModificationTracker { + return forModule.getOrPut(module) { SimpleModificationTracker() } } override fun createLibrariesModificationTracker(): ModificationTracker { diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt index 438e715301e..32c9d58d0fc 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt @@ -30,7 +30,7 @@ public class KotlinStaticPackageProvider( packages } - override fun isPackageExists(packageFqName: FqName): Boolean { + override fun doKotlinPackageExists(packageFqName: FqName): Boolean { return packageFqName in packageToSubPackageNames } diff --git a/analysis/low-level-api-fir/build.gradle.kts b/analysis/low-level-api-fir/build.gradle.kts index 16787efb3e5..9156eebf76d 100644 --- a/analysis/low-level-api-fir/build.gradle.kts +++ b/analysis/low-level-api-fir/build.gradle.kts @@ -5,6 +5,7 @@ plugins { dependencies { compile(project(":compiler:psi")) + implementation(project(":analysis:project-structure")) compile(project(":compiler:fir:fir2ir")) compile(project(":compiler:fir:fir2ir:jvm-backend")) compile(project(":compiler:ir.serialization.common")) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt index ea16e6fcd4b..228987a7e7d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt @@ -9,15 +9,15 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectRootModificationTracker import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProviderStorage -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.* - +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.cachedValue +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getValue +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import java.util.concurrent.ConcurrentHashMap internal class FirIdeResolveStateService(project: Project) { @@ -28,29 +28,29 @@ internal class FirIdeResolveStateService(project: Project) { project.createProjectWideOutOfBlockModificationTracker(), ProjectRootModificationTracker.getInstance(project), ) { - ConcurrentHashMap() + ConcurrentHashMap() } - fun getResolveState(moduleInfo: ModuleInfo): FirModuleResolveStateImpl = - stateCache.computeIfAbsent(moduleInfo) { createResolveStateFor(moduleInfo, sessionProviderStorage) } + fun getResolveState(module: KtModule): FirModuleResolveStateImpl = + stateCache.computeIfAbsent(module) { createResolveStateFor(module, sessionProviderStorage) } companion object { fun getInstance(project: Project): FirIdeResolveStateService = ServiceManager.getService(project, FirIdeResolveStateService::class.java) internal fun createResolveStateFor( - moduleInfo: ModuleInfo, + module: KtModule, sessionProviderStorage: FirIdeSessionProviderStorage, configureSession: (FirIdeSession.() -> Unit)? = null, ): FirModuleResolveStateImpl { - if (moduleInfo !is ModuleSourceInfoBase) { - error("Creating FirModuleResolveState is not yet supported for $moduleInfo") + if (module !is KtSourceModule) { + error("Creating FirModuleResolveState is not yet supported for $module") } - val sessionProvider = sessionProviderStorage.getSessionProvider(moduleInfo, configureSession) + val sessionProvider = sessionProviderStorage.getSessionProvider(module, configureSession) val firFileBuilder = sessionProvider.rootModuleSession.firFileBuilder return FirModuleResolveStateImpl( sessionProviderStorage.project, - moduleInfo, + module, sessionProvider, firFileBuilder, FirLazyDeclarationResolver(firFileBuilder), @@ -61,12 +61,12 @@ internal class FirIdeResolveStateService(project: Project) { @TestOnly fun createResolveStateForNoCaching( - moduleInfo: ModuleInfo, + module: KtModule, project: Project, configureSession: (FirIdeSession.() -> Unit)? = null, ): FirModuleResolveState = FirIdeResolveStateService.createResolveStateFor( - moduleInfo = moduleInfo, + module = module, sessionProviderStorage = FirIdeSessionProviderStorage(project), configureSession = configureSession ) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt index c126dce40cb..b98535c7f5a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt @@ -6,13 +6,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic -import org.jetbrains.kotlin.fir.declarations.FirDeclaration -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.analysis.low.level.api.fir.annotations.InternalForInline import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState @@ -22,6 +15,13 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMap import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingKtFileIfAny import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -34,12 +34,12 @@ internal class FirModuleResolveStateDepended( ) : FirModuleResolveState() { override val project: Project get() = originalState.project - override val moduleInfo: ModuleInfo get() = originalState.moduleInfo + override val module: KtModule get() = originalState.module override val rootModuleSession get() = originalState.rootModuleSession private val fileStructureCache get() = originalState.fileStructureCache - override fun getSessionFor(moduleInfo: ModuleInfo): FirSession = - originalState.getSessionFor(moduleInfo) + override fun getSessionFor(module: KtModule): FirSession = + originalState.getSessionFor(module) override fun getOrBuildFirFor(element: KtElement): FirElement? { val elementBuilder = originalState.elementBuilder diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt index 680ce2567a7..51780e4620f 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt @@ -6,9 +6,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.providers.getModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic @@ -37,11 +34,14 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSes import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.psi.* internal class FirModuleResolveStateImpl( override val project: Project, - override val moduleInfo: ModuleInfo, + override val module: KtModule, private val sessionProvider: FirIdeSessionProvider, val firFileBuilder: FirFileBuilder, val firLazyDeclarationResolver: FirLazyDeclarationResolver, @@ -58,8 +58,8 @@ internal class FirModuleResolveStateImpl( val elementBuilder = FirElementBuilder() private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, rootModuleSession.cache) - override fun getSessionFor(moduleInfo: ModuleInfo): FirSession = - sessionProvider.getSession(moduleInfo)!! + override fun getSessionFor(module: KtModule): FirSession = + sessionProvider.getSession(module)!! override fun getOrBuildFirFor(element: KtElement): FirElement? = elementBuilder.getOrBuildFirFor( @@ -95,9 +95,9 @@ internal class FirModuleResolveStateImpl( * [ktDeclaration] should be either [KtDeclaration] or [KtLambdaExpression] */ private fun findSourceFirDeclarationByExpression(ktDeclaration: KtExpression): FirDeclaration { - val moduleInfo = ktDeclaration.getModuleInfo() as? ModuleSourceInfoBase - require(moduleInfo != null) { - "Declaration should have ModuleSourceInfo, instead it had ${ktDeclaration.getModuleInfo()}" + val module = ktDeclaration.getKtModule(project) + require(module is KtSourceModule) { + "Declaration should have ModuleSourceInfo, instead it had ${module::class}" } val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() ?: error("Declaration should have non-local container${ktDeclaration.getElementTextInContext()}") @@ -106,7 +106,7 @@ internal class FirModuleResolveStateImpl( return nonLocalNamedDeclaration.findSourceNonLocalFirDeclaration( firFileBuilder = firFileBuilder, firSymbolProvider = rootModuleSession.firIdeProvider.symbolProvider, - moduleFileCache = sessionProvider.getModuleCache(moduleInfo) + moduleFileCache = sessionProvider.getModuleCache(module) ) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt index 3b5dd723443..eb26258269d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt @@ -6,13 +6,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.analysis.low.level.api.fir.annotations.InternalForInline import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType +import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -23,9 +23,9 @@ abstract class FirModuleResolveState { abstract val rootModuleSession: FirSession - abstract val moduleInfo: ModuleInfo + abstract val module: KtModule - internal abstract fun getSessionFor(moduleInfo: ModuleInfo): FirSession + internal abstract fun getSessionFor(module: KtModule): FirSession /** * Build fully resolved FIR node for requested element. diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveStateConfigurator.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveStateConfigurator.kt deleted file mode 100644 index ed48ae4a7bf..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveStateConfigurator.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2010-2021 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.analysis.low.level.api.fir.api - -import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElementFinder -import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider -import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider -import org.jetbrains.kotlin.fir.java.FirJavaElementFinder -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession -import org.jetbrains.kotlin.load.kotlin.PackagePartProvider -import org.jetbrains.kotlin.psi.KtElement - -abstract class FirModuleResolveStateConfigurator { - abstract fun createPackagePartsProvider(moduleInfo: ModuleSourceInfoBase, scope: GlobalSearchScope): PackagePartProvider - - abstract fun createModuleDataProvider(moduleInfo: ModuleSourceInfoBase): ModuleDataProvider - - abstract fun getLanguageVersionSettings(moduleInfo: ModuleSourceInfoBase): LanguageVersionSettings - abstract fun getModuleSourceScope(moduleInfo: ModuleSourceInfoBase): GlobalSearchScope - abstract fun createScopeForModuleLibraries(moduleInfo: ModuleSourceInfoBase): GlobalSearchScope - abstract fun createSealedInheritorsProvider(): SealedClassInheritorsProvider - - abstract fun configureSourceSession(session: FirSession) -} - -val Project.stateConfigurator: FirModuleResolveStateConfigurator - get() = ServiceManager.getService(this, FirModuleResolveStateConfigurator::class.java) \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacade.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacade.kt index 404cec6634a..3336b64c4ba 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacade.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacade.kt @@ -6,14 +6,14 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.providers.getModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.analysis.low.level.api.fir.FirIdeResolveStateService import org.jetbrains.kotlin.analysis.low.level.api.fir.annotations.InternalForInline import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile @@ -23,13 +23,15 @@ import kotlin.reflect.KClass /** * Returns [FirModuleResolveState] which corresponds to containing module */ -fun KtElement.getResolveState(): FirModuleResolveState = - getModuleInfo().getResolveState(project) +fun KtElement.getResolveState(): FirModuleResolveState { + val project = project + return getKtModule(project).getResolveState(project) +} /** * Returns [FirModuleResolveState] which corresponds to containing module */ -fun ModuleInfo.getResolveState(project: Project): FirModuleResolveState = +fun KtModule.getResolveState(project: Project): FirModuleResolveState = FirIdeResolveStateService.getInstance(project).getResolveState(this) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt index ec1628a5dc8..c06ce024e9d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.analysis.providers.getModuleInfo import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation @@ -39,6 +38,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInCont import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentOfType import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentsOfType +import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.isAncestor @@ -127,7 +127,7 @@ object LowLevelFirApiFacadeForResolveOnAir { file: KtFile, ): FirTowerDataContext { require(file.isPhysical) - val session = state.getSessionFor(file.getModuleInfo()) as FirIdeSourcesSession + val session = state.getSessionFor(file.getKtModule(state.project)) as FirIdeSourcesSession val firFile = session.firFileBuilder.buildRawFirFileWithCaching( ktFile = file, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/ModuleInfoProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/ModuleInfoProvider.kt deleted file mode 100644 index 496878bc215..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/ModuleInfoProvider.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2010-2021 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.analysis.low.level.api.fir.api - -import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.psi.KtElement - -abstract class ModuleInfoProvider { - - companion object { - fun getInstance(project: Project): ModuleInfoProvider = ServiceManager.getService(project, ModuleInfoProvider::class.java) - } -} - diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/firSessionUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/firSessionUtils.kt deleted file mode 100644 index aba897a6a11..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/firSessionUtils.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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.analysis.low.level.api.fir.api - -import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeModuleSession - -/** - * Returns a [GlobalSearchScope] declarations from which [FirSession] knows about - */ -val FirSession.searchScope: GlobalSearchScope - get() { - check(this is FirIdeModuleSession) - return scope - } \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/PackagePartProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/PackagePartProviderFactory.kt new file mode 100644 index 00000000000..260eb85cc6b --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/PackagePartProviderFactory.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2021 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.analysis.low.level.api.fir.api.services + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.load.kotlin.PackagePartProvider + +abstract class PackagePartProviderFactory { + /** + * Create a [PackagePartProvider] for a given scope. [PackagePartProvider] is responsible for searching sub packages in a library. + */ + abstract fun createPackagePartProviderForLibrary(scope: GlobalSearchScope): PackagePartProvider +} + +/** + * Create a [PackagePartProvider] for a given scope. [PackagePartProvider] is responsible for searching sub packages in a library. + */ +internal fun Project.createPackagePartProviderForLibrary(scope: GlobalSearchScope): PackagePartProvider = + getService(PackagePartProviderFactory::class.java).createPackagePartProviderForLibrary(scope) \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/SealedInheritorsProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/SealedInheritorsProviderFactory.kt new file mode 100644 index 00000000000..6a04af1f50f --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/services/SealedInheritorsProviderFactory.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2021 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.analysis.low.level.api.fir.api.services + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider +import org.jetbrains.kotlin.fir.resolve.transformers.FirSealedClassInheritorsProcessor +import org.jetbrains.kotlin.load.kotlin.PackagePartProvider + +abstract class FirSealedClassInheritorsProcessorFactory { + /** + * Creates [SealedClassInheritorsProvider] for a module. + * This function should crate a new [SealedClassInheritorsProvider] instance on every call. + */ + abstract fun createSealedClassInheritorsProvider(): SealedClassInheritorsProvider +} + +/** + * Creates [SealedClassInheritorsProvider] for a module. + * This function should crate a new [SealedClassInheritorsProvider] instance on every call. + */ +internal fun Project.createSealedInheritorsProvider(): SealedClassInheritorsProvider = + getService(FirSealedClassInheritorsProcessorFactory::class.java).createSealedClassInheritorsProvider() \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/AbstractFirIdeDiagnosticsCollector.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/AbstractFirIdeDiagnosticsCollector.kt index 28ba908429d..6a9451944bb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/AbstractFirIdeDiagnosticsCollector.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/AbstractFirIdeDiagnosticsCollector.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.module import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal import org.jetbrains.kotlin.fir.analysis.checkers.* @@ -20,7 +21,6 @@ import org.jetbrains.kotlin.fir.analysis.jvm.checkers.JvmDeclarationCheckers import org.jetbrains.kotlin.fir.analysis.jvm.checkers.JvmExpressionCheckers import org.jetbrains.kotlin.fir.analysis.jvm.diagnostics.FirJvmDefaultErrorMessages import org.jetbrains.kotlin.fir.moduleData -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.moduleSourceInfo import org.jetbrains.kotlin.platform.SimplePlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatform @@ -41,8 +41,8 @@ private object CheckersFactory { reporter: DiagnosticReporter, useExtendedCheckers: Boolean ): List { - val moduleInfo = session.moduleData.moduleSourceInfo - val platform = moduleInfo.platform.componentPlatforms.first() + val module = session.moduleData.module + val platform = module.platform.componentPlatforms.first() installPlatformSpecificErrorMessages(platform) val declarationCheckers = createDeclarationCheckers(useExtendedCheckers, platform) val expressionCheckers = createExpressionCheckers(useExtendedCheckers, platform) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/ModuleFileCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/ModuleFileCache.kt index 0be941d5300..955ba1f8453 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/ModuleFileCache.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/ModuleFileCache.kt @@ -21,7 +21,7 @@ import java.util.* import java.util.concurrent.ConcurrentHashMap /** - * Caches mapping [KtFile] -> [FirFile] of module [moduleInfo] + * Caches mapping [KtFile] -> [FirFile] of module [KtModule] */ @ThreadSafe internal abstract class ModuleFileCache { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt index 78b842a661b..6249e5941cd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt @@ -6,9 +6,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache +import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.NoMutableState import org.jetbrains.kotlin.fir.ThreadSafeMutableState @@ -21,8 +23,6 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -31,7 +31,7 @@ import org.jetbrains.kotlin.name.Name internal class FirIdeProvider( @Suppress("UNUSED_PARAMETER") project: Project, val session: FirSession, - @Suppress("UNUSED_PARAMETER") moduleInfo: ModuleSourceInfoBase, + @Suppress("UNUSED_PARAMETER") module: KtModule, val kotlinScopeProvider: FirKotlinScopeProvider, firFileBuilder: FirFileBuilder, val cache: ModuleFileCache, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirProviderHelper.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirProviderHelper.kt index 5b3904d8503..965a6c3bf9e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirProviderHelper.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirProviderHelper.kt @@ -86,5 +86,5 @@ internal class FirProviderHelper( } fun getPackage(fqName: FqName): FqName? = - fqName.takeIf(packageProvider::isPackageExists) + fqName.takeIf(packageProvider::doKotlinPackageExists) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeLibrarySession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeLibrarySession.kt index 1438dba606d..bb32253f6a9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeLibrarySession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeLibrarySession.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.PrivateSessionConstructor @@ -17,6 +16,5 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor @OptIn(PrivateSessionConstructor::class) internal class FirIdeLibrariesSession @PrivateSessionConstructor constructor( override val project: Project, - override val scope: GlobalSearchScope, builtinTypes: BuiltinTypes, -) : FirIdeModuleSession(builtinTypes, Kind.Library) +) : FirIdeSession(builtinTypes, Kind.Library) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSession.kt index c081781cd41..3c0468a5bae 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSession.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.PrivateSessionConstructor @@ -18,5 +19,5 @@ abstract class FirIdeSession(override val builtinTypes: BuiltinTypes, kind: Kind @OptIn(PrivateSessionConstructor::class) abstract class FirIdeModuleSession(builtinTypes: BuiltinTypes, kind: Kind) : FirIdeSession(builtinTypes, kind) { - abstract val scope: GlobalSearchScope + abstract val module: KtModule } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt index 770645604b5..8f55f2e1f74 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt @@ -6,9 +6,20 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner +import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeFirPhaseManager +import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createPackagePartProviderForLibrary +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createSealedInheritorsProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCacheImpl +import org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches.FirThreadSafeCachesFactory +import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.* +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled +import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createPackageProvider -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.fir.* @@ -16,6 +27,7 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper import org.jetbrains.kotlin.fir.caches.FirCachesFactory import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider +import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider import org.jetbrains.kotlin.fir.java.JavaSymbolProvider import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider @@ -26,58 +38,42 @@ import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCompositeSymbolProvide import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.transformers.FirPhaseCheckingPhaseManager -import org.jetbrains.kotlin.fir.symbols.FirPhaseManager import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.session.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner -import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeFirPhaseManager -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveStateConfigurator -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.stateConfigurator -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCacheImpl -import org.jetbrains.kotlin.analysis.low.level.api.fir.fir.caches.FirThreadSafeCachesFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeBuiltinsAndCloneableSessionProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeLibrariesSessionProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirModuleWithDependenciesSymbolProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled +import org.jetbrains.kotlin.fir.symbols.FirPhaseManager import org.jetbrains.kotlin.load.java.createJavaClassFinder import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices +import java.nio.file.Path @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) internal object FirIdeSessionFactory { fun createSourcesSession( project: Project, - configurator: FirModuleResolveStateConfigurator, - moduleInfo: ModuleSourceInfoBase, + module: KtSourceModule, builtinsAndCloneableSession: FirIdeBuiltinsAndCloneableSession, firPhaseRunner: FirPhaseRunner, sessionInvalidator: FirSessionInvalidator, builtinTypes: BuiltinTypes, - sessionsCache: MutableMap, + sessionsCache: MutableMap, isRootModule: Boolean, librariesCache: LibrariesCache, configureSession: (FirIdeSession.() -> Unit)? = null ): FirIdeSourcesSession { - sessionsCache[moduleInfo]?.let { return it } - val languageVersionSettings = project.stateConfigurator.getLanguageVersionSettings(moduleInfo) + sessionsCache[module]?.let { return it } + val languageVersionSettings = module.languageVersionSettings val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val firBuilder = FirFileBuilder(scopeProvider, firPhaseRunner) - val searchScope = project.stateConfigurator.getModuleSourceScope(moduleInfo) - val dependentModules = moduleInfo.dependenciesWithoutSelf() - .filterIsInstanceTo>(mutableListOf()) - val session = FirIdeSourcesSession(dependentModules, project, searchScope, firBuilder, builtinTypes) - sessionsCache[moduleInfo] = session + val contentScope = module.contentScope + val dependentModules = module.directRegularDependenciesOfType() + val session = FirIdeSourcesSession(module, project, firBuilder, builtinTypes) + sessionsCache[module] = session return session.apply session@{ - val moduleData = FirModuleInfoBasedModuleData(moduleInfo).apply { bindSession(this@session) } + val moduleData = KtModuleBasedModuleData(module).apply { bindSession(this@session) } registerModuleData(moduleData) val cache = ModuleFileCacheImpl(this) @@ -91,12 +87,12 @@ internal object FirIdeSessionFactory { val provider = FirIdeProvider( project, this, - moduleInfo, + module, scopeProvider, firFileBuilder, cache, - project.createDeclarationProvider(searchScope), - project.createPackageProvider(searchScope), + project.createDeclarationProvider(contentScope), + project.createPackageProvider(contentScope), ) register(FirProvider::class, provider) @@ -107,8 +103,8 @@ internal object FirIdeSessionFactory { @OptIn(ExperimentalStdlibApi::class) val dependentProviders = buildList { add( - createLibrarySession( - moduleInfo, + createModuleLibrariesSession( + module, project, builtinsAndCloneableSession, builtinTypes, @@ -121,7 +117,6 @@ internal object FirIdeSessionFactory { .mapTo(this) { createSourcesSession( project, - configurator, it, builtinsAndCloneableSession, firPhaseRunner, @@ -129,7 +124,7 @@ internal object FirIdeSessionFactory { builtinTypes, sessionsCache, isRootModule = false, - librariesCache, + librariesCache = librariesCache, configureSession = configureSession, ).symbolProvider } @@ -143,7 +138,7 @@ internal object FirIdeSessionFactory { this, providers = listOf( provider.symbolProvider, - JavaSymbolProvider(this, moduleData, project.createJavaClassFinder(searchScope)), + JavaSymbolProvider(this, moduleData, project.createJavaClassFinder(contentScope)), ), dependencyProvider ) @@ -159,23 +154,22 @@ internal object FirIdeSessionFactory { } }.configure() configureSession?.invoke(this) - project.stateConfigurator.configureSourceSession(this) } } - fun createLibrarySession( - mainModuleInfo: ModuleSourceInfoBase, + private fun createModuleLibrariesSession( + sourceModule: KtSourceModule, project: Project, builtinsAndCloneableSession: FirIdeBuiltinsAndCloneableSession, builtinTypes: BuiltinTypes, librariesCache: LibrariesCache, languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, configureSession: (FirIdeSession.() -> Unit)?, - ): FirIdeLibrariesSession = librariesCache.cached(mainModuleInfo) { + ): FirIdeLibrariesSession = librariesCache.cached(sourceModule) { checkCanceled() - val searchScope = project.stateConfigurator.createScopeForModuleLibraries(mainModuleInfo) - FirIdeLibrariesSession(project, searchScope, builtinTypes).apply session@{ - registerModuleData(FirModuleInfoBasedModuleData(mainModuleInfo).apply { bindSession(this@session) }) + val searchScope = project.moduleScopeProvider.getModuleLibrariesScope(sourceModule) + FirIdeLibrariesSession(project, builtinTypes).apply session@{ + registerModuleData(KtModuleBasedModuleData(sourceModule).apply { bindSession(this@session) }) registerIdeComponents(project) register(FirPhaseManager::class, FirPhaseCheckingPhaseManager) registerCommonComponents(languageVersionSettings) @@ -184,11 +178,9 @@ internal object FirIdeSessionFactory { val kotlinSymbolProvider = KotlinDeserializedJvmSymbolsProvider( this@session, - moduleDataProvider = project.stateConfigurator.createModuleDataProvider(mainModuleInfo).apply { - allModuleData.forEach { it.bindSession(this@session) } - }, + moduleDataProvider = createModuleDataProvider(sourceModule, this), kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped), - packagePartProvider = project.stateConfigurator.createPackagePartsProvider(mainModuleInfo, searchScope), + packagePartProvider = project.createPackagePartProviderForLibrary(searchScope), kotlinClassFinder = VirtualFileFinderFactory.getInstance(project).create(searchScope), javaClassFinder = project.createJavaClassFinder(searchScope) ) @@ -200,6 +192,21 @@ internal object FirIdeSessionFactory { } } + private fun createModuleDataProvider(sourceModule: KtSourceModule, session: FirIdeSession): ModuleDataProvider { + val dependencyList = DependencyListForCliModule.build( + Name.special("<${sourceModule.moduleDescription}>"), + sourceModule.platform, + sourceModule.analyzerServices + ) { + dependencies(sourceModule.directRegularDependencies.extractLibraryPaths()) + friendDependencies(sourceModule.directFriendDependencies.extractLibraryPaths()) + dependsOnDependencies(sourceModule.directRefinementDependencies.extractLibraryPaths()) + } + return dependencyList.moduleDataProvider.apply { + allModuleData.forEach { it.bindSession(session) } + } + } + fun createBuiltinsAndCloneableSession( project: Project, builtinTypes: BuiltinTypes, @@ -240,10 +247,16 @@ internal object FirIdeSessionFactory { private fun FirIdeSession.registerIdeComponents(project: Project) { register(IdeSessionComponents::class, IdeSessionComponents.create(this)) register(FirCachesFactory::class, FirThreadSafeCachesFactory) - register(SealedClassInheritorsProvider::class, project.stateConfigurator.createSealedInheritorsProvider()) + register(SealedClassInheritorsProvider::class, project.createSealedInheritorsProvider()) } } +private fun List.extractLibraryPaths(): List = + asSequence() + .filterIsInstance() + .flatMap { it.getBinaryRoots() } + .toList() + @Deprecated( "This is a dirty hack used only for one usage (building fir for psi from stubs) and it should be removed after fix of that usage", level = DeprecationLevel.ERROR diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt index 7bacc50e22e..e852a499e8b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt @@ -6,26 +6,26 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase +import org.jetbrains.kotlin.analysis.low.level.api.fir.annotations.Immutable +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.annotations.Immutable -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache @Immutable class FirIdeSessionProvider internal constructor( val project: Project, internal val rootModuleSession: FirIdeSourcesSession, - val sessions: Map + val sessions: Map ) : FirSessionProvider() { override fun getSession(moduleData: FirModuleData): FirSession? = - sessions[moduleData.moduleSourceInfo] + sessions[moduleData.module] - fun getSession(moduleInfo: ModuleInfo): FirSession? = - sessions[moduleInfo] + fun getSession(module: KtModule): FirSession? = + sessions[module] - internal fun getModuleCache(moduleSourceInfo: ModuleSourceInfoBase): ModuleFileCache = - (sessions.getValue(moduleSourceInfo) as FirIdeSourcesSession).cache + internal fun getModuleCache(module: KtSourceModule): ModuleFileCache = + (sessions.getValue(module) as FirIdeSourcesSession).cache } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt index 24223f8ab5b..9d710313885 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt @@ -5,34 +5,30 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions -import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import kotlinx.collections.immutable.PersistentMap import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toPersistentMap import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.moduleData -import org.jetbrains.kotlin.fir.session.FirModuleInfoBasedModuleData -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveStateConfigurator import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor import org.jetbrains.kotlin.analysis.low.level.api.fir.util.* import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeWithoutPCE +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import java.util.concurrent.ConcurrentHashMap class FirIdeSessionProviderStorage(val project: Project) { - private val sessionsCache = ConcurrentHashMap() - private val configurator = ServiceManager.getService(project, FirModuleResolveStateConfigurator::class.java) + private val sessionsCache = ConcurrentHashMap() private val librariesCache by cachedValue(project, project.createLibrariesModificationTracker()) { LibrariesCache() } fun getSessionProvider( - rootModule: ModuleSourceInfoBase, + rootModule: KtSourceModule, configureSession: (FirIdeSession.() -> Unit)? = null ): FirIdeSessionProvider { val firPhaseRunner = FirPhaseRunner() @@ -41,11 +37,10 @@ class FirIdeSessionProviderStorage(val project: Project) { val builtinsAndCloneableSession = FirIdeSessionFactory.createBuiltinsAndCloneableSession(project, builtinTypes) val cache = sessionsCache.getOrPut(rootModule) { FromModuleViewSessionCache(rootModule) } val (sessions, session) = cache.withMappings(project) { mappings -> - val sessions = mutableMapOf().apply { putAll(mappings) } + val sessions = mutableMapOf().apply { putAll(mappings) } val session = executeWithoutPCE { FirIdeSessionFactory.createSourcesSession( project, - configurator, rootModule, builtinsAndCloneableSession, firPhaseRunner, @@ -53,7 +48,7 @@ class FirIdeSessionProviderStorage(val project: Project) { builtinTypes, sessions, isRootModule = true, - librariesCache, + librariesCache = librariesCache, configureSession = configureSession, ) } @@ -65,32 +60,32 @@ class FirIdeSessionProviderStorage(val project: Project) { } private class FromModuleViewSessionCache( - val root: ModuleSourceInfoBase, + val root: KtSourceModule, ) { @Volatile - private var mappings: PersistentMap = persistentMapOf() + private var mappings: PersistentMap = persistentMapOf() val sessionInvalidator: FirSessionInvalidator = FirSessionInvalidator { session -> - mappings[session.moduleData.moduleSourceInfo]?.invalidate() + mappings[session.moduleData.module]?.invalidate() } inline fun withMappings( project: Project, - action: (Map) -> Pair, R> - ): Pair, R> { + action: (Map) -> Pair, R> + ): Pair, R> { val (newMappings, result) = action(getSessions().mapValues { it.value }) mappings = newMappings.mapValues { FirSessionWithModificationTracker(project, it.value) }.toPersistentMap() return newMappings to result } @OptIn(ExperimentalStdlibApi::class) - private fun getSessions(): Map = buildMap { + private fun getSessions(): Map = buildMap { val sessions = mappings.values val wasSessionInvalidated = sessions.associateWithTo(hashMapOf()) { false } val reversedDependencies = sessions.reversedDependencies { session -> - session.firSession.dependencies.mapNotNull { mappings[it] } + session.firSession.module.directRegularDependencies.mapNotNull { mappings[it] } } fun markAsInvalidWithDfs(session: FirSessionWithModificationTracker) { @@ -111,7 +106,7 @@ private class FromModuleViewSessionCache( } return wasSessionInvalidated.entries .mapNotNull { (session, wasInvalidated) -> session.takeUnless { wasInvalidated } } - .associate { session -> session.firSession.moduleData.moduleSourceInfo to session.firSession } + .associate { session -> session.firSession.moduleData.module to session.firSession } } private fun Collection.reversedDependencies(getDependencies: (T) -> List): Map> { @@ -130,7 +125,7 @@ private class FirSessionWithModificationTracker( val firSession: FirIdeSourcesSession, ) { private val modificationTracker = - firSession.moduleData.moduleSourceInfo.createModuleWithoutDependenciesOutOfBlockModificationTracker(project) + firSession.moduleData.module.createModuleWithoutDependenciesOutOfBlockModificationTracker(project) private val timeStamp = modificationTracker.modificationCount @@ -144,8 +139,7 @@ private class FirSessionWithModificationTracker( val isValid: Boolean get() = !isInvalidated && modificationTracker.modificationCount == timeStamp } -val FirModuleData.moduleSourceInfo: ModuleSourceInfoBase - get() = moduleInfoUnsafe() +internal val FirModuleData.module: KtSourceModule get() = moduleUnsafe() -inline fun FirModuleData.moduleInfoUnsafe(): T = (this as FirModuleInfoBasedModuleData).moduleInfo as T -inline fun FirModuleData.moduleInfoSafe(): T? = (this as FirModuleInfoBasedModuleData).moduleInfo as? T +internal inline fun FirModuleData.moduleUnsafe(): T = (this as KtModuleBasedModuleData).module as T +internal inline fun FirModuleData.moduleInfoSafe(): T? = (this as KtModuleBasedModuleData).module as? T diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt index e04bb4752c8..3ff8d2b2440 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt @@ -7,17 +7,17 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase -import org.jetbrains.kotlin.fir.BuiltinTypes -import org.jetbrains.kotlin.fir.PrivateSessionConstructor import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import org.jetbrains.kotlin.fir.BuiltinTypes +import org.jetbrains.kotlin.fir.PrivateSessionConstructor @OptIn(PrivateSessionConstructor::class) internal class FirIdeSourcesSession @PrivateSessionConstructor constructor( - val dependencies: List, + override val module: KtSourceModule, override val project: Project, - override val scope: GlobalSearchScope, val firFileBuilder: FirFileBuilder, builtinTypes: BuiltinTypes, ) : FirIdeModuleSession(builtinTypes, Kind.Source) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/KtModuleBasedModuleData.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/KtModuleBasedModuleData.kt new file mode 100644 index 00000000000..7c71aaeaa99 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/KtModuleBasedModuleData.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2021 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.analysis.low.level.api.fir.sessions + +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.fir.FirModuleData +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices + +internal class KtModuleBasedModuleData( + val module: KtModule, +) : FirModuleData() { + override val name: Name get() = Name.special("<${module.moduleDescription}>") + + override val dependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + module.directRegularDependencies.map(::KtModuleBasedModuleData) + } + + override val dependsOnDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + module.directRefinementDependencies.map(::KtModuleBasedModuleData) + } + + override val friendDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + module.directRefinementDependencies.map(::KtModuleBasedModuleData) + } + + override val platform: TargetPlatform get() = module.platform + + override val analyzerServices: PlatformDependentAnalyzerServices get() = module.analyzerServices +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt index a9e8a23aa3e..a1f397c71c6 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt @@ -5,11 +5,16 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import java.util.concurrent.ConcurrentHashMap @JvmInline -internal value class LibrariesCache(private val cache: ConcurrentHashMap = ConcurrentHashMap()) { - fun cached(moduleSourceInfo: ModuleSourceInfoBase, create: (ModuleSourceInfoBase) -> FirIdeLibrariesSession): FirIdeLibrariesSession = +internal value class LibrariesCache( + private val cache: ConcurrentHashMap = ConcurrentHashMap() +) { + fun cached( + moduleSourceInfo: KtSourceModule, + create: (KtSourceModule) -> FirIdeLibrariesSession + ): FirIdeLibrariesSession = cache.computeIfAbsent(moduleSourceInfo, create) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt index 568ced65ad2..a61b2df85d9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt @@ -12,7 +12,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.util.* -import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.cfg.containingDeclarationForPseudocode import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.FirDeclaration @@ -89,16 +88,6 @@ internal val FirDeclaration.containingKtFileIfAny: KtFile? get() = psi?.containingFile as? KtFile -internal fun ModuleInfo.collectTransitiveDependenciesWithSelf(): List { - val result = mutableSetOf() - fun collect(module: ModuleInfo) { - if (module in result) return - result += module - module.dependencies().forEach(::collect) - } - collect(this) - return result.toList() -} internal fun KtDeclaration.isNonAnonymousClassOrObject() = this is KtClassOrObject diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTest.kt index 0e01cc887b7..5f099ef758b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTest.kt @@ -9,18 +9,28 @@ import com.intellij.mock.MockProject import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer +import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementFinder import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.ProjectScope +import org.jetbrains.kotlin.analysis.api.InvalidWayOfUsingAnalysisSession +import org.jetbrains.kotlin.analysis.api.KtAnalysisSessionProvider +import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.FirIdeResolveStateService +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirSealedClassInheritorsProcessorFactory +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.PackagePartProviderFactory +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile +import org.jetbrains.kotlin.analysis.low.level.api.fir.createResolveStateForNoCaching +import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.SealedClassInheritorsProviderTestImpl +import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirLazyTransformerForIDE +import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory -import org.jetbrains.kotlin.analysis.providers.KotlinModuleInfoProvider import org.jetbrains.kotlin.analysis.providers.KotlinPackageProviderFactory import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticDeclarationProviderFactory import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticModificationTrackerFactory import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticPackageProviderFactory -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleSourceInfoBase import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.finder.JavaElementFinder import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM @@ -28,18 +38,7 @@ import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.fir.DependencyListForCliModule -import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider -import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider -import org.jetbrains.kotlin.fir.session.FirModuleInfoBasedModuleData -import org.jetbrains.kotlin.analysis.low.level.api.fir.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.SealedClassInheritorsProviderTestImpl -import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirLazyTransformerForIDE -import org.jetbrains.kotlin.analysis.api.InvalidWayOfUsingAnalysisSession -import org.jetbrains.kotlin.analysis.api.KtAnalysisSessionProvider -import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider import org.jetbrains.kotlin.light.classes.symbol.IDEKotlinAsJavaFirSupport import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.name.Name @@ -59,9 +58,13 @@ import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices import org.jetbrains.kotlin.test.model.* import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest import org.jetbrains.kotlin.test.services.* +import org.jetbrains.kotlin.utils.addIfNotNull import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInfo +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths abstract class AbstractCompilerBasedTest : AbstractKotlinCompilerTest() { private var _disposable: Disposable? = null @@ -88,7 +91,7 @@ abstract class AbstractCompilerBasedTest : AbstractKotlinCompilerTest() { configureTest() defaultConfiguration(this) - useAdditionalService(::TestModuleInfoProvider) + useAdditionalService(::TestKtModuleProvider) usePreAnalysisHandlers(::ModuleRegistrarPreAnalysisHandler.bind(disposable)) } @@ -103,8 +106,8 @@ abstract class AbstractCompilerBasedTest : AbstractKotlinCompilerTest() { get() = listOf(FirDiagnosticsDirectives) override fun analyze(module: TestModule): FirOutputArtifact { - val moduleInfoProvider = testServices.moduleInfoProvider - val moduleInfo = moduleInfoProvider.getModuleInfo(module.name) + val moduleInfoProvider = testServices.projectModuleProvider + val moduleInfo = moduleInfoProvider.getModule(module.name) val project = testServices.compilerConfigurationProvider.getProject(module) val resolveState = createResolveStateForNoCaching(moduleInfo, project) @@ -148,30 +151,32 @@ abstract class AbstractCompilerBasedTest : AbstractKotlinCompilerTest() { } -class TestModuleInfoProvider(private val testServices: TestServices) : TestService { - private val cache = mutableMapOf() +class TestProjectModuleProvider( + private val testServices: TestServices +) : TestService { + private val cache = mutableMapOf() - fun registerModuleInfo(testModule: TestModule, ktFiles: Map) { - cache[testModule.name] = TestModuleSourceInfo(testModule, ktFiles, testServices) + fun registerModuleInfo(project: Project, testModule: TestModule, ktFiles: Map) { + cache[testModule.name] = TestSourceProjectModule(project, testModule, ktFiles, testServices) } - fun getModuleInfoByKtFile(ktFile: KtFile): TestModuleSourceInfo = + fun getModuleInfoByKtFile(ktFile: KtFile): TestSourceProjectModule = cache.values.first { moduleSourceInfo -> ktFile in moduleSourceInfo.ktFiles } - fun getModuleInfo(moduleName: String): TestModuleSourceInfo = + fun getModule(moduleName: String): TestSourceProjectModule = cache.getValue(moduleName) } -val TestServices.moduleInfoProvider: TestModuleInfoProvider by TestServices.testServiceAccessor() +val TestServices.projectModuleProvider: TestProjectModuleProvider by TestServices.testServiceAccessor() class ModuleRegistrarPreAnalysisHandler( testServices: TestServices, private val parentDisposable: Disposable ) : PreAnalysisHandler(testServices) { - private val moduleInfoProvider = testServices.moduleInfoProvider + private val moduleInfoProvider = testServices.projectModuleProvider override fun preprocessModuleStructure(moduleStructure: TestModuleStructure) { // todo rework after all modules will have the same Project instance @@ -184,42 +189,65 @@ class ModuleRegistrarPreAnalysisHandler( ktFilesByModule.forEach { (testModule, ktFiles) -> val project = testServices.compilerConfigurationProvider.getProject(testModule) - moduleInfoProvider.registerModuleInfo(testModule, ktFiles) - - val configurator = FirModuleResolveStateConfiguratorForSingleModuleTestImpl( - project, - testServices, - parentDisposable - ) - (project as MockProject).registerTestServices(configurator, allKtFiles, testServices) + moduleInfoProvider.registerModuleInfo(project, testModule, ktFiles) + (project as MockProject).registerTestServices(testModule, allKtFiles, testServices) } } } -class TestModuleSourceInfo( +@OptIn(ExperimentalStdlibApi::class) +class TestSourceProjectModule( + private val project: Project, val testModule: TestModule, val testFilesToKtFiles: Map, testServices: TestServices, -) : ModuleInfo, ModuleSourceInfoBase { - private val moduleInfoProvider = testServices.moduleInfoProvider +) : SourceProjectModule { + private val moduleProvider = testServices.projectModuleProvider + private val compilerConfigurationProvider = testServices.compilerConfigurationProvider + private val configuration = compilerConfigurationProvider.getCompilerConfiguration(testModule) + val ktFiles = testFilesToKtFiles.values.toSet() - val moduleData = FirModuleInfoBasedModuleData(this) - override val name: Name - get() = Name.identifier(testModule.name) + override val name: Name get() = Name.identifier(testModule.name) - override fun dependencies(): List = - testModule.allDependencies - .map { moduleInfoProvider.getModuleInfo(it.moduleName) } + override val regularDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + buildList { + testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) } + addIfNotNull( + libraryByRoots( + (configuration.jvmModularRoots + configuration.jvmClasspathRoots).map(File::toPath) + ) + ) + } + } + override val dependsOnDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + testModule.dependsOnDependencies + .map { moduleProvider.getModule(it.moduleName) } + } + override val friendDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + buildList { + testModule.friendDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) } + addIfNotNull( + libraryByRoots(configuration[JVMConfigurationKeys.FRIEND_PATHS].orEmpty().map(Paths::get)) + ) + } + } - override val expectedBy: List - get() = testModule.dependsOnDependencies - .map { moduleInfoProvider.getModuleInfo(it.moduleName) } + private fun libraryByRoots(roots: List): LibraryByRoots? { + if (roots.isEmpty()) return null + return LibraryByRoots( + roots, + this@TestSourceProjectModule, + project + ) + } - override fun modulesWhoseInternalsAreVisible(): Collection = - testModule.friendDependencies - .map { moduleInfoProvider.getModuleInfo(it.moduleName) } + override val searchScope: GlobalSearchScope = + TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, testFilesToKtFiles.values) + + override val languageVersionSettings: LanguageVersionSettings + get() = testModule.languageVersionSettings override val platform: TargetPlatform get() = testModule.targetPlatform @@ -228,72 +256,53 @@ class TestModuleSourceInfo( get() = testModule.targetPlatform.getAnalyzerServices() } - -class FirModuleResolveStateConfiguratorForSingleModuleTestImpl( +private class LibraryByRoots( + private val roots: List, + private val sourceModule: SourceProjectModule, private val project: Project, - testServices: TestServices, - private val parentDisposable: Disposable, -) : FirModuleResolveStateConfigurator() { - private val compilerConfigurationProvider = testServices.compilerConfigurationProvider - private val librariesScope = ProjectScope.getLibrariesScope(project)//todo incorrect? - private val sealedClassInheritorsProvider = SealedClassInheritorsProviderTestImpl() - - override fun createPackagePartsProvider(moduleInfo: ModuleSourceInfoBase, scope: GlobalSearchScope): PackagePartProvider { - require(moduleInfo is TestModuleSourceInfo) - val factory = compilerConfigurationProvider.getPackagePartProviderFactory(moduleInfo.testModule) - return factory(scope) - } - - - override fun createModuleDataProvider(moduleInfo: ModuleSourceInfoBase): ModuleDataProvider { - require(moduleInfo is TestModuleSourceInfo) - val configuration = compilerConfigurationProvider.getCompilerConfiguration(moduleInfo.testModule) - return DependencyListForCliModule.build( - moduleInfo.name, - moduleInfo.platform, - moduleInfo.analyzerServices - ) { - dependencies(configuration.jvmModularRoots.map { it.toPath() }) - dependencies(configuration.jvmClasspathRoots.map { it.toPath() }) - - friendDependencies(configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList()) - - sourceDependencies(moduleInfo.moduleData.dependencies) - sourceFriendsDependencies(moduleInfo.moduleData.friendDependencies) - sourceDependsOnDependencies(moduleInfo.moduleData.dependsOnDependencies) - }.moduleDataProvider - } - - override fun getLanguageVersionSettings(moduleInfo: ModuleSourceInfoBase): LanguageVersionSettings { - require(moduleInfo is TestModuleSourceInfo) - return moduleInfo.testModule.languageVersionSettings - } - - override fun getModuleSourceScope(moduleInfo: ModuleSourceInfoBase): GlobalSearchScope { - require(moduleInfo is TestModuleSourceInfo) - return TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, moduleInfo.testFilesToKtFiles.values) - } - - override fun createScopeForModuleLibraries(moduleInfo: ModuleSourceInfoBase): GlobalSearchScope { - return librariesScope - } - - override fun createSealedInheritorsProvider(): SealedClassInheritorsProvider { - return sealedClassInheritorsProvider - } - - override fun configureSourceSession(session: FirSession) { - } +) : LibraryProjectModule { + override val name: Name get() = Name.special("") + override val regularDependencies: List get() = emptyList() + override val dependsOnDependencies: List get() = emptyList() + override val friendDependencies: List get() = emptyList() + override val searchScope: GlobalSearchScope get() = ProjectScope.getLibrariesScope(project) + override val platform: TargetPlatform get() = sourceModule.platform + override val analyzerServices: PlatformDependentAnalyzerServices get() = sourceModule.analyzerServices + override fun getBinaryRoots(): Collection = roots } fun MockProject.registerTestServices( - configurator: FirModuleResolveStateConfiguratorForSingleModuleTestImpl, + testModule: TestModule, allKtFiles: List, testServices: TestServices, ) { registerService( - FirModuleResolveStateConfigurator::class.java, - configurator + PackagePartProviderFactory::class.java, + object : PackagePartProviderFactory() { + override fun createPackagePartProvider(scope: GlobalSearchScope): PackagePartProvider { + val factory = testServices.compilerConfigurationProvider.getPackagePartProviderFactory(testModule) + return factory(scope) + } + } + ) + registerService( + FirSealedClassInheritorsProcessorFactory::class.java, + object : FirSealedClassInheritorsProcessorFactory() { + override fun createSealedClassInheritorsProvider(): SealedClassInheritorsProvider { + return SealedClassInheritorsProviderTestImpl() + } + } + ) + registerService( + ProjectModuleScopeProvider::class.java, + object : ProjectModuleScopeProvider() { + override fun getModuleLibrariesScope(sourceModule: SourceProjectModule): GlobalSearchScope { + val libraries = sourceModule.dependenciesOfType() + val scopes = libraries.map { it.searchScope }.toList() + if (scopes.isEmpty()) return GlobalSearchScope.EMPTY_SCOPE + return GlobalSearchScope.union(scopes) + } + } ) registerService(FirIdeResolveStateService::class.java) registerService( @@ -302,17 +311,16 @@ fun MockProject.registerTestServices( ) registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(allKtFiles)) registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(allKtFiles)) - registerService(KotlinModuleInfoProvider::class.java, TestKotlinModuleInfoProvider(testServices)) + registerService(ProjectStructureProvider::class.java, TestKotlinProjectStructureProvider(testServices)) reRegisterJavaElementFinder(this) } -private class TestKotlinModuleInfoProvider(testServices: TestServices): KotlinModuleInfoProvider() { - private val moduleInfoProvider = testServices.moduleInfoProvider - override fun getModuleInfo(element: KtElement): ModuleInfo { - val containingFile = element.containingKtFile +private class TestKotlinProjectStructureProvider(testServices: TestServices) : ProjectStructureProvider() { + private val moduleInfoProvider = testServices.projectModuleProvider + override fun getProjectModuleForKtElement(element: PsiElement): ProjectModule { + val containingFile = element.containingFile as KtFile return moduleInfoProvider.getModuleInfoByKtFile(containingFile) } - } @OptIn(InvalidWayOfUsingAnalysisSession::class) diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestProjectModuleProvider.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestProjectModuleProvider.kt new file mode 100644 index 00000000000..019ef71e729 --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestProjectModuleProvider.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2021 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.analysis.low.level.api.fir.compiler.based + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.model.TestFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestService +import org.jetbrains.kotlin.test.services.TestServices + +class TestKtModuleProvider( + private val testServices: TestServices +) : TestService { + private val cache = mutableMapOf() + + fun registerModuleInfo(project: Project, testModule: TestModule, ktFiles: Map) { + cache[testModule.name] = TestKtSourceModule(project, testModule, ktFiles, testServices) + } + + internal fun getModuleInfoByKtFile(ktFile: KtFile): TestKtSourceModule = + cache.values.first { moduleSourceInfo -> + ktFile in moduleSourceInfo.ktFiles + } + + internal fun getModule(moduleName: String): TestKtSourceModule = + cache.getValue(moduleName) +} + +val TestServices.projectModuleProvider: TestKtModuleProvider by TestServices.testServiceAccessor() diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestSourceSetProjectModule.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestSourceSetProjectModule.kt new file mode 100644 index 00000000000..7b713746209 --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/TestSourceSetProjectModule.kt @@ -0,0 +1,109 @@ +/* + * Copyright 2010-2021 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.analysis.low.level.api.fir.compiler.based + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.ProjectScope +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM +import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots +import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices +import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices +import org.jetbrains.kotlin.test.model.TestFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.compilerConfigurationProvider +import org.jetbrains.kotlin.utils.addIfNotNull +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths + +@OptIn(ExperimentalStdlibApi::class) +internal class TestKtSourceModule( + override val project: Project, + val testModule: TestModule, + val testFilesToKtFiles: Map, + testServices: TestServices, +) : KtSourceModule { + private val moduleProvider = testServices.projectModuleProvider + private val compilerConfigurationProvider = testServices.compilerConfigurationProvider + private val configuration = compilerConfigurationProvider.getCompilerConfiguration(testModule) + + val ktFiles = testFilesToKtFiles.values.toSet() + + override val moduleName: String + get() = testModule.name + + override val directRegularDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + buildList { + testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) } + addIfNotNull( + libraryByRoots( + (configuration.jvmModularRoots + configuration.jvmClasspathRoots).map(File::toPath) + ) + ) + } + } + override val directRefinementDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + testModule.dependsOnDependencies + .map { moduleProvider.getModule(it.moduleName) } + } + override val directFriendDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + buildList { + testModule.friendDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) } + addIfNotNull( + libraryByRoots(configuration[JVMConfigurationKeys.FRIEND_PATHS].orEmpty().map(Paths::get)) + ) + } + } + + private fun libraryByRoots(roots: List): LibraryByRoots? { + if (roots.isEmpty()) return null + return LibraryByRoots( + roots, + this@TestKtSourceModule, + project, + ) + } + + override val contentScope: GlobalSearchScope = + TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, testFilesToKtFiles.values) + + override val languageVersionSettings: LanguageVersionSettings + get() = testModule.languageVersionSettings + + override val platform: TargetPlatform + get() = testModule.targetPlatform + + override val analyzerServices: PlatformDependentAnalyzerServices + get() = testModule.targetPlatform.getAnalyzerServices() +} + +private class LibraryByRoots( + private val roots: List, + private val sourceModule: KtSourceModule, + override val project: Project, +) : KtLibraryModule { + override val libraryName: String get() = "Test Library" + override val directRegularDependencies: List get() = emptyList() + override val directRefinementDependencies: List get() = emptyList() + override val directFriendDependencies: List get() = emptyList() + override val contentScope: GlobalSearchScope get() = ProjectScope.getLibrariesScope(project) + override val platform: TargetPlatform get() = sourceModule.platform + override val analyzerServices: PlatformDependentAnalyzerServices get() = sourceModule.analyzerServices + override fun getBinaryRoots(): Collection = roots + override val librarySources: KtLibrarySourceModule? get() = null +} + diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/testServices.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/testServices.kt new file mode 100644 index 00000000000..ef470a09558 --- /dev/null +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/testServices.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-2021 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.analysis.low.level.api.fir.compiler.based + +import com.intellij.mock.MockProject +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementFinder +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.api.InvalidWayOfUsingAnalysisSession +import org.jetbrains.kotlin.analysis.api.KtAnalysisSessionProvider +import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.FirIdeResolveStateService +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.PackagePartProviderFactory +import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.SealedClassInheritorsProviderTestImpl +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtModuleScopeProvider +import org.jetbrains.kotlin.analysis.project.structure.KtModuleScopeProviderImpl +import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory +import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory +import org.jetbrains.kotlin.analysis.providers.KotlinPackageProviderFactory +import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticDeclarationProviderFactory +import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticModificationTrackerFactory +import org.jetbrains.kotlin.analysis.providers.impl.KotlinStaticPackageProviderFactory +import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport +import org.jetbrains.kotlin.asJava.finder.JavaElementFinder +import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider +import org.jetbrains.kotlin.light.classes.symbol.IDEKotlinAsJavaFirSupport +import org.jetbrains.kotlin.load.kotlin.PackagePartProvider +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.test.model.TestModule +import org.jetbrains.kotlin.test.services.TestServices +import org.jetbrains.kotlin.test.services.compilerConfigurationProvider + +fun MockProject.registerTestServices( + testModule: TestModule, + allKtFiles: List, + testServices: TestServices, +) { + registerService( + PackagePartProviderFactory::class.java, + TestPackagePartProvider(testServices, testModule) + ) + registerService( + FirSealedClassInheritorsProcessorFactory::class.java, + TestFirSealedClassInheritorsProcessorFactory() + ) + registerService(KtModuleScopeProvider::class.java, KtModuleScopeProviderImpl()) + registerService(FirIdeResolveStateService::class.java) + registerService( + KotlinModificationTrackerFactory::class.java, + KotlinStaticModificationTrackerFactory::class.java + ) + registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(allKtFiles)) + registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(allKtFiles)) + registerService(ProjectStructureProvider::class.java, TestKotlinProjectStructureProvider(testServices)) + reRegisterJavaElementFinder(this) +} + +class TestFirSealedClassInheritorsProcessorFactory : FirSealedClassInheritorsProcessorFactory() { + override fun createSealedClassInheritorsProvider(): SealedClassInheritorsProvider { + return SealedClassInheritorsProviderTestImpl() + } +} + +private class TestPackagePartProvider( + private val testServices: TestServices, + private val testModule: TestModule +) : PackagePartProviderFactory() { + override fun createPackagePartProviderForLibrary(scope: GlobalSearchScope): PackagePartProvider { + val factory = testServices.compilerConfigurationProvider.getPackagePartProviderFactory(testModule) + return factory(scope) + } +} + +private class TestKotlinProjectStructureProvider(testServices: TestServices) : ProjectStructureProvider() { + private val moduleInfoProvider = testServices.projectModuleProvider + override fun getKtModuleForKtElement(element: PsiElement): KtModule { + val containingFile = element.containingFile as KtFile + return moduleInfoProvider.getModuleInfoByKtFile(containingFile) + } +} + +@OptIn(InvalidWayOfUsingAnalysisSession::class) +private fun reRegisterJavaElementFinder(project: Project) { + PsiElementFinder.EP.getPoint(project).unregisterExtension(JavaElementFinder::class.java) + with(project as MockProject) { + picoContainer.registerComponentInstance( + KtAnalysisSessionProvider::class.qualifiedName, + KtFirAnalysisSessionProvider(this) + ) + picoContainer.unregisterComponent(KotlinAsJavaSupport::class.qualifiedName) + picoContainer.registerComponentInstance( + KotlinAsJavaSupport::class.qualifiedName, + IDEKotlinAsJavaFirSupport(project) + ) + } + @Suppress("DEPRECATION") + PsiElementFinder.EP.getPoint(project).registerExtension(JavaElementFinder(project)) +} diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt index 0fd686dfad2..cc8580b15e1 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.providers.getModuleInfo import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.declarations.FirDeclaration @@ -19,6 +18,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFileSymbol import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSession +import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.psi.KtElement internal fun Project.allModules() = ModuleManager.getInstance(this).modules.toList() @@ -43,6 +43,7 @@ internal inline fun resolveWithClearCaches( noinline configureSession: FirIdeSession.() -> Unit = {}, action: (FirModuleResolveState) -> R, ): R { - val resolveState = createResolveStateForNoCaching(context.getModuleInfo(), context.project, configureSession) + val project = context.project + val resolveState = createResolveStateForNoCaching(context.getKtModule(project), project, configureSession) return action(resolveState) } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AbstractLowLevelApiTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AbstractLowLevelApiTest.kt index e62b7a58924..a75591dc972 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AbstractLowLevelApiTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AbstractLowLevelApiTest.kt @@ -10,12 +10,10 @@ import com.intellij.mock.MockProject import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.util.Disposer import com.intellij.testFramework.TestDataFile -import com.intellij.testFramework.TestDataPath -import org.jetbrains.kotlin.analysis.providers.KotlinModuleInfoProvider import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.ModuleRegistrarPreAnalysisHandler -import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.TestModuleInfoProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.moduleInfoProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.TestKtModuleProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.projectModuleProvider import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.TestInfrastructureInternals @@ -59,7 +57,7 @@ abstract class AbstractLowLevelApiTest : TestWithDisposable() { useSourcePreprocessor(::ExpressionMarkersSourceFilePreprocessor) useAdditionalService { ExpressionMarkerProvider() } - useAdditionalService(::TestModuleInfoProvider) + useAdditionalService(::TestKtModuleProvider) usePreAnalysisHandlers(::ModuleRegistrarPreAnalysisHandler.bind(disposable)) configureTest(this) @@ -94,9 +92,9 @@ abstract class AbstractLowLevelApiTest : TestWithDisposable() { val singleModule = moduleStructure.modules.single() val project = testServices.compilerConfigurationProvider.getProject(singleModule) - val moduleInfoProvider = testServices.moduleInfoProvider + val moduleInfoProvider = testServices.projectModuleProvider - val moduleInfo = moduleInfoProvider.getModuleInfo(singleModule.name) + val moduleInfo = moduleInfoProvider.getModule(singleModule.name) with(project as MockProject) { registerServicesForProject(this) diff --git a/analysis/project-structure/build.gradle.kts b/analysis/project-structure/build.gradle.kts new file mode 100644 index 00000000000..10dfd2ac8d7 --- /dev/null +++ b/analysis/project-structure/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + kotlin("jvm") + id("jps-compatible") +} + +dependencies { + implementation(project(":core:compiler.common")) + implementation(project(":compiler:util")) + implementation(project(":compiler:psi")) + implementation(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) } +} + +kotlin { + explicitApi() +} + +tasks.withType().configureEach { + kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.ExperimentalStdlibApi" +} + +sourceSets { + "main" { projectDefault() } +} diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt new file mode 100644 index 00000000000..23cd4030a6a --- /dev/null +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModule.kt @@ -0,0 +1,159 @@ +/* + * Copyright 2010-2021 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.analysis.project.structure + +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices +import java.nio.file.Path + +/** + * Represents a module inside a project. + * + * [KtModule] is a Source Set (or considering a new project model naming a Fragment). + * Some examples of a module: main source set, test source set, library, JDK. + * + */ +public sealed interface KtModule { + /** + * A list of Regular dependencies. Regular dependency allows current module to see symbols from dependent module. + * In a case for a source set, it can be other source set it depends on, library, or SDK. + * + * The dependencies list is non-transitive and should not include current module. + */ + public val directRegularDependencies: List + + /** + * Only for Kotlin MPP project. + * A list of Refinement dependencies. + * Refinement dependency express that the current module can provide actual declarations for expect declarations from dependent module, + * as well as see internal symbols of dependent module. + * + * The dependencies list is non-transitive and should not include current module. + */ + public val directRefinementDependencies: List + + /** + * A list of Friend dependencies. Friend dependencies express that current module may see internal symbols of dependent module. + * + * The dependencies list is non-transitive and should not include current module. + */ + public val directFriendDependencies: List + + /** + * A [GlobalSearchScope] which belongs to a module content. + * + * Contract: `module.contentScope.contains(file) <=> file belongs to this module` + */ + public val contentScope: GlobalSearchScope + + /** + * A platform (e.g, JVM, JS, Native) current module represents. + * + * @see [TargetPlatform] + */ + public val platform: TargetPlatform + + public val analyzerServices: PlatformDependentAnalyzerServices + + /** + * [Project] to which module belongs. + * If current module depends on some other modules, all those modules should have the same [Project] as the current one. + */ + public val project: Project? + + /** + * Human-readable description of the module. E.g, "main sources of module 'analysis-api'" + */ + public val moduleDescription: String +} + +public sealed interface KtModuleWithProject : KtModule { + override val project: Project +} + +/** + * A module which consists of a set of source declarations inside a projects. + * + * Generally, a main or test Source Set. + */ +public interface KtSourceModule : KtModule, KtModuleWithProject { + public val moduleName: String + + override val moduleDescription: String + get() = "Sources of $moduleName" + + /** + * A set of Kotlin settings, like API version, supported features and flags. + */ + public val languageVersionSettings: LanguageVersionSettings +} + +/** + * A module which consists of binary declarations. + */ +public sealed interface KtBinaryModule : KtModule, KtModuleWithProject { + /** + * A list of binary files which forms a binary module. It can be a list of JARs, KLIBs, folders with .class files. + * Should be consistent with [contentScope], + * so (pseudo-Kotlin) ` + * ``` + * library.contentScope.contains(file) <=> library.getBinaryRoots().listRecursively().contains(file) + * ``` + */ + public fun getBinaryRoots(): Collection +} + +/** + * A module which represents a binary library. E.g, JAR o KLIB. + */ +public interface KtLibraryModule : KtBinaryModule { + public val libraryName: String + + /** + * A library source, if any. If current module is a binary JAR, then [librarySources] corresponds to the sources JAR. + */ + public val librarySources: KtLibrarySourceModule? + + override val moduleDescription: String + get() = "Library $libraryName" +} + +/** + * A module which represent some SDK. E.g, Java JDK. + */ +public interface KtSdkModule : KtBinaryModule { + public val sdkName: String + + override val moduleDescription: String + get() = "SDK $sdkName" +} + +/** + * A sources for some [KtLibraryModule] + */ +public interface KtLibrarySourceModule : KtModuleWithProject { + public val libraryName: String + + /** + * A library binary corresponding to the current library source. + * If current module is a source JAR, then [binaryLibrary] is corresponds to the binaries JAR. + */ + public val binaryLibrary: KtLibraryModule + + override val moduleDescription: String + get() = "Library sourced of $libraryName" +} + +/** + * A set of sources which lives outside project content root. E.g, testdata files or source files of some other project. + */ +public interface KtNotUnderContentRootModule : KtModule { + override val project: Project? + get() = null +} diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModuleScopeProvider.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModuleScopeProvider.kt new file mode 100644 index 00000000000..e1c65d3df37 --- /dev/null +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/KtModuleScopeProvider.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2021 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.analysis.project.structure + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope + +public abstract class KtModuleScopeProvider { + /** + * Get a scope of binaries on which current source module depends. + * Should be equivalent to + * + * ``` + * GlobalSearchScope.union( + * sourceModule.allDependenciesOfType() + * .map { it.contentScope } + * ) + * ``` + * For the IDE there can be more optimal implementations. + * + * See [KtModuleScopeProviderImpl] a correct but non-optimal implementation. + */ + public abstract fun getModuleLibrariesScope(sourceModule: KtSourceModule): GlobalSearchScope +} + +public class KtModuleScopeProviderImpl : KtModuleScopeProvider() { + override fun getModuleLibrariesScope(sourceModule: KtSourceModule): GlobalSearchScope { + val scopes = sourceModule.allDirectDependenciesOfType() + .map { it.contentScope } + .toList() + if (scopes.isEmpty()) return GlobalSearchScope.EMPTY_SCOPE + return GlobalSearchScope.union(scopes) + } +} + +public val Project.moduleScopeProvider: KtModuleScopeProvider + get() = ServiceManager.getService(this, KtModuleScopeProvider::class.java) diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt new file mode 100644 index 00000000000..f02966a4aa9 --- /dev/null +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2021 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.analysis.project.structure + +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement + +public abstract class ProjectStructureProvider { + /** + * For a given [PsiElement] get a [KtModule] to which [PsiElement] belongs. + */ + public abstract fun getKtModuleForKtElement(element: PsiElement): KtModule +} + +/** + * For a given [PsiElement] get a [KtModule] to which [PsiElement] belongs. + * @param project [Project] which contains current [PsiElement]. `PsiElement.project` may be a heavy operation as it includes PSI tree traversal. So, when a [Project] is already available, it is better to pass it explicitly + */ +public fun PsiElement.getKtModule(project: Project = this.project): KtModule = + project.getService(ProjectStructureProvider::class.java) + .getKtModuleForKtElement(this) + +/** + * For a given [PsiElement] get a [KtModule] to which [PsiElement] belongs. + * @return [KtModule] of type [M] if `result <: M`, [java.lang.ClassCastException] otherwise + * @param project [Project] which contains current [PsiElement]. `PsiElement.project` may be a heavy operation as it includes PSI tree traversal. So, when a [Project] is already available, it is better to pass it explicitly + */ +public inline fun PsiElement.getKtModuleOfType(project: Project = this.project): M = + getKtModule(project) as M + +/** + * For a given [PsiElement] get a [KtModule] to which [PsiElement] belongs. + * @return [KtModule] of type [M] if `result <: M`, `null` otherwise + * @param project [Project] which contains current [PsiElement]. `PsiElement.project` may be a heavy operation as it includes PSI tree traversal. So, when a [Project] is already available, it is better to pass it explicitly + */ +public inline fun PsiElement.getKtModuleOfTypeSafe(project: Project = this.project): M? = + getKtModule(project) as M? \ No newline at end of file diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ktModuleUtils.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ktModuleUtils.kt new file mode 100644 index 00000000000..0af0178d9fd --- /dev/null +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ktModuleUtils.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2021 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.analysis.project.structure + +/** + * A list of all modules current module can depend onwith regular dependency + * + * @see KtModule.directRegularDependencies + */ +public inline fun KtModule.directRegularDependenciesOfType(): Sequence = + directRegularDependencies.asSequence().filterIsInstance() + +/** + * A list of all other modules current module can depend on. + * + * @see KtModule.directRegularDependencies + * @see KtModule.directRefinementDependencies + * @see KtModule.directFriendDependencies + */ +public fun KtModule.allDirectDependencies(): Sequence = + sequence { + yieldAll(directRegularDependencies) + yieldAll(directRefinementDependencies) + yieldAll(directFriendDependencies) + } + +/** + * A list of all other modules of type [M] current module can depend on. + * + * @see KtModule.directRegularDependencies + * @see KtModule.directRefinementDependencies + * @see KtModule.directFriendDependencies + */ +public inline fun KtModule.allDirectDependenciesOfType(): Sequence = + allDirectDependencies().filterIsInstance() \ No newline at end of file diff --git a/analysis/symbol-light-classes/build.gradle.kts b/analysis/symbol-light-classes/build.gradle.kts index 6e0c6332572..f772709a547 100644 --- a/analysis/symbol-light-classes/build.gradle.kts +++ b/analysis/symbol-light-classes/build.gradle.kts @@ -10,6 +10,7 @@ dependencies { implementation(project(":compiler:light-classes")) implementation(project(":analysis:analysis-api-providers")) implementation(project(":analysis:analysis-api")) + implementation(project(":analysis:project-structure")) implementation(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) } } diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/IDEKotlinAsJavaFirSupport.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/IDEKotlinAsJavaFirSupport.kt index 79e5cf26efa..b9a2fc9c205 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/IDEKotlinAsJavaFirSupport.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/IDEKotlinAsJavaFirSupport.kt @@ -8,11 +8,12 @@ package org.jetbrains.kotlin.light.classes.symbol import com.intellij.openapi.project.Project import com.intellij.psi.PsiClass import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule +import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule +import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule +import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createPackageProvider -import org.jetbrains.kotlin.analysis.providers.getModuleInfo -import org.jetbrains.kotlin.analyzer.LibraryModuleSourceInfoBase -import org.jetbrains.kotlin.analyzer.NonSourceModuleInfoBase import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.classes.KtFakeLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClass @@ -68,15 +69,15 @@ class IDEKotlinAsJavaFirSupport(private val project: Project) : KotlinAsJavaSupp project.createDeclarationProvider(searchScope).getClassesByClassId(it) }.filter { //TODO Do not return LC came from LibrarySources - when (it.getModuleInfo()) { - is LibraryModuleSourceInfoBase -> it.containingKtFile.isCompiled - is NonSourceModuleInfoBase -> false + when (it.getKtModule(project)) { + is KtLibrarySourceModule -> false + is KtNotUnderContentRootModule -> false else -> true } }.toSet() override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean = - project.createPackageProvider(scope).isPackageExists(fqName) + project.createPackageProvider(scope).doKotlinPackageExists(fqName) override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection = project.createPackageProvider(scope) diff --git a/build.gradle.kts b/build.gradle.kts index 14aa1d76c1e..c17d758bd65 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -319,6 +319,7 @@ extra["compilerArtifactsForIde"] = listOf( ":prepare:ide-plugin-dependencies:high-level-api-fir-for-ide", ":prepare:ide-plugin-dependencies:high-level-api-fir-tests-for-ide", ":prepare:ide-plugin-dependencies:analysis-api-providers-for-ide", + ":prepare:ide-plugin-dependencies:analysis-project-structure-for-ide", ":prepare:ide-plugin-dependencies:symbol-light-classes-for-ide", ":prepare:ide-plugin-dependencies:kotlin-compiler-ir-for-ide", ":prepare:ide-plugin-dependencies:kotlin-compiler-common-for-ide", diff --git a/prepare/ide-plugin-dependencies/analysis-project-structure-for-ide/build.gradle.kts b/prepare/ide-plugin-dependencies/analysis-project-structure-for-ide/build.gradle.kts new file mode 100644 index 00000000000..01b8dad6560 --- /dev/null +++ b/prepare/ide-plugin-dependencies/analysis-project-structure-for-ide/build.gradle.kts @@ -0,0 +1,5 @@ +plugins { + kotlin("jvm") +} + +publishJarsForIde(listOf(":analysis:project-structure")) diff --git a/settings.gradle b/settings.gradle index 0bba1958c9a..13c7da1169a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -329,6 +329,7 @@ if (!buildProperties.inJpsBuildIdeaSync) { ":prepare:ide-plugin-dependencies:high-level-api-fir-for-ide", ":prepare:ide-plugin-dependencies:high-level-api-fir-tests-for-ide", ":prepare:ide-plugin-dependencies:analysis-api-providers-for-ide", + ":prepare:ide-plugin-dependencies:analysis-project-structure-for-ide", ":prepare:ide-plugin-dependencies:symbol-light-classes-for-ide", ":prepare:ide-plugin-dependencies:kotlin-compiler-ir-for-ide", ":prepare:ide-plugin-dependencies:kotlin-compiler-common-for-ide", @@ -449,7 +450,8 @@ include ":generators:analysis-api-generator", ":analysis:analysis-api-fir", ":analysis:analysis-api", ":analysis:analysis-api-providers", - ":analysis:symbol-light-classes" + ":analysis:symbol-light-classes", + ":analysis:project-structure" if (buildProperties.inJpsBuildIdeaSync) {