[Analysis API Standalone] fix exception on invalid KLib from symbol provider

^KT-62244 fixed
This commit is contained in:
Ilya Kirillov
2023-10-06 21:20:44 +02:00
committed by Space Team
parent d005d1cd68
commit 4d38cc4548
3 changed files with 54 additions and 8 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.standalone.base.project.structure package org.jetbrains.kotlin.analysis.api.standalone.base.project.structure
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope 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.LLFirLibrarySymbolProviderFactory
@@ -26,7 +27,7 @@ import org.jetbrains.kotlin.library.metadata.impl.KlibResolvedModuleDescriptorsF
import org.jetbrains.kotlin.load.kotlin.PackageAndMetadataPartProvider import org.jetbrains.kotlin.load.kotlin.PackageAndMetadataPartProvider
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.util.DummyLogger import java.lang.IllegalStateException
class LLFirStandaloneLibrarySymbolProviderFactory(private val project: Project) : LLFirLibrarySymbolProviderFactory() { class LLFirStandaloneLibrarySymbolProviderFactory(private val project: Project) : LLFirLibrarySymbolProviderFactory() {
override fun createJvmLibrarySymbolProvider( override fun createJvmLibrarySymbolProvider(
@@ -107,10 +108,35 @@ class LLFirStandaloneLibrarySymbolProviderFactory(private val project: Project)
private fun LLFirModuleData.getLibraryKLibs(): List<KotlinLibrary> { private fun LLFirModuleData.getLibraryKLibs(): List<KotlinLibrary> {
val ktLibraryModule = ktModule as? KtLibraryModule ?: return emptyList() val ktLibraryModule = ktModule as? KtLibraryModule ?: return emptyList()
val resolveResult = CommonKLibResolver.resolve( val resolveResult = CommonKLibResolver.resolve(
ktLibraryModule.getBinaryRoots().map { it.toString() }, ktLibraryModule.getBinaryRoots().map { it.toString() },
DummyLogger IntellijLogBasedLogger,
lenient = true,
) )
return resolveResult.getFullResolvedList().map { it.library } return resolveResult.getFullResolvedList().map { it.library }
} }
}
companion object {
private val LOG = Logger.getInstance(LLFirStandaloneLibrarySymbolProviderFactory::class.java)
}
private object IntellijLogBasedLogger : org.jetbrains.kotlin.util.Logger {
override fun log(message: String) {
LOG.info(message)
}
override fun error(message: String) {
LOG.error(message)
}
override fun warning(message: String) {
LOG.warn(message)
}
override fun fatal(message: String): Nothing {
throw IllegalStateException(message)
}
}
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@@ -92,6 +93,18 @@ class StandaloneSessionBuilderTest {
doTestKotlinStdLibResolve(JsPlatforms.defaultJsPlatform, Paths.get("dist/kotlinc/lib/kotlin-stdlib-js.jar")) doTestKotlinStdLibResolve(JsPlatforms.defaultJsPlatform, Paths.get("dist/kotlinc/lib/kotlin-stdlib-js.jar"))
} }
@Test
fun testKotlinStdLibJsWithInvalidKlib() {
doTestKotlinStdLibResolve(
JsPlatforms.defaultJsPlatform,
Paths.get("dist/kotlinc/lib/kotlin-stdlib-js.jar"),
additionalStdlibRoots = listOf(
Paths.get(System.getProperty("java.home")), // directory which exists and does not contain KLibs inside
ForTestCompileRuntime.runtimeJarForTests().toPath(), // file which exists and not a KLib
)
)
}
@Test @Test
fun testKotlinSourceModuleSessionBuilder() { fun testKotlinSourceModuleSessionBuilder() {
lateinit var sourceModule: KtSourceModule lateinit var sourceModule: KtSourceModule
@@ -122,7 +135,10 @@ class StandaloneSessionBuilderTest {
ktCallExpression.assertIsCallOf(CallableId(FqName.ROOT, Name.identifier("foo"))) ktCallExpression.assertIsCallOf(CallableId(FqName.ROOT, Name.identifier("foo")))
} }
private fun doTestKotlinStdLibResolve(targetPlatform: TargetPlatform, platformStdlibPath: Path) { private fun doTestKotlinStdLibResolve(
targetPlatform: TargetPlatform, platformStdlibPath: Path,
additionalStdlibRoots: List<Path> = emptyList(),
) {
lateinit var sourceModule: KtSourceModule lateinit var sourceModule: KtSourceModule
val session = buildStandaloneAnalysisAPISession { val session = buildStandaloneAnalysisAPISession {
registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider())
@@ -132,6 +148,7 @@ class StandaloneSessionBuilderTest {
val stdlib = addModule( val stdlib = addModule(
buildKtLibraryModule { buildKtLibraryModule {
addBinaryRoot(platformStdlibPath) addBinaryRoot(platformStdlibPath)
addBinaryRoots(additionalStdlibRoots)
platform = targetPlatform platform = targetPlatform
libraryName = "stdlib" libraryName = "stdlib"
} }
@@ -20,20 +20,23 @@ object CommonKLibResolver {
fun resolve( fun resolve(
libraries: Collection<String>, libraries: Collection<String>,
logger: Logger, logger: Logger,
zipAccessor: ZipFileSystemAccessor? = null zipAccessor: ZipFileSystemAccessor? = null,
lenient: Boolean = false,
): KotlinLibraryResolveResult = ): KotlinLibraryResolveResult =
resolveWithoutDependencies( resolveWithoutDependencies(
libraries, libraries,
logger, logger,
zipAccessor zipAccessor,
lenient,
).resolveWithDependencies() ).resolveWithDependencies()
fun resolveWithoutDependencies( fun resolveWithoutDependencies(
libraries: Collection<String>, libraries: Collection<String>,
logger: Logger, logger: Logger,
zipAccessor: ZipFileSystemAccessor? zipAccessor: ZipFileSystemAccessor?,
lenient: Boolean = false,
): KLibResolution { ): KLibResolution {
val unresolvedLibraries = libraries.map { UnresolvedLibrary(it, null) } val unresolvedLibraries = libraries.map { UnresolvedLibrary(it, null, lenient) }
val libraryAbsolutePaths = libraries.map { File(it).absolutePath } val libraryAbsolutePaths = libraries.map { File(it).absolutePath }
// Configure the resolver to only work with absolute paths for now. // Configure the resolver to only work with absolute paths for now.
val libraryResolver = KLibResolverHelper( val libraryResolver = KLibResolverHelper(