[AA, tests] Limit scopes of test libraries to their roots, add JDK_HOME
Without the fix, all libraries share the global scope for all project libraries. JDK_HOME was used implicitly for things such as providing Record support, but was not included as a test library/sdk. KT-59637
This commit is contained in:
committed by
Space Team
parent
5b8b3644fc
commit
630c8e9df6
+39
-2
@@ -15,6 +15,7 @@ import com.intellij.mock.MockApplication
|
|||||||
import com.intellij.mock.MockProject
|
import com.intellij.mock.MockProject
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.extensions.PluginDescriptor
|
import com.intellij.openapi.extensions.PluginDescriptor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.roots.PackageIndex
|
import com.intellij.openapi.roots.PackageIndex
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
@@ -27,8 +28,8 @@ import com.intellij.psi.search.GlobalSearchScope
|
|||||||
import com.intellij.psi.search.ProjectScope
|
import com.intellij.psi.search.ProjectScope
|
||||||
import com.intellij.util.io.URLUtil.JAR_PROTOCOL
|
import com.intellij.util.io.URLUtil.JAR_PROTOCOL
|
||||||
import com.intellij.util.io.URLUtil.JAR_SEPARATOR
|
import com.intellij.util.io.URLUtil.JAR_SEPARATOR
|
||||||
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
|
|
||||||
import org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSourceWithSmartPointerFactory
|
import org.jetbrains.kotlin.analysis.api.impl.base.java.source.JavaElementSourceWithSmartPointerFactory
|
||||||
|
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
|
||||||
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
|
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
|
||||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.DummyFileAttributeService
|
import org.jetbrains.kotlin.analysis.decompiler.stub.file.DummyFileAttributeService
|
||||||
@@ -57,6 +58,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.popLast
|
import org.jetbrains.kotlin.utils.addToStdlib.popLast
|
||||||
import org.picocontainer.PicoContainer
|
import org.picocontainer.PicoContainer
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
object StandaloneProjectFactory {
|
object StandaloneProjectFactory {
|
||||||
fun createProjectEnvironment(
|
fun createProjectEnvironment(
|
||||||
@@ -251,6 +253,18 @@ object StandaloneProjectFactory {
|
|||||||
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
|
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDefaultJdkModulePaths(
|
||||||
|
project: Project,
|
||||||
|
jdkHome: Path?,
|
||||||
|
): List<Path> {
|
||||||
|
val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
|
||||||
|
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.toFile(), null, javaFileManager, project, null)
|
||||||
|
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||||
|
|
||||||
|
val javaRoots = getDefaultJdkModuleRoots(javaModuleFinder, javaModuleGraph)
|
||||||
|
return javaRoots.map { getBinaryPath(it.file) }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the [JavaRoot]s of the JDK's default modules.
|
* Computes the [JavaRoot]s of the JDK's default modules.
|
||||||
*
|
*
|
||||||
@@ -364,13 +378,36 @@ object StandaloneProjectFactory {
|
|||||||
// e.g., "/path/to/jdk/home!/modules/java.base". (JDK home path + JAR separator + actual file path)
|
// e.g., "/path/to/jdk/home!/modules/java.base". (JDK home path + JAR separator + actual file path)
|
||||||
// To work with that JRT handler, a hacky workaround here is to add "modules" before the module name so that it can
|
// To work with that JRT handler, a hacky workaround here is to add "modules" before the module name so that it can
|
||||||
// find the actual file path.
|
// find the actual file path.
|
||||||
// See [LLFirJavaFacadeForBinaries#getBinaryPath] for a similar hack.
|
// See [LLFirJavaFacadeForBinaries#getBinaryPath] and [StandaloneProjectFactory#getBinaryPath] for a similar hack.
|
||||||
val (libHomePath, pathInImage) = CoreJrtFileSystem.splitPath(pathString)
|
val (libHomePath, pathInImage) = CoreJrtFileSystem.splitPath(pathString)
|
||||||
libHomePath + JAR_SEPARATOR + "modules/$pathInImage"
|
libHomePath + JAR_SEPARATOR + "modules/$pathInImage"
|
||||||
} else
|
} else
|
||||||
pathString
|
pathString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From [LLFirJavaFacadeForBinaries#getBinaryPath]
|
||||||
|
private fun getBinaryPath(virtualFile: VirtualFile): Path {
|
||||||
|
val path = virtualFile.path
|
||||||
|
return when {
|
||||||
|
".$JAR_PROTOCOL$JAR_SEPARATOR" in path ->
|
||||||
|
Paths.get(path.substringBefore(JAR_SEPARATOR))
|
||||||
|
JAR_SEPARATOR in path && "modules/" in path -> {
|
||||||
|
// CoreJrtFileSystem.CoreJrtHandler#findFile, which uses Path#resolve, finds a virtual file path to the file itself,
|
||||||
|
// e.g., "/path/to/jdk/home!/modules/java.base/java/lang/Object.class". (JDK home path + JAR separator + actual file path)
|
||||||
|
// URLs loaded from JDK, though, point to module names in a JRT protocol format,
|
||||||
|
// e.g., "jrt:///path/to/jdk/home!/java.base" (JRT protocol prefix + JDK home path + JAR separator + module name)
|
||||||
|
// After splitting at the JAR separator, it is regarded as a root directory "/java.base".
|
||||||
|
// To work with LibraryPathFilter, a hacky workaround here is to remove "modules/" from actual file path.
|
||||||
|
// e.g. "/path/to/jdk/home!/java.base/java/lang/Object.class", which, from Path viewpoint, belongs to "/java.base",
|
||||||
|
// after splitting at the JAR separator, in a similar way.
|
||||||
|
// See [StandaloneProjectFactory#getAllBinaryRoots] for a similar hack.
|
||||||
|
Paths.get(path.replace("modules/", ""))
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
Paths.get(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun createPackagePartsProvider(
|
fun createPackagePartsProvider(
|
||||||
project: MockProject,
|
project: MockProject,
|
||||||
libraryRoots: List<JavaRoot>,
|
libraryRoots: List<JavaRoot>,
|
||||||
|
|||||||
+27
-9
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.analysis.test.framework.project.structure
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.search.ProjectScope
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.*
|
import org.jetbrains.kotlin.analysis.project.structure.*
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
||||||
@@ -16,12 +16,14 @@ import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots
|
|||||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||||
import org.jetbrains.kotlin.test.getAnalyzerServices
|
import org.jetbrains.kotlin.test.getAnalyzerServices
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
|
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@@ -30,7 +32,7 @@ abstract class KtModuleByCompilerConfiguration(
|
|||||||
val project: Project,
|
val project: Project,
|
||||||
val testModule: TestModule,
|
val testModule: TestModule,
|
||||||
val psiFiles: List<PsiFile>,
|
val psiFiles: List<PsiFile>,
|
||||||
testServices: TestServices,
|
val testServices: TestServices,
|
||||||
) {
|
) {
|
||||||
private val moduleProvider = testServices.ktModuleProvider
|
private val moduleProvider = testServices.ktModuleProvider
|
||||||
private val compilerConfigurationProvider = testServices.compilerConfigurationProvider
|
private val compilerConfigurationProvider = testServices.compilerConfigurationProvider
|
||||||
@@ -43,14 +45,29 @@ abstract class KtModuleByCompilerConfiguration(
|
|||||||
val directRegularDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
val directRegularDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
buildList {
|
buildList {
|
||||||
testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) }
|
testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) }
|
||||||
addAll(
|
val roots = buildList {
|
||||||
librariesByRoots(
|
addAll(configuration.jvmModularRoots.map(File::toPath))
|
||||||
(configuration.jvmModularRoots + configuration.jvmClasspathRoots).map(File::toPath)
|
addAll(configuration.jvmClasspathRoots.map(File::toPath))
|
||||||
)
|
}
|
||||||
)
|
addAll(librariesByRoots(roots))
|
||||||
|
addIfNotNull(createJdkFromConfiguration())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createJdkFromConfiguration(): KtSdkModule? = configuration.get(JVMConfigurationKeys.JDK_HOME)?.let { jdkHome ->
|
||||||
|
val jdkHomePaths = StandaloneProjectFactory.getDefaultJdkModulePaths(project, jdkHome.toPath())
|
||||||
|
val scope = TestModuleStructureFactory.getScopeForLibraryByRoots(jdkHomePaths, project, testServices)
|
||||||
|
|
||||||
|
KtJdkModuleImpl(
|
||||||
|
"jdk",
|
||||||
|
JvmPlatforms.defaultJvmPlatform,
|
||||||
|
scope,
|
||||||
|
project,
|
||||||
|
jdkHomePaths,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate") // used for overrides in subclasses
|
||||||
val directDependsOnDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
val directDependsOnDependencies: List<KtModule> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
testModule.dependsOnDependencies
|
testModule.dependsOnDependencies
|
||||||
.map { moduleProvider.getModule(it.moduleName) }
|
.map { moduleProvider.getModule(it.moduleName) }
|
||||||
@@ -69,7 +86,7 @@ abstract class KtModuleByCompilerConfiguration(
|
|||||||
|
|
||||||
protected abstract val ktModule: KtModule
|
protected abstract val ktModule: KtModule
|
||||||
|
|
||||||
private fun librariesByRoots(roots: List<Path>): List<LibraryByRoot> = roots.map { LibraryByRoot(it, ktModule, project) }
|
private fun librariesByRoots(roots: List<Path>): List<LibraryByRoot> = roots.map { LibraryByRoot(it, ktModule, project, testServices) }
|
||||||
|
|
||||||
val languageVersionSettings: LanguageVersionSettings
|
val languageVersionSettings: LanguageVersionSettings
|
||||||
get() = testModule.languageVersionSettings
|
get() = testModule.languageVersionSettings
|
||||||
@@ -127,13 +144,14 @@ private class LibraryByRoot(
|
|||||||
private val root: Path,
|
private val root: Path,
|
||||||
private val parentModule: KtModule,
|
private val parentModule: KtModule,
|
||||||
override val project: Project,
|
override val project: Project,
|
||||||
|
testServices: TestServices,
|
||||||
) : KtLibraryModule {
|
) : KtLibraryModule {
|
||||||
|
override val contentScope: GlobalSearchScope = TestModuleStructureFactory.getScopeForLibraryByRoots(listOf(root), project, testServices)
|
||||||
override val libraryName: String get() = "Test Library $root"
|
override val libraryName: String get() = "Test Library $root"
|
||||||
override val directRegularDependencies: List<KtModule> get() = emptyList()
|
override val directRegularDependencies: List<KtModule> get() = emptyList()
|
||||||
override val directDependsOnDependencies: List<KtModule> get() = emptyList()
|
override val directDependsOnDependencies: List<KtModule> get() = emptyList()
|
||||||
override val transitiveDependsOnDependencies: List<KtModule> get() = emptyList()
|
override val transitiveDependsOnDependencies: List<KtModule> get() = emptyList()
|
||||||
override val directFriendDependencies: List<KtModule> get() = emptyList()
|
override val directFriendDependencies: List<KtModule> get() = emptyList()
|
||||||
override val contentScope: GlobalSearchScope get() = ProjectScope.getLibrariesScope(project)
|
|
||||||
override val platform: TargetPlatform get() = parentModule.platform
|
override val platform: TargetPlatform get() = parentModule.platform
|
||||||
override val analyzerServices: PlatformDependentAnalyzerServices get() = parentModule.analyzerServices
|
override val analyzerServices: PlatformDependentAnalyzerServices get() = parentModule.analyzerServices
|
||||||
override fun getBinaryRoots(): Collection<Path> = listOf(root)
|
override fun getBinaryRoots(): Collection<Path> = listOf(root)
|
||||||
|
|||||||
+1
-1
@@ -173,7 +173,7 @@ object TestModuleStructureFactory {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getScopeForLibraryByRoots(roots: Collection<Path>, project: Project, testServices: TestServices): GlobalSearchScope {
|
fun getScopeForLibraryByRoots(roots: Collection<Path>, project: Project, testServices: TestServices): GlobalSearchScope {
|
||||||
val virtualFileRoots = StandaloneProjectFactory.getVirtualFilesForLibraryRoots(
|
val virtualFileRoots = StandaloneProjectFactory.getVirtualFilesForLibraryRoots(
|
||||||
roots,
|
roots,
|
||||||
testServices.environmentManager.getProjectEnvironment()
|
testServices.environmentManager.getProjectEnvironment()
|
||||||
|
|||||||
+2
-1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisAp
|
|||||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiDecompiledCodeTestServiceRegistrar
|
||||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
|
||||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.allDirectDependenciesOfType
|
import org.jetbrains.kotlin.analysis.project.structure.allDirectDependenciesOfType
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleByCompilerConfiguration
|
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleByCompilerConfiguration
|
||||||
@@ -52,7 +53,7 @@ object FirLowLevelCompilerBasedTestConfigurator : AnalysisApiTestConfigurator()
|
|||||||
}
|
}
|
||||||
return KtModuleProjectStructure(
|
return KtModuleProjectStructure(
|
||||||
mainModules = mainModules,
|
mainModules = mainModules,
|
||||||
binaryModules = mainModules.asSequence().flatMap { it.ktModule.allDirectDependenciesOfType<KtLibraryModule>() }.asIterable(),
|
binaryModules = mainModules.asSequence().flatMap { it.ktModule.allDirectDependenciesOfType<KtBinaryModule>() }.asIterable(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// FIR_IDENTICAL
|
// FIR_IDENTICAL
|
||||||
|
// IGNORE_REVERSED_RESOLVE
|
||||||
|
// IGNORE_DIAGNOSTIC_API
|
||||||
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER
|
||||||
// !LANGUAGE: +MultiPlatformProjects
|
// !LANGUAGE: +MultiPlatformProjects
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user