AA: introduce AA session and builder

This commit is contained in:
Jinseong Jeon
2022-06-01 14:56:18 -07:00
committed by Ilya Kirillov
parent 5585d84808
commit aef3df0336
9 changed files with 288 additions and 9 deletions
@@ -25,8 +25,7 @@ import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver
import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
@@ -52,8 +51,8 @@ object StandaloneProjectFactory {
projectStructureProvider: ProjectStructureProvider,
modules: List<KtModule>,
sourceFiles: List<PsiFileSystemItem>,
languageVersionSettings: LanguageVersionSettings,
jdkHome: Path?,
languageVersionSettings: LanguageVersionSettings = latestLanguageVersionSettings,
jdkHome: Path? = null,
) {
val project = environment.project
@@ -96,7 +95,7 @@ object StandaloneProjectFactory {
javaFileManager.initialize(
JvmDependenciesIndexImpl(sourceAndLibraryRoots),
listOf(
createPackagePartsProvider(languageVersionSettings, project, libraryRoots)
createPackagePartsProvider(project, libraryRoots, languageVersionSettings)
.invoke(ProjectScope.getLibrariesScope(project))
),
SingleJavaFileRootsIndex(emptyList()),
@@ -174,9 +173,9 @@ object StandaloneProjectFactory {
}
fun createPackagePartsProvider(
languageVersionSettings: LanguageVersionSettings,
project: MockProject,
libraryRoots: List<JavaRoot>
libraryRoots: List<JavaRoot>,
languageVersionSettings: LanguageVersionSettings = latestLanguageVersionSettings,
): (GlobalSearchScope) -> JvmPackagePartProvider = { scope ->
JvmPackagePartProvider(languageVersionSettings, scope).apply {
addRoots(libraryRoots, MessageCollector.NONE)
@@ -185,4 +184,7 @@ object StandaloneProjectFactory {
.addPackagePartProvider(this)
}
}
private val latestLanguageVersionSettings: LanguageVersionSettings =
LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST)
}
@@ -18,6 +18,7 @@ dependencies {
api(project(":analysis:low-level-api-fir"))
api(project(":analysis:symbol-light-classes"))
api(project(":analysis:decompiled:light-classes-for-decompiled"))
api(project(":analysis:analysis-api-standalone:analysis-api-standalone-base"))
testApi(projectTests(":analysis:analysis-api-impl-base"))
testApi(projectTests(":analysis:analysis-api-fir"))
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2022 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.api.standalone
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.mock.MockProject
import com.intellij.openapi.application.Application
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
public class StandaloneAnalysisAPISession internal constructor(
kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment,
) {
// TODO: better to limit exposure? Current usages are: addExtension, jarFileSystem
public val coreApplicationEnvironment: CoreApplicationEnvironment = kotlinCoreProjectEnvironment.environment
public val application: Application = kotlinCoreProjectEnvironment.environment.application
public val project: Project = kotlinCoreProjectEnvironment.project
@Deprecated(
"Use session builder's service registration.",
ReplaceWith("project")
)
public val mockProject: MockProject = kotlinCoreProjectEnvironment.project
}
@@ -0,0 +1,219 @@
/*
* Copyright 2010-2022 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.api.standalone
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.Application
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.impl.PsiElementFinderImpl
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
import org.jetbrains.kotlin.analysis.api.lifetime.KtDefaultLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.lifetime.KtReadActionConfinementDefaultLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
import org.jetbrains.kotlin.analysis.decompiled.light.classes.ClsJavaStubByVirtualFileCache
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.project.structure.KtModuleScopeProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModuleScopeProviderImpl
import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
import org.jetbrains.kotlin.analysis.project.structure.builder.KtModuleProviderBuilder
import org.jetbrains.kotlin.analysis.project.structure.builder.buildProjectStructureProvider
import org.jetbrains.kotlin.analysis.project.structure.impl.KtModuleProviderImpl
import org.jetbrains.kotlin.analysis.project.structure.impl.buildKtModuleProviderByCompilerConfiguration
import org.jetbrains.kotlin.analysis.project.structure.impl.getPsiFilesFromPaths
import org.jetbrains.kotlin.analysis.project.structure.impl.getSourceFilePaths
import org.jetbrains.kotlin.analysis.providers.KotlinAnnotationsResolverFactory
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.KotlinStaticAnnotationsResolverFactory
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.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.setupIdeaStandaloneExecution
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider
import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderImpl
import org.jetbrains.kotlin.idea.references.KotlinFirReferenceContributor
import org.jetbrains.kotlin.idea.references.KotlinReferenceProviderContributor
import org.jetbrains.kotlin.light.classes.symbol.KotlinAsJavaFirSupport
import org.jetbrains.kotlin.light.classes.symbol.caches.SymbolLightClassFacadeCache
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.psi.KotlinReferenceProvidersService
import org.jetbrains.kotlin.psi.KtFile
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
public class StandaloneAnalysisAPISessionBuilder(
applicationDisposable: Disposable,
projectDisposable: Disposable,
) {
init {
setupIdeaStandaloneExecution()
}
private val kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment =
StandaloneProjectFactory.createProjectEnvironment(
projectDisposable,
applicationDisposable,
)
public val application: Application = kotlinCoreProjectEnvironment.environment.application
public val project: Project = kotlinCoreProjectEnvironment.project
private lateinit var projectStructureProvider: ProjectStructureProvider
public fun buildKtModuleProvider(init: KtModuleProviderBuilder.() -> Unit) {
projectStructureProvider = buildProjectStructureProvider(init)
}
@Deprecated(
"Compiler configuration is not a good fit for specifying multi-module project.",
ReplaceWith("buildKtModuleProvider { }")
)
public fun buildKtModuleProviderByCompilerConfiguration(
compilerConfiguration: CompilerConfiguration,
) {
val project = kotlinCoreProjectEnvironment.project
projectStructureProvider = buildKtModuleProviderByCompilerConfiguration(
compilerConfiguration,
project,
getPsiFilesFromPaths(project, getSourceFilePaths(compilerConfiguration)),
)
}
private fun registerApplicationServices() {
kotlinCoreProjectEnvironment.environment.application.apply {
registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java)
registerService(KotlinReferenceProviderContributor::class.java, KotlinFirReferenceContributor::class.java)
}
}
public fun <T : Any> registerApplicationService(serviceInterface: Class<T>, serviceImplementation: T) {
kotlinCoreProjectEnvironment.environment.application.apply {
registerService(serviceInterface, serviceImplementation)
}
}
public fun <T : Any> registerApplicationService(serviceImplementation: Class<T>) {
kotlinCoreProjectEnvironment.environment.application.apply {
registerService(serviceImplementation)
}
}
@OptIn(KtAnalysisApiInternals::class)
private fun registerProjectServices(
ktFiles: List<KtFile>,
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
) {
val project = kotlinCoreProjectEnvironment.project
project.apply {
registerService(KotlinModificationTrackerFactory::class.java, KotlinStaticModificationTrackerFactory::class.java)
registerService(KtDefaultLifetimeTokenProvider::class.java, KtReadActionConfinementDefaultLifetimeTokenProvider::class.java)
registerService(KtModuleScopeProvider::class.java, KtModuleScopeProviderImpl())
registerService(KotlinModificationTrackerFactory::class.java, KotlinStaticModificationTrackerFactory::class.java)
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(ktFiles))
registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(ktFiles))
registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(ktFiles))
registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this))
registerService(
FirSealedClassInheritorsProcessorFactory::class.java,
object : FirSealedClassInheritorsProcessorFactory() {
override fun createSealedClassInheritorsProvider(): SealedClassInheritorsProvider {
return SealedClassInheritorsProviderImpl
}
}
)
RegisterComponentService.registerLLFirResolveSessionService(this)
registerService(
PackagePartProviderFactory::class.java,
object : PackagePartProviderFactory() {
override fun createPackagePartProviderForLibrary(scope: GlobalSearchScope): PackagePartProvider {
return packagePartProvider(scope)
}
}
)
registerService(SymbolLightClassFacadeCache::class.java)
registerService(ClsJavaStubByVirtualFileCache::class.java)
registerService(KotlinAsJavaSupport::class.java, KotlinAsJavaFirSupport(this))
}
@Suppress("DEPRECATION")
PsiElementFinder.EP.getPoint(project).registerExtension(JavaElementFinder(project))
@Suppress("DEPRECATION")
PsiElementFinder.EP.getPoint(project).registerExtension(PsiElementFinderImpl(project))
}
public fun <T : Any> registerProjectService(serviceInterface: Class<T>, serviceImplementation: T) {
kotlinCoreProjectEnvironment.project.apply {
registerService(serviceInterface, serviceImplementation)
}
}
public fun <T : Any> registerProjectService(serviceImplementation: Class<T>) {
kotlinCoreProjectEnvironment.project.apply {
registerService(serviceImplementation)
}
}
public fun build(): StandaloneAnalysisAPISession {
val ktModuleProviderImpl = projectStructureProvider as KtModuleProviderImpl
val modules = ktModuleProviderImpl.mainModules
val allSourceFiles = ktModuleProviderImpl.allSourceFiles()
StandaloneProjectFactory.registerServicesForProjectEnvironment(
kotlinCoreProjectEnvironment,
projectStructureProvider,
modules,
allSourceFiles,
)
registerApplicationServices()
val project = kotlinCoreProjectEnvironment.project
val ktFiles = allSourceFiles.filterIsInstance<KtFile>()
val libraryRoots = StandaloneProjectFactory.getAllBinaryRoots(modules, kotlinCoreProjectEnvironment)
registerProjectServices(
ktFiles,
StandaloneProjectFactory.createPackagePartsProvider(
project,
libraryRoots,
)
)
return StandaloneAnalysisAPISession(
kotlinCoreProjectEnvironment,
)
}
}
@OptIn(ExperimentalContracts::class)
public inline fun buildStandaloneAnalysisAPISession(
applicationDisposable: Disposable = Disposer.newDisposable("StandaloneAnalysisAPISession.application"),
projectDisposable: Disposable = Disposer.newDisposable("StandaloneAnalysisAPISession.project"),
init: StandaloneAnalysisAPISessionBuilder.() -> Unit
): StandaloneAnalysisAPISession {
contract {
callsInPlace(init, InvocationKind.EXACTLY_ONCE)
}
return StandaloneAnalysisAPISessionBuilder(
applicationDisposable,
projectDisposable,
).apply(init).build()
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.project.structure.builder
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.project.structure.impl.KtSourceModuleImpl
import org.jetbrains.kotlin.config.ApiVersion
@@ -20,6 +21,15 @@ public class KtSourceModuleBuilder : KtModuleBuilder() {
public lateinit var moduleName: String
public var languageVersionSettings: LanguageVersionSettings =
LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST)
private val sourceRoots: MutableList<PsiFile> = mutableListOf()
public fun addSourceRoot(file: PsiFile) {
sourceRoots.add(file)
}
public fun addSourceRoots(files: Collection<PsiFile>) {
sourceRoots.addAll(files)
}
override fun build(): KtSourceModule {
return KtSourceModuleImpl(
@@ -31,6 +41,7 @@ public class KtSourceModuleBuilder : KtModuleBuilder() {
project,
moduleName,
languageVersionSettings,
sourceRoots,
)
}
}
@@ -6,10 +6,13 @@
package org.jetbrains.kotlin.analysis.project.structure.impl
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.PsiJavaFile
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory.findJvmRootsForJavaFiles
import org.jetbrains.kotlin.analysis.project.structure.*
internal class KtModuleProviderImpl(
private val mainModules: List<KtModule>,
internal val mainModules: List<KtModule>,
) : ProjectStructureProvider() {
override fun getKtModuleForKtElement(element: PsiElement): KtModule {
val containingFile = element.containingFile.virtualFile
@@ -33,4 +36,10 @@ internal class KtModuleProviderImpl(
.filterIsInstance<KtLibraryModuleImpl>()
.firstOrNull { it.isBuiltinsContainingStdlib }
}
internal fun allSourceFiles(): List<PsiFileSystemItem> = buildList {
val files = mainModules.mapNotNull { (it as? KtSourceModuleImpl)?.sourceRoots }.flatten()
addAll(files)
addAll(findJvmRootsForJavaFiles(files.filterIsInstance<PsiJavaFile>()))
}
}
@@ -154,6 +154,7 @@ internal fun buildKtModuleProviderByCompilerConfiguration(
this.platform = platform
this.project = project
this.moduleName = moduleName
addSourceRoots(getPsiFilesFromPaths(project, getSourceFilePaths(compilerConfig)))
}
)
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.project.structure.impl
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
@@ -22,6 +23,7 @@ internal class KtSourceModuleImpl(
override val project: Project,
override val moduleName: String,
override val languageVersionSettings: LanguageVersionSettings,
internal val sourceRoots: List<PsiFile>,
) : KtSourceModule, KtModuleWithPlatform {
override val analyzerServices: PlatformDependentAnalyzerServices = super.analyzerServices
}
@@ -2,4 +2,9 @@ plugins {
kotlin("jvm")
}
publishJarsForIde(listOf(":analysis:analysis-api-standalone"))
publishJarsForIde(
listOf(
":analysis:analysis-api-standalone:analysis-api-standalone-base",
":analysis:analysis-api-standalone",
)
)