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 17395251a0c..42464a2eec8 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 @@ -9,14 +9,24 @@ import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.backend.common.CommonKLibResolver +import org.jetbrains.kotlin.fir.BinaryModuleData import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.java.FirJavaFacade import org.jetbrains.kotlin.fir.java.deserialization.JvmClassFileBasedSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider +import org.jetbrains.kotlin.fir.session.KlibBasedSymbolProvider +import org.jetbrains.kotlin.fir.session.MetadataSymbolProvider +import org.jetbrains.kotlin.fir.session.NativeForwardDeclarationsSymbolProvider +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.library.metadata.impl.KlibResolvedModuleDescriptorsFactoryImpl.Companion.FORWARD_DECLARATIONS_MODULE_NAME +import org.jetbrains.kotlin.load.kotlin.PackageAndMetadataPartProvider import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory +import org.jetbrains.kotlin.util.DummyLogger class LLFirStandaloneLibrarySymbolProviderFactory(private val project: Project) : LLFirLibrarySymbolProviderFactory() { override fun createJvmLibrarySymbolProvider( @@ -39,4 +49,68 @@ class LLFirStandaloneLibrarySymbolProviderFactory(private val project: Project) ) ) } + + override fun createCommonLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + packagePartProvider: PackagePartProvider, + scope: GlobalSearchScope, + ): List { + return listOf( + MetadataSymbolProvider( + session, + moduleDataProvider, + kotlinScopeProvider, + packagePartProvider as PackageAndMetadataPartProvider, + VirtualFileFinderFactory.getInstance(project).create(scope), + ) + ) + } + + override fun createNativeLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + scope: GlobalSearchScope, + ): List { + val forwardDeclarationsModuleData = BinaryModuleData.createDependencyModuleData( + FORWARD_DECLARATIONS_MODULE_NAME, + moduleDataProvider.platform, + moduleDataProvider.analyzerServices, + ).apply { + bindSession(session) + } + val kLibs = moduleData.getLibraryKLibs() + return listOfNotNull( + KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, kLibs), + NativeForwardDeclarationsSymbolProvider(session, forwardDeclarationsModuleData, kotlinScopeProvider, kLibs), + ) + } + + override fun createJsLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + scope: GlobalSearchScope, + ): List { + val kLibs = moduleData.getLibraryKLibs() + + return listOf( + KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, kLibs) + ) + } + + + private fun LLFirModuleData.getLibraryKLibs(): List { + val ktLibraryModule = ktModule as? KtLibraryModule ?: return emptyList() + val resolveResult = CommonKLibResolver.resolve( + ktLibraryModule.getBinaryRoots().map { it.toString() }, + DummyLogger + ) + return resolveResult.getFullResolvedList().map { it.library } + } } \ 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 09c15d5d1ad..2aeb12628d4 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 @@ -26,12 +26,16 @@ import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.CommonPlatforms +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.js.JsPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test +import java.nio.file.Path import java.nio.file.Paths @OptIn(KtAnalysisApiInternals::class) @@ -74,33 +78,18 @@ class StandaloneSessionBuilderTest { } @Test - fun testKotlinSdkSessionBuilder() { - lateinit var sourceModule: KtSourceModule - val session = buildStandaloneAnalysisAPISession { - registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + fun testKotlinStdlibJvm() { + doTestKotlinStdLibResolve(JvmPlatforms.defaultJvmPlatform, ForTestCompileRuntime.runtimeJarForTests().toPath()) + } - buildKtModuleProvider { - platform = JvmPlatforms.defaultJvmPlatform - val stdlib = addModule( - buildKtLibraryModule { - addBinaryRoot(ForTestCompileRuntime.runtimeJarForTests().toPath()) - platform = JvmPlatforms.defaultJvmPlatform - libraryName = "stdlib" - } - ) - sourceModule = addModule( - buildKtSourceModule { - addSourceRoot(testDataPath("stdlibFunctionUsage")) - addRegularDependency(stdlib) - platform = JvmPlatforms.defaultJvmPlatform - moduleName = "source" - } - ) - } - } - val ktFile = session.modulesWithFiles.getValue(sourceModule).single() as KtFile - val ktCallExpression = ktFile.findDescendantOfType()!! - ktCallExpression.assertIsCallOf(CallableId(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, Name.identifier("listOf"))) + @Test + fun testKotlinStdLibCommon() { + doTestKotlinStdLibResolve(CommonPlatforms.defaultCommonPlatform, Paths.get("dist/common/kotlin-stdlib-common.jar")) + } + + @Test + fun testKotlinStdLibJs() { + doTestKotlinStdLibResolve(JsPlatforms.defaultJsPlatform, Paths.get("dist/kotlinc/lib/kotlin-stdlib-js.jar")) } @Test @@ -133,6 +122,35 @@ class StandaloneSessionBuilderTest { ktCallExpression.assertIsCallOf(CallableId(FqName.ROOT, Name.identifier("foo"))) } + private fun doTestKotlinStdLibResolve(targetPlatform: TargetPlatform, platformStdlibPath: Path) { + lateinit var sourceModule: KtSourceModule + val session = buildStandaloneAnalysisAPISession { + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + + buildKtModuleProvider { + platform = targetPlatform + val stdlib = addModule( + buildKtLibraryModule { + addBinaryRoot(platformStdlibPath) + platform = targetPlatform + libraryName = "stdlib" + } + ) + sourceModule = addModule( + buildKtSourceModule { + addSourceRoot(testDataPath("stdlibFunctionUsage")) + addRegularDependency(stdlib) + platform = targetPlatform + moduleName = "source" + } + ) + } + } + val ktFile = session.modulesWithFiles.getValue(sourceModule).single() as KtFile + val ktCallExpression = ktFile.findDescendantOfType()!! + ktCallExpression.assertIsCallOf(CallableId(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, Name.identifier("listOf"))) + } + private fun KtCallExpression.assertIsCallOf(callableId: CallableId) { analyze(this) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySymbolProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySymbolProviderFactory.kt index 2b3ec46c1f1..b46aa4d5cb2 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySymbolProviderFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySymbolProviderFactory.kt @@ -25,6 +25,32 @@ abstract class LLFirLibrarySymbolProviderFactory { scope: GlobalSearchScope, ): List + abstract fun createCommonLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + packagePartProvider: PackagePartProvider, + scope: GlobalSearchScope, + ): List + + abstract fun createNativeLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + scope: GlobalSearchScope, + ): List + + + abstract fun createJsLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + scope: GlobalSearchScope, + ): List + companion object { fun getService(project: Project): LLFirLibrarySymbolProviderFactory = project.getService(LLFirLibrarySymbolProviderFactory::class.java) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt index 8429bb69c0a..fe7af2499d7 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirCommonSessionFactory.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.createStubBasedFirSymbolProviderForCommonMetadataFiles @@ -90,8 +91,11 @@ internal class LLFirCommonSessionFactory(project: Project) : LLFirAbstractSessio val moduleDataProvider = SingleModuleDataProvider(moduleData) val packagePartProvider = project.createPackagePartProvider(scope) return buildList { - add(createStubBasedFirSymbolProviderForCommonMetadataFiles(project, scope, session, moduleDataProvider, kotlinScopeProvider)) - add(createStubBasedFirSymbolProviderForKotlinNativeMetadataFiles(project, scope, session, moduleDataProvider, kotlinScopeProvider)) + addAll( + LLFirLibrarySymbolProviderFactory.getService(project).createCommonLibrarySymbolProvider( + session, moduleData, kotlinScopeProvider, moduleDataProvider, packagePartProvider, scope, + ) + ) addIfNotNull( OptionalAnnotationClassesProvider.createIfNeeded( diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt index b4c0f518fa5..feb94a7a3c2 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirJsSessionFactory.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule @@ -20,6 +21,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.FirPlatformDiagnosticSuppresso import org.jetbrains.kotlin.fir.analysis.js.checkers.FirJsPlatformDiagnosticSuppressor import org.jetbrains.kotlin.fir.analysis.jvm.FirJvmOverridesBackwardCompatibilityHelper import org.jetbrains.kotlin.fir.declarations.FirTypeSpecificityComparatorProvider +import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider @@ -80,7 +82,9 @@ internal class LLFirJsSessionFactory(project: Project) : LLFirAbstractSessionFac builtinTypes: BuiltinTypes, scope: GlobalSearchScope, ): List { - return emptyList() // TODO(kirpichenkov) + val moduleDataProvider = SingleModuleDataProvider(moduleData) + return LLFirLibrarySymbolProviderFactory.getService(project) + .createJsLibrarySymbolProvider(session, moduleData, kotlinScopeProvider, moduleDataProvider, scope) } private fun LLFirSession.registerModuleIndependentJsComponents() { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt index c263b9ec622..a27cf92a1bb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNativeSessionFactory.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySymbolProviderFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirModuleWithDependenciesSymbolProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.createStubBasedFirSymbolProviderForKotlinNativeMetadataFiles @@ -82,9 +83,9 @@ internal class LLFirNativeSessionFactory(project: Project) : LLFirAbstractSessio val moduleDataProvider = SingleModuleDataProvider(moduleData) val packagePartProvider = project.createPackagePartProvider(scope) return buildList { - add( - createStubBasedFirSymbolProviderForKotlinNativeMetadataFiles( - project, scope, session, moduleDataProvider, kotlinScopeProvider + addAll( + LLFirLibrarySymbolProviderFactory.getService(project).createNativeLibrarySymbolProvider( + session, moduleData, kotlinScopeProvider, moduleDataProvider, scope ) ) addIfNotNull( diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/LLStubBasedLibrarySymbolProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/LLStubBasedLibrarySymbolProviderFactory.kt index 81eacbcc23d..065ff54e91e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/LLStubBasedLibrarySymbolProviderFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/LLStubBasedLibrarySymbolProviderFactory.kt @@ -27,7 +27,7 @@ class LLStubBasedLibrarySymbolProviderFactory(private val project: Project) : LL moduleDataProvider: SingleModuleDataProvider, firJavaFacade: FirJavaFacade, packagePartProvider: PackagePartProvider, - scope: GlobalSearchScope + scope: GlobalSearchScope, ): List { return buildList { //stub based provider here works over kotlin-only indices and thus provides only kotlin declarations @@ -38,4 +38,47 @@ class LLStubBasedLibrarySymbolProviderFactory(private val project: Project) : LL add(LLFirJavaSymbolProvider(session, moduleData, project, scope)) } } + + override fun createCommonLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + packagePartProvider: PackagePartProvider, + scope: GlobalSearchScope, + ): List { + return buildList { + add(createStubBasedFirSymbolProviderForCommonMetadataFiles(project, scope, session, moduleDataProvider, kotlinScopeProvider)) + add( + // klib metadata symbol provider + createStubBasedFirSymbolProviderForKotlinNativeMetadataFiles( + project, scope, session, moduleDataProvider, kotlinScopeProvider + ) + ) + } + } + + override fun createNativeLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + scope: GlobalSearchScope, + ): List { + return listOf( + createStubBasedFirSymbolProviderForKotlinNativeMetadataFiles( + project, scope, session, moduleDataProvider, kotlinScopeProvider + ) + ) + } + + override fun createJsLibrarySymbolProvider( + session: FirSession, + moduleData: LLFirModuleData, + kotlinScopeProvider: FirKotlinScopeProvider, + moduleDataProvider: SingleModuleDataProvider, + scope: GlobalSearchScope, + ): List { + return emptyList() // TODO(kirpichenkov) + } }