AA: introduce KtNotUnderContentRootModule impl to standalone mode

to gracefully handle element/file/etc without a binding module.

This could happen, e.g.,
1) source PSI created from KtPsiFactory, which uses literally dummy.kt
2) debugger that creates a code fragment on-the-fly
3) on-air analysis of non-physical files
This commit is contained in:
Jinseong Jeon
2022-08-03 00:49:22 -07:00
committed by Ilya Kirillov
parent e8e88b4eb2
commit 4531080858
5 changed files with 57 additions and 6 deletions
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.api.standalone;
import com.intellij.mock.MockProject;
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService;
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySessionFactory;
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirNonUnderContentRootSessionFactory;
class RegisterComponentService {
static void registerLLFirLibrarySessionFactory(MockProject project) {
@@ -17,6 +18,13 @@ class RegisterComponentService {
);
}
static void registerLLFirNonUnderContentRootSessionFactory(MockProject project) {
project.registerService(
LLFirNonUnderContentRootSessionFactory.class,
new LLFirNonUnderContentRootSessionFactory(project)
);
}
static void registerLLFirResolveSessionService(MockProject project) {
project.registerService(
LLFirResolveSessionService.class,
@@ -144,6 +144,7 @@ public class StandaloneAnalysisAPISessionBuilder(
)
registerService(LLFirBuiltinsSessionFactory::class.java, LLFirBuiltinsSessionFactory(this))
RegisterComponentService.registerLLFirLibrarySessionFactory(this)
RegisterComponentService.registerLLFirNonUnderContentRootSessionFactory(this)
RegisterComponentService.registerLLFirResolveSessionService(this)
registerService(
PackagePartProviderFactory::class.java,
@@ -6,23 +6,38 @@
package org.jetbrains.kotlin.analysis.project.structure.impl
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.PsiJavaFile
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory.findJvmRootsForJavaFiles
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.platform.TargetPlatform
internal class KtModuleProviderImpl(
internal val mainModules: List<KtModule>,
) : ProjectStructureProvider() {
private val ktNotUnderContentRootModuleWithoutPsiFile by lazy {
KtNotUnderContentRootModuleImpl(
moduleDescription = "Standalone-not-under-content-root-module-without-psi-file"
)
}
private val notUnderContentRootModuleCache = ContainerUtil.createConcurrentWeakMap<PsiFile, KtNotUnderContentRootModule>()
override fun getKtModuleForKtElement(element: PsiElement): KtModule {
val containingFileAsPsiFile = element.containingFile
?: error("Can't get containing PsiFile for ${element.text}")
?: return ktNotUnderContentRootModuleWithoutPsiFile
// If an [element] is created on the fly, e.g., via [KtPsiFactory],
// its containing [PsiFile] may not have [VirtualFile].
// That also means the [element] is not bound to any [KtModule] either.
val containingFileAsVirtualFile = containingFileAsPsiFile.virtualFile
?: error("Can't get containing VirtualFile for ${element.text} in $containingFileAsPsiFile")
?: return notUnderContentRootModuleCache.getOrPut(containingFileAsPsiFile) {
KtNotUnderContentRootModuleImpl(
moduleDescription = "Standalone-not-under-content-root-module-for-$containingFileAsPsiFile",
psiFile = containingFileAsPsiFile
)
}
return mainModules.first { module ->
containingFileAsVirtualFile in module.contentScope
}
@@ -28,12 +28,11 @@ 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.JvmPlatforms
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.psi.KtFile
@@ -102,7 +101,7 @@ internal fun buildKtModuleProviderByCompilerConfiguration(
): ProjectStructureProvider = buildProjectStructureProvider {
addModule(
buildKtSourceModule {
val platform = TargetPlatform(setOf(JdkPlatform(JvmTarget.DEFAULT)))
val platform = JvmPlatforms.defaultJvmPlatform
val moduleName = compilerConfig.get(CommonConfigurationKeys.MODULE_NAME) ?: "<no module name provided>"
val libraryRoots = compilerConfig.jvmModularRoots + compilerConfig.jvmClasspathRoots
@@ -0,0 +1,28 @@
/*
* 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.PsiFile
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
internal class KtNotUnderContentRootModuleImpl(
override val directRegularDependencies: List<KtModule> = emptyList(),
override val directRefinementDependencies: List<KtModule> = emptyList(),
override val directFriendDependencies: List<KtModule> = emptyList(),
override val platform: TargetPlatform = JvmPlatforms.defaultJvmPlatform,
psiFile: PsiFile? = null,
override val moduleDescription: String,
) : KtNotUnderContentRootModule, KtModuleWithPlatform {
override val analyzerServices: PlatformDependentAnalyzerServices = super.analyzerServices
override val contentScope: GlobalSearchScope =
if (psiFile != null) GlobalSearchScope.fileScope(psiFile) else GlobalSearchScope.EMPTY_SCOPE
}