diff --git a/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/LLFirStandaloneLibrarySymbolProviderFactory.kt b/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/LLFirStandaloneLibrarySymbolProviderFactory.kt index b19740d0918..acd18090dc9 100644 --- a/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/LLFirStandaloneLibrarySymbolProviderFactory.kt +++ b/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/LLFirStandaloneLibrarySymbolProviderFactory.kt @@ -60,15 +60,21 @@ class LLFirStandaloneLibrarySymbolProviderFactory(private val project: Project) packagePartProvider: PackagePartProvider, scope: GlobalSearchScope, ): List { - return listOf( - MetadataSymbolProvider( - session, - moduleDataProvider, - kotlinScopeProvider, - packagePartProvider as PackageAndMetadataPartProvider, - VirtualFileFinderFactory.getInstance(project).create(scope), + return buildList { + add( + MetadataSymbolProvider( + session, + moduleDataProvider, + kotlinScopeProvider, + packagePartProvider as PackageAndMetadataPartProvider, + VirtualFileFinderFactory.getInstance(project).create(scope), + ) ) - ) + val kLibs = moduleData.getLibraryKLibs() + if (kLibs.isNotEmpty()) { + add(KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, kLibs)) + } + } } override fun createNativeLibrarySymbolProvider( diff --git a/analysis/analysis-api-standalone/testData/sessionBuilder/resolveAgainstCommonKLib/klibSrc/commonKLibFunction.kt b/analysis/analysis-api-standalone/testData/sessionBuilder/resolveAgainstCommonKLib/klibSrc/commonKLibFunction.kt new file mode 100644 index 00000000000..e068d584920 --- /dev/null +++ b/analysis/analysis-api-standalone/testData/sessionBuilder/resolveAgainstCommonKLib/klibSrc/commonKLibFunction.kt @@ -0,0 +1,5 @@ +package commonKLib + +fun commonKLibFunction(arg: String): Int { + return 1 +} \ No newline at end of file diff --git a/analysis/analysis-api-standalone/testData/sessionBuilder/resolveAgainstCommonKLib/src/main.kt b/analysis/analysis-api-standalone/testData/sessionBuilder/resolveAgainstCommonKLib/src/main.kt new file mode 100644 index 00000000000..d7931267c5c --- /dev/null +++ b/analysis/analysis-api-standalone/testData/sessionBuilder/resolveAgainstCommonKLib/src/main.kt @@ -0,0 +1,5 @@ +import commonKLib.commonKLibFunction + +fun main() { + commonKLibFunction("aaa") +} \ No newline at end of file diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt index 901e1715eab..e5cf0995aac 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt @@ -80,6 +80,38 @@ class StandaloneSessionBuilderTest { } } + @Test + fun testResolveAgainstCommonKlib() { + lateinit var sourceModule: KtSourceModule + val session = buildStandaloneAnalysisAPISession { + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + + buildKtModuleProvider { + platform = CommonPlatforms.defaultCommonPlatform + val kLib = addModule( + buildKtLibraryModule { + val compiledKLibRoot = compileCommonKlib(testDataPath("resolveAgainstCommonKLib/klibSrc")) + addBinaryRoot(compiledKLibRoot) + platform = CommonPlatforms.defaultCommonPlatform + libraryName = "klib" + } + ) + sourceModule = addModule( + buildKtSourceModule { + addSourceRoot(testDataPath("resolveAgainstCommonKLib/src")) + addRegularDependency(kLib) + platform = CommonPlatforms.defaultCommonPlatform + moduleName = "source" + } + ) + } + } + val ktFile = session.modulesWithFiles.getValue(sourceModule).single() as KtFile + + val ktCallExpression = ktFile.findDescendantOfType()!! + ktCallExpression.assertIsCallOf(CallableId(FqName("commonKLib"), Name.identifier("commonKLibFunction"))) + } + @Test fun testKotlinStdlibJvm() { doTestKotlinStdLibResolve(JvmPlatforms.defaultJvmPlatform, PathUtil.kotlinPathsForDistDirectory.stdlibPath.toPath()) diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt index 0b7c2388ba1..f3b59f59896 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/sessionBuilderTestUtils.kt @@ -5,9 +5,30 @@ package org.jetbrains.kotlin.analysis.api.standalone.fir.test.cases.session.builder +import org.jetbrains.kotlin.test.MockLibraryUtil +import org.jetbrains.kotlin.test.util.KtTestUtil +import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.absolutePathString +import kotlin.io.path.extension +import kotlin.streams.asSequence internal fun testDataPath(path: String): Path { return Paths.get("analysis/analysis-api-standalone/testData/sessionBuilder").resolve(path) +} + + +internal fun compileCommonKlib(kLibSourcesRoot: Path): Path { + val ktFiles = Files.walk(kLibSourcesRoot).asSequence().filter { it.extension == "kt" }.toList() + val testKlib = KtTestUtil.tmpDir("testLibrary").resolve("library.klib").toPath() + + val arguments = buildList { + ktFiles.mapTo(this) { it.absolutePathString() } + add("-d") + add(testKlib.absolutePathString()) + } + MockLibraryUtil.runMetadataCompiler(arguments) + + return testKlib } \ No newline at end of file diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt index c60f26675fa..8edae315366 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.js.K2JSCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler +import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler import org.jetbrains.kotlin.preloading.ClassPreloadingUtils import org.jetbrains.kotlin.preloading.Preloader import org.jetbrains.kotlin.test.KtAssert.assertTrue @@ -177,6 +178,10 @@ object MockLibraryUtil { runCompiler(compiler2JSClass, args) } + fun runMetadataCompiler(args: List) { + runCompiler(compiler2MetadataClass, args) + } + // Runs compiler in custom class loader to avoid effects caused by replacing Application with another one created in compiler. private fun runCompiler(compilerClass: Class<*>, args: List) { val outStream = ByteArrayOutputStream() @@ -223,6 +228,9 @@ object MockLibraryUtil { private val compiler2JSClass: Class<*> @Synchronized get() = loadCompilerClass(K2JSCompiler::class) + private val compiler2MetadataClass: Class<*> + @Synchronized get() = loadCompilerClass(K2MetadataCompiler::class) + @Synchronized private fun loadCompilerClass(compilerClass: KClass>): Class<*> { val classLoader = compilerClassLoader.get() ?: createCompilerClassLoader().also { classLoader ->