diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt index 6b71dd0a93c..0dad9a7a42e 100644 --- a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt +++ b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt @@ -15,6 +15,7 @@ import com.intellij.mock.MockApplication import com.intellij.mock.MockProject import com.intellij.openapi.Disposable import com.intellij.openapi.extensions.PluginDescriptor +import com.intellij.openapi.project.Project import com.intellij.openapi.roots.PackageIndex import com.intellij.openapi.vfs.VirtualFile 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.util.io.URLUtil.JAR_PROTOCOL 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.references.HLApiReferenceProviderService 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.DummyFileAttributeService @@ -57,6 +58,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.popLast import org.picocontainer.PicoContainer import java.nio.file.Path +import java.nio.file.Paths object StandaloneProjectFactory { fun createProjectEnvironment( @@ -251,6 +253,18 @@ object StandaloneProjectFactory { project.registerService(VirtualFileFinderFactory::class.java, finderFactory) } + fun getDefaultJdkModulePaths( + project: Project, + jdkHome: Path?, + ): List { + 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. * @@ -364,13 +378,36 @@ object StandaloneProjectFactory { // 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 // 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) libHomePath + JAR_SEPARATOR + "modules/$pathInImage" } else 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( project: MockProject, libraryRoots: List, diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/KtSourceModuleByCompilerConfiguration.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/KtSourceModuleByCompilerConfiguration.kt index d69ec9d0147..112a0cd24a9 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/KtSourceModuleByCompilerConfiguration.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/KtSourceModuleByCompilerConfiguration.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.analysis.test.framework.project.structure import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile 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.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM 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.LanguageVersionSettings import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.test.getAnalyzerServices 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 @@ -30,7 +32,7 @@ abstract class KtModuleByCompilerConfiguration( val project: Project, val testModule: TestModule, val psiFiles: List, - testServices: TestServices, + val testServices: TestServices, ) { private val moduleProvider = testServices.ktModuleProvider private val compilerConfigurationProvider = testServices.compilerConfigurationProvider @@ -43,14 +45,29 @@ abstract class KtModuleByCompilerConfiguration( val directRegularDependencies: List by lazy(LazyThreadSafetyMode.PUBLICATION) { buildList { testModule.allDependencies.mapTo(this) { moduleProvider.getModule(it.moduleName) } - addAll( - librariesByRoots( - (configuration.jvmModularRoots + configuration.jvmClasspathRoots).map(File::toPath) - ) - ) + val roots = buildList { + addAll(configuration.jvmModularRoots.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 by lazy(LazyThreadSafetyMode.PUBLICATION) { testModule.dependsOnDependencies .map { moduleProvider.getModule(it.moduleName) } @@ -69,7 +86,7 @@ abstract class KtModuleByCompilerConfiguration( protected abstract val ktModule: KtModule - private fun librariesByRoots(roots: List): List = roots.map { LibraryByRoot(it, ktModule, project) } + private fun librariesByRoots(roots: List): List = roots.map { LibraryByRoot(it, ktModule, project, testServices) } val languageVersionSettings: LanguageVersionSettings get() = testModule.languageVersionSettings @@ -127,13 +144,14 @@ private class LibraryByRoot( private val root: Path, private val parentModule: KtModule, override val project: Project, + testServices: TestServices, ) : KtLibraryModule { + override val contentScope: GlobalSearchScope = TestModuleStructureFactory.getScopeForLibraryByRoots(listOf(root), project, testServices) override val libraryName: String get() = "Test Library $root" override val directRegularDependencies: List get() = emptyList() override val directDependsOnDependencies: List get() = emptyList() override val transitiveDependsOnDependencies: List get() = emptyList() override val directFriendDependencies: List get() = emptyList() - override val contentScope: GlobalSearchScope get() = ProjectScope.getLibrariesScope(project) override val platform: TargetPlatform get() = parentModule.platform override val analyzerServices: PlatformDependentAnalyzerServices get() = parentModule.analyzerServices override fun getBinaryRoots(): Collection = listOf(root) diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/TestModuleStructureFactory.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/TestModuleStructureFactory.kt index 12d00d3b2a3..08cdb196842 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/TestModuleStructureFactory.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/project/structure/TestModuleStructureFactory.kt @@ -173,7 +173,7 @@ object TestModuleStructureFactory { ) } - private fun getScopeForLibraryByRoots(roots: Collection, project: Project, testServices: TestServices): GlobalSearchScope { + fun getScopeForLibraryByRoots(roots: Collection, project: Project, testServices: TestServices): GlobalSearchScope { val virtualFileRoots = StandaloneProjectFactory.getVirtualFilesForLibraryRoots( roots, testServices.environmentManager.getProjectEnvironment() diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/FirLowLevelCompilerBasedTestConfigurator.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/FirLowLevelCompilerBasedTestConfigurator.kt index f092f9b6f00..5c56e2c596f 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/FirLowLevelCompilerBasedTestConfigurator.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/FirLowLevelCompilerBasedTestConfigurator.kt @@ -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.standalone.base.project.structure.KtModuleProjectStructure 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.allDirectDependenciesOfType import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleByCompilerConfiguration @@ -52,7 +53,7 @@ object FirLowLevelCompilerBasedTestConfigurator : AnalysisApiTestConfigurator() } return KtModuleProjectStructure( mainModules = mainModules, - binaryModules = mainModules.asSequence().flatMap { it.ktModule.allDirectDependenciesOfType() }.asIterable(), + binaryModules = mainModules.asSequence().flatMap { it.ktModule.allDirectDependenciesOfType() }.asIterable(), ) } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt index 8171dbceeb9..17cf2fbcbcd 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt @@ -1,4 +1,6 @@ // FIR_IDENTICAL +// IGNORE_REVERSED_RESOLVE +// IGNORE_DIAGNOSTIC_API // !DIAGNOSTICS: -UNUSED_ANONYMOUS_PARAMETER // !LANGUAGE: +MultiPlatformProjects