Analysis API: introduce Project Structure

This commit is contained in:
Ilya Kirillov
2021-09-16 00:21:28 +02:00
parent c9348b3512
commit 678b931ba3
49 changed files with 952 additions and 391 deletions
@@ -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
@@ -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)
}
@@ -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) }
}
@@ -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)
@@ -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)
@@ -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<Name>
}
@@ -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<ModuleSourceInfoBase, SimpleModificationTracker>()
private val forModule = mutableMapOf<KtSourceModule, SimpleModificationTracker>()
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 {
@@ -30,7 +30,7 @@ public class KotlinStaticPackageProvider(
packages
}
override fun isPackageExists(packageFqName: FqName): Boolean {
override fun doKotlinPackageExists(packageFqName: FqName): Boolean {
return packageFqName in packageToSubPackageNames
}
@@ -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"))
@@ -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<ModuleInfo, FirModuleResolveStateImpl>()
ConcurrentHashMap<KtModule, FirModuleResolveStateImpl>()
}
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
)
@@ -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
@@ -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)
)
}
@@ -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.
@@ -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)
@@ -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)
@@ -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,
@@ -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)
}
}
@@ -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
}
@@ -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)
@@ -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()
@@ -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<AbstractDiagnosticCollectorComponent> {
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)
@@ -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 {
@@ -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,
@@ -86,5 +86,5 @@ internal class FirProviderHelper(
}
fun getPackage(fqName: FqName): FqName? =
fqName.takeIf(packageProvider::isPackageExists)
fqName.takeIf(packageProvider::doKotlinPackageExists)
}
@@ -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)
@@ -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
}
@@ -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<ModuleSourceInfoBase, FirIdeSourcesSession>,
sessionsCache: MutableMap<KtSourceModule, FirIdeSourcesSession>,
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<ModuleSourceInfoBase, MutableList<ModuleSourceInfoBase>>(mutableListOf())
val session = FirIdeSourcesSession(dependentModules, project, searchScope, firBuilder, builtinTypes)
sessionsCache[moduleInfo] = session
val contentScope = module.contentScope
val dependentModules = module.directRegularDependenciesOfType<KtSourceModule>()
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<KtModule>.extractLibraryPaths(): List<Path> =
asSequence()
.filterIsInstance<KtBinaryModule>()
.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
@@ -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<ModuleSourceInfoBase, FirIdeSession>
val sessions: Map<KtSourceModule, FirIdeSession>
) : 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
}
@@ -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<ModuleSourceInfoBase, FromModuleViewSessionCache>()
private val configurator = ServiceManager.getService(project, FirModuleResolveStateConfigurator::class.java)
private val sessionsCache = ConcurrentHashMap<KtSourceModule, FromModuleViewSessionCache>()
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<ModuleSourceInfoBase, FirIdeSourcesSession>().apply { putAll(mappings) }
val sessions = mutableMapOf<KtSourceModule, FirIdeSourcesSession>().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<ModuleSourceInfoBase, FirSessionWithModificationTracker> = persistentMapOf()
private var mappings: PersistentMap<KtSourceModule, FirSessionWithModificationTracker> = persistentMapOf()
val sessionInvalidator: FirSessionInvalidator = FirSessionInvalidator { session ->
mappings[session.moduleData.moduleSourceInfo]?.invalidate()
mappings[session.moduleData.module]?.invalidate()
}
inline fun <R> withMappings(
project: Project,
action: (Map<ModuleSourceInfoBase, FirIdeSourcesSession>) -> Pair<Map<ModuleSourceInfoBase, FirIdeSourcesSession>, R>
): Pair<Map<ModuleSourceInfoBase, FirIdeSourcesSession>, R> {
action: (Map<KtSourceModule, FirIdeSourcesSession>) -> Pair<Map<KtSourceModule, FirIdeSourcesSession>, R>
): Pair<Map<KtSourceModule, FirIdeSourcesSession>, 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<ModuleSourceInfoBase, FirIdeSourcesSession> = buildMap {
private fun getSessions(): Map<KtSourceModule, FirIdeSourcesSession> = 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 <T> Collection<T>.reversedDependencies(getDependencies: (T) -> List<T>): Map<T, List<T>> {
@@ -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 <reified T : ModuleInfo> FirModuleData.moduleInfoUnsafe(): T = (this as FirModuleInfoBasedModuleData).moduleInfo as T
inline fun <reified T : ModuleInfo> FirModuleData.moduleInfoSafe(): T? = (this as FirModuleInfoBasedModuleData).moduleInfo as? T
internal inline fun <reified T : KtModule> FirModuleData.moduleUnsafe(): T = (this as KtModuleBasedModuleData).module as T
internal inline fun <reified T : KtModule> FirModuleData.moduleInfoSafe(): T? = (this as KtModuleBasedModuleData).module as? T
@@ -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<ModuleSourceInfoBase>,
override val module: KtSourceModule,
override val project: Project,
override val scope: GlobalSearchScope,
val firFileBuilder: FirFileBuilder,
builtinTypes: BuiltinTypes,
) : FirIdeModuleSession(builtinTypes, Kind.Source) {
@@ -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<FirModuleData> by lazy(LazyThreadSafetyMode.PUBLICATION) {
module.directRegularDependencies.map(::KtModuleBasedModuleData)
}
override val dependsOnDependencies: List<FirModuleData> by lazy(LazyThreadSafetyMode.PUBLICATION) {
module.directRefinementDependencies.map(::KtModuleBasedModuleData)
}
override val friendDependencies: List<FirModuleData> by lazy(LazyThreadSafetyMode.PUBLICATION) {
module.directRefinementDependencies.map(::KtModuleBasedModuleData)
}
override val platform: TargetPlatform get() = module.platform
override val analyzerServices: PlatformDependentAnalyzerServices get() = module.analyzerServices
}
@@ -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<ModuleSourceInfoBase, FirIdeLibrariesSession> = ConcurrentHashMap()) {
fun cached(moduleSourceInfo: ModuleSourceInfoBase, create: (ModuleSourceInfoBase) -> FirIdeLibrariesSession): FirIdeLibrariesSession =
internal value class LibrariesCache(
private val cache: ConcurrentHashMap<KtSourceModule, FirIdeLibrariesSession> = ConcurrentHashMap()
) {
fun cached(
moduleSourceInfo: KtSourceModule,
create: (KtSourceModule) -> FirIdeLibrariesSession
): FirIdeLibrariesSession =
cache.computeIfAbsent(moduleSourceInfo, create)
}
@@ -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<ModuleInfo> {
val result = mutableSetOf<ModuleInfo>()
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
@@ -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<String, TestModuleSourceInfo>()
class TestProjectModuleProvider(
private val testServices: TestServices
) : TestService {
private val cache = mutableMapOf<String, TestSourceProjectModule>()
fun registerModuleInfo(testModule: TestModule, ktFiles: Map<TestFile, KtFile>) {
cache[testModule.name] = TestModuleSourceInfo(testModule, ktFiles, testServices)
fun registerModuleInfo(project: Project, testModule: TestModule, ktFiles: Map<TestFile, KtFile>) {
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<TestFile, KtFile>,
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<ModuleInfo> =
testModule.allDependencies
.map { moduleInfoProvider.getModuleInfo(it.moduleName) }
override val regularDependencies: List<ProjectModule> 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<ProjectModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
testModule.dependsOnDependencies
.map { moduleProvider.getModule(it.moduleName) }
}
override val friendDependencies: List<ProjectModule> 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<ModuleInfo>
get() = testModule.dependsOnDependencies
.map { moduleInfoProvider.getModuleInfo(it.moduleName) }
private fun libraryByRoots(roots: List<Path>): LibraryByRoots? {
if (roots.isEmpty()) return null
return LibraryByRoots(
roots,
this@TestSourceProjectModule,
project
)
}
override fun modulesWhoseInternalsAreVisible(): Collection<ModuleInfo> =
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<Path>,
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("<Libraries>")
override val regularDependencies: List<ProjectModule> get() = emptyList()
override val dependsOnDependencies: List<ProjectModule> get() = emptyList()
override val friendDependencies: List<ProjectModule> 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<Path> = roots
}
fun MockProject.registerTestServices(
configurator: FirModuleResolveStateConfiguratorForSingleModuleTestImpl,
testModule: TestModule,
allKtFiles: List<KtFile>,
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<BinaryProjectModule>()
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)
@@ -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<String, TestKtSourceModule>()
fun registerModuleInfo(project: Project, testModule: TestModule, ktFiles: Map<TestFile, KtFile>) {
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()
@@ -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<TestFile, KtFile>,
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<KtModule> 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<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
testModule.dependsOnDependencies
.map { moduleProvider.getModule(it.moduleName) }
}
override val directFriendDependencies: List<KtModule> 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<Path>): 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<Path>,
private val sourceModule: KtSourceModule,
override val project: Project,
) : KtLibraryModule {
override val libraryName: String get() = "Test Library"
override val directRegularDependencies: List<KtModule> get() = emptyList()
override val directRefinementDependencies: List<KtModule> get() = emptyList()
override val directFriendDependencies: List<KtModule> 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<Path> = roots
override val librarySources: KtLibrarySourceModule? get() = null
}
@@ -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<KtFile>,
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))
}
@@ -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 <R> 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)
}
@@ -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)
@@ -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<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.ExperimentalStdlibApi"
}
sourceSets {
"main" { projectDefault() }
}
@@ -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<KtModule>
/**
* 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<KtModule>
/**
* 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<KtModule>
/**
* 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<Path>
}
/**
* 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
}
@@ -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<KtBinaryModule>()
* .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<KtBinaryModule>()
.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)
@@ -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 <reified M : KtModule> 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 <reified M : KtModule> PsiElement.getKtModuleOfTypeSafe(project: Project = this.project): M? =
getKtModule(project) as M?
@@ -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 <reified M : KtModule> KtModule.directRegularDependenciesOfType(): Sequence<M> =
directRegularDependencies.asSequence().filterIsInstance<M>()
/**
* 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<KtModule> =
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 <reified M : KtModule> KtModule.allDirectDependenciesOfType(): Sequence<M> =
allDirectDependencies().filterIsInstance<M>()
@@ -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) }
}
@@ -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<FqName> =
project.createPackageProvider(scope)
+1
View File
@@ -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",
@@ -0,0 +1,5 @@
plugins {
kotlin("jvm")
}
publishJarsForIde(listOf(":analysis:project-structure"))
+3 -1
View File
@@ -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) {