diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneUtils.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneUtils.kt index e3eb145cd45..bc30a5e6d58 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneUtils.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneUtils.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.PackagePartP 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.impl.KtModuleProviderByCompilerConfiguration +import org.jetbrains.kotlin.analysis.project.structure.impl.buildKtModuleProviderByCompilerConfiguration import org.jetbrains.kotlin.analysis.providers.* import org.jetbrains.kotlin.analysis.providers.impl.* import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport @@ -171,7 +171,7 @@ internal fun configureProjectEnvironment( project.picoContainer.registerComponentInstance( ProjectStructureProvider::class.qualifiedName, - KtModuleProviderByCompilerConfiguration( + buildKtModuleProviderByCompilerConfiguration( compilerConfig, project, ktFiles, diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleBuilder.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleBuilder.kt index c21d81842fe..a16d1b889b3 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleBuilder.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleBuilder.kt @@ -12,9 +12,21 @@ import org.jetbrains.kotlin.platform.TargetPlatform @KtModuleBuilderDsl public abstract class KtModuleBuilder { - public val directRegularDependencies: MutableList = mutableListOf() - public val directRefinementDependencies: MutableList = mutableListOf() - public val directFriendDependencies: MutableList = mutableListOf() + protected val directRegularDependencies: MutableList = mutableListOf() + protected val directRefinementDependencies: MutableList = mutableListOf() + protected val directFriendDependencies: MutableList = mutableListOf() + + public fun addRegularDependency(module: KtModule) { + directRegularDependencies.add(module) + } + + public fun addRefinementDependency(module: KtModule) { + directRefinementDependencies.add(module) + } + + public fun addFriendDependency(module: KtModule) { + directFriendDependencies.add(module) + } public lateinit var contentScope: GlobalSearchScope public lateinit var platform: TargetPlatform diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleProviderBuilder.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleProviderBuilder.kt new file mode 100644 index 00000000000..2f1048b2fa2 --- /dev/null +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/builder/KtModuleProviderBuilder.kt @@ -0,0 +1,36 @@ +/* + * 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.project.structure.builder + +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider +import org.jetbrains.kotlin.analysis.project.structure.impl.KtModuleProviderImpl +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +@KtModuleBuilderDsl +public class KtModuleProviderBuilder { + private val mainModules: MutableList = mutableListOf() + + public fun addModule(module: KtModule) { + mainModules.add(module) + } + + public fun build(): ProjectStructureProvider { + return KtModuleProviderImpl( + mainModules, + ) + } +} + +@OptIn(ExperimentalContracts::class) +public inline fun buildProjectStructureProvider(init: KtModuleProviderBuilder.() -> Unit): ProjectStructureProvider { + contract { + callsInPlace(init, InvocationKind.EXACTLY_ONCE) + } + return KtModuleProviderBuilder().apply(init).build() +} diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt deleted file mode 100644 index 573bc3140c2..00000000000 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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.project.structure.impl - -import com.google.common.io.Files -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.psi.PsiElement -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.search.ProjectScope -import com.intellij.util.io.URLUtil -import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils -import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule -import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule -import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule -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.* -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.platform.jvm.JdkPlatform -import org.jetbrains.kotlin.psi.KtFile -import java.nio.file.Paths - -internal class KtModuleProviderByCompilerConfiguration( - compilerConfig: CompilerConfiguration, - project: Project, - ktFiles: List, -) : ProjectStructureProvider() { - private val sourceModule = buildKtSourceModule { - val platform = TargetPlatform(setOf(JdkPlatform(JvmTarget.DEFAULT))) - val moduleName = compilerConfig.get(CommonConfigurationKeys.MODULE_NAME) ?: "" - - val libraryRoots = compilerConfig.jvmModularRoots + compilerConfig.jvmClasspathRoots - val libraryRootsByType = libraryRoots.groupBy { it.isDirectory } - libraryRootsByType[true]?.let { directories -> - directories.forEach { - // E.g., project/app/build/intermediates/javac/debug/classes - val root = it.toPath() - directRegularDependencies.add( - buildKtLibraryModule { - contentScope = ProjectScope.getLibrariesScope(project) - this.platform = platform - this.project = project - binaryRoots = listOf(root) - libraryName = "$moduleName-${root.toString().replace("/", "-")}" - } - ) - } - } - libraryRootsByType[false]?.let { jars -> - jars.forEach { - // E.g., project/libs/libA/a.jar - val root = it.toPath() - directRegularDependencies.add( - buildKtLibraryModule { - contentScope = ProjectScope.getLibrariesScope(project) - this.platform = platform - this.project = project - binaryRoots = listOf(root) - libraryName = Files.getNameWithoutExtension(root.toString()) - isBuiltinsContainingStdlib = - libraryName.startsWith("kotlin-stdlib") && - !libraryName.contains("common") && !libraryName.contains("jdk") - } - ) - } - } - compilerConfig.get(JVMConfigurationKeys.JDK_HOME)?.let { jdkHome -> - val vfm = VirtualFileManager.getInstance() - val jdkHomePath = jdkHome.toPath() - val jdkHomeVirtualFile = vfm.findFileByNioPath(jdkHomePath) - val binaryRoots = LibraryUtils.findClassesFromJdkHome(jdkHomePath).map { - Paths.get(URLUtil.extractPath(it)) - } - directRegularDependencies.add( - buildKtSdkModule { - contentScope = GlobalSearchScope.fileScope(project, jdkHomeVirtualFile) - this.platform = platform - this.project = project - this.binaryRoots = binaryRoots - sdkName = "JDK for $moduleName" - } - ) - } - - contentScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles) - this.platform = platform - this.project = project - this.moduleName = moduleName - } - - private val binaryModules: Collection by lazy { - sourceModule.directRegularDependencies.filterIsInstance() - } - - override fun getKtModuleForKtElement(element: PsiElement): KtModule { - val containingFile = element.containingFile.virtualFile - return if (containingFile in sourceModule.contentScope) { - sourceModule - } else { - binaryModules.find { libModule -> containingFile in libModule.contentScope } - ?: error("Can't find module for ${containingFile.path}") - } - } - - override fun getKtBinaryModules(): Collection { - return binaryModules - } - - override fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule? { - return binaryModules - .filterIsInstance() - .firstOrNull { it.isBuiltinsContainingStdlib } - } -} diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderImpl.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderImpl.kt new file mode 100644 index 00000000000..3a30971c43c --- /dev/null +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderImpl.kt @@ -0,0 +1,36 @@ +/* + * 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.project.structure.impl + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.project.structure.* + +internal class KtModuleProviderImpl( + private val mainModules: List, +) : ProjectStructureProvider() { + override fun getKtModuleForKtElement(element: PsiElement): KtModule { + val containingFile = element.containingFile.virtualFile + return mainModules.first { module -> + containingFile in module.contentScope + } + } + + private val binaryModules: Collection by lazy { + mainModules + .flatMap { it.allDirectDependencies() } + .filterIsInstance() + } + + override fun getKtBinaryModules(): Collection { + return binaryModules + } + + override fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule? { + return binaryModules + .filterIsInstance() + .firstOrNull { it.isBuiltinsContainingStdlib } + } +} \ No newline at end of file diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt index c2daa000669..75b5be2a1a4 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt @@ -5,16 +5,38 @@ package org.jetbrains.kotlin.analysis.project.structure.impl +import com.google.common.io.Files +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.ProjectScope +import com.intellij.util.io.URLUtil +import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils +import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider +import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule +import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule +import org.jetbrains.kotlin.analysis.project.structure.builder.buildProjectStructureProvider import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices +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.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.js.isJs +import org.jetbrains.kotlin.platform.jvm.JdkPlatform import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.konan.isNative +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices +import java.nio.file.Paths internal fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices { return when { @@ -26,3 +48,73 @@ internal fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServ } } +internal fun buildKtModuleProviderByCompilerConfiguration( + compilerConfig: CompilerConfiguration, + project: Project, + ktFiles: List, +): ProjectStructureProvider = buildProjectStructureProvider { + addModule( + buildKtSourceModule { + val platform = TargetPlatform(setOf(JdkPlatform(JvmTarget.DEFAULT))) + val moduleName = compilerConfig.get(CommonConfigurationKeys.MODULE_NAME) ?: "" + + val libraryRoots = compilerConfig.jvmModularRoots + compilerConfig.jvmClasspathRoots + val libraryRootsByType = libraryRoots.groupBy { it.isDirectory } + libraryRootsByType[true]?.let { directories -> + directories.forEach { + // E.g., project/app/build/intermediates/javac/debug/classes + val root = it.toPath() + addRegularDependency( + buildKtLibraryModule { + contentScope = ProjectScope.getLibrariesScope(project) + this.platform = platform + this.project = project + binaryRoots = listOf(root) + libraryName = "$moduleName-${root.toString().replace("/", "-")}" + } + ) + } + } + libraryRootsByType[false]?.let { jars -> + jars.forEach { + // E.g., project/libs/libA/a.jar + val root = it.toPath() + addRegularDependency( + buildKtLibraryModule { + contentScope = ProjectScope.getLibrariesScope(project) + this.platform = platform + this.project = project + binaryRoots = listOf(root) + libraryName = Files.getNameWithoutExtension(root.toString()) + isBuiltinsContainingStdlib = + libraryName.startsWith("kotlin-stdlib") && + !libraryName.contains("common") && !libraryName.contains("jdk") + } + ) + } + } + compilerConfig.get(JVMConfigurationKeys.JDK_HOME)?.let { jdkHome -> + val vfm = VirtualFileManager.getInstance() + val jdkHomePath = jdkHome.toPath() + val jdkHomeVirtualFile = vfm.findFileByNioPath(jdkHomePath) + val binaryRoots = LibraryUtils.findClassesFromJdkHome(jdkHomePath).map { + Paths.get(URLUtil.extractPath(it)) + } + addRegularDependency( + buildKtSdkModule { + contentScope = GlobalSearchScope.fileScope(project, jdkHomeVirtualFile) + this.platform = platform + this.project = project + this.binaryRoots = binaryRoots + sdkName = "JDK for $moduleName" + } + ) + } + + contentScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles) + this.platform = platform + this.project = project + this.moduleName = moduleName + } + ) +}