[Analysis API Standalone] use compiler FirSymbolProvider for standalone mode

^KT-61371 fixed
This commit is contained in:
Ilya Kirillov
2023-09-13 11:41:26 +02:00
committed by Space Team
parent d377d87c77
commit b25185530f
7 changed files with 203 additions and 33 deletions
@@ -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<FirSymbolProvider> {
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<FirSymbolProvider> {
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<FirSymbolProvider> {
val kLibs = moduleData.getLibraryKLibs()
return listOf(
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, kLibs)
)
}
private fun LLFirModuleData.getLibraryKLibs(): List<KotlinLibrary> {
val ktLibraryModule = ktModule as? KtLibraryModule ?: return emptyList()
val resolveResult = CommonKLibResolver.resolve(
ktLibraryModule.getBinaryRoots().map { it.toString() },
DummyLogger
)
return resolveResult.getFullResolvedList().map { it.library }
}
}
@@ -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>()!!
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>()!!
ktCallExpression.assertIsCallOf(CallableId(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, Name.identifier("listOf")))
}
private fun KtCallExpression.assertIsCallOf(callableId: CallableId) {
analyze(this) {
@@ -25,6 +25,32 @@ abstract class LLFirLibrarySymbolProviderFactory {
scope: GlobalSearchScope,
): List<FirSymbolProvider>
abstract fun createCommonLibrarySymbolProvider(
session: FirSession,
moduleData: LLFirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider,
moduleDataProvider: SingleModuleDataProvider,
packagePartProvider: PackagePartProvider,
scope: GlobalSearchScope,
): List<FirSymbolProvider>
abstract fun createNativeLibrarySymbolProvider(
session: FirSession,
moduleData: LLFirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider,
moduleDataProvider: SingleModuleDataProvider,
scope: GlobalSearchScope,
): List<FirSymbolProvider>
abstract fun createJsLibrarySymbolProvider(
session: FirSession,
moduleData: LLFirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider,
moduleDataProvider: SingleModuleDataProvider,
scope: GlobalSearchScope,
): List<FirSymbolProvider>
companion object {
fun getService(project: Project): LLFirLibrarySymbolProviderFactory =
project.getService(LLFirLibrarySymbolProviderFactory::class.java)
@@ -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(
@@ -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<FirSymbolProvider> {
return emptyList() // TODO(kirpichenkov)
val moduleDataProvider = SingleModuleDataProvider(moduleData)
return LLFirLibrarySymbolProviderFactory.getService(project)
.createJsLibrarySymbolProvider(session, moduleData, kotlinScopeProvider, moduleDataProvider, scope)
}
private fun LLFirSession.registerModuleIndependentJsComponents() {
@@ -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(
@@ -27,7 +27,7 @@ class LLStubBasedLibrarySymbolProviderFactory(private val project: Project) : LL
moduleDataProvider: SingleModuleDataProvider,
firJavaFacade: FirJavaFacade,
packagePartProvider: PackagePartProvider,
scope: GlobalSearchScope
scope: GlobalSearchScope,
): List<FirSymbolProvider> {
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<FirSymbolProvider> {
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<FirSymbolProvider> {
return listOf(
createStubBasedFirSymbolProviderForKotlinNativeMetadataFiles(
project, scope, session, moduleDataProvider, kotlinScopeProvider
)
)
}
override fun createJsLibrarySymbolProvider(
session: FirSession,
moduleData: LLFirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider,
moduleDataProvider: SingleModuleDataProvider,
scope: GlobalSearchScope,
): List<FirSymbolProvider> {
return emptyList() // TODO(kirpichenkov)
}
}