[decompiler] fix ambiguities to builtin members resolve in K2 IDE

If a user has multiple kotlin-stdlib libraries in a project, all those stdlib libraries will contain builtins
which will result in resolution ambiguities.

To prevent such kind of ambiguities inside LLFirDependenciesSymbolProvider,
callables are grouped by facade class name.
Only matching callables from the first facade are used.

Facade is a Kotlin/JVM-term so right now it works only for JVM targets.
Builtins are also used in JVM, so the current solution is to have a Facade name also for builtins.

^KTIJ-26760
This commit is contained in:
Ilya Kirillov
2023-08-25 10:50:29 +02:00
committed by Space Team
parent 866368cf69
commit 9ea344fe76
6 changed files with 43 additions and 8 deletions
@@ -6,10 +6,14 @@ import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinMetadataStubBuilder
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
@@ -21,16 +25,34 @@ class KotlinBuiltInDecompiler : KotlinMetadataDecompiler<BuiltInsBinaryVersion>(
FlexibleTypeDeserializer.ThrowException, { BuiltInsBinaryVersion.INSTANCE }, { BuiltInsBinaryVersion.INVALID_VERSION },
KotlinStubVersions.BUILTIN_STUB_VERSION
) {
override val metadataStubBuilder: KotlinMetadataStubBuilder =
KotlinBuiltInMetadataStubBuilder(::readFileSafely)
override fun readFile(bytes: ByteArray, file: VirtualFile): KotlinMetadataStubBuilder.FileWithMetadata? {
return BuiltInDefinitionFile.read(bytes, file)
}
}
private class KotlinBuiltInMetadataStubBuilder(
readFile: (VirtualFile, ByteArray) -> FileWithMetadata?,
) : KotlinMetadataStubBuilder(KotlinStubVersions.BUILTIN_STUB_VERSION, KotlinBuiltInFileType, { BuiltInSerializerProtocol }, readFile) {
override fun createCallableSource(file: FileWithMetadata.Compatible, filename: String): SourceElement? {
val fileNameForFacade = when (val withoutExtension = filename.removeSuffix(BuiltInSerializerProtocol.DOT_DEFAULT_EXTENSION)) {
// this is the filename used in stdlib, others should match
"kotlin" -> "library"
else -> withoutExtension
}
val facadeFqName = PackagePartClassUtils.getPackagePartFqName(file.packageFqName, fileNameForFacade)
return JvmPackagePartSource(JvmClassName.byClassId(ClassId.topLevel(facadeFqName)), null, file.proto.`package`, file.nameResolver)
}
}
class BuiltInDefinitionFile(
proto: ProtoBuf.PackageFragment,
version: BuiltInsBinaryVersion,
val packageDirectory: VirtualFile,
val isMetadata: Boolean
val isMetadata: Boolean,
) : KotlinMetadataStubBuilder.FileWithMetadata.Compatible(proto, version, BuiltInSerializerProtocol) {
override val classesToDecompile: List<ProtoBuf.Class>
get() = super.classesToDecompile.let { classes ->
@@ -31,7 +31,7 @@ abstract class KotlinMetadataDecompiler<out V : BinaryVersion>(
private val invalidBinaryVersion: () -> V,
stubVersion: Int
) : ClassFileDecompilers.Full() {
private val metadataStubBuilder: KotlinMetadataStubBuilder =
protected open val metadataStubBuilder: KotlinMetadataStubBuilder =
KotlinMetadataStubBuilder(stubVersion, fileType, serializerProtocol, ::readFileSafely)
private val renderer: DescriptorRenderer by lazy {
@@ -61,7 +61,7 @@ abstract class KotlinMetadataDecompiler<out V : BinaryVersion>(
@TestOnly
fun readFile(file: VirtualFile) = readFileSafely(file)
private fun readFileSafely(file: VirtualFile, content: ByteArray? = null): KotlinMetadataStubBuilder.FileWithMetadata? {
protected fun readFileSafely(file: VirtualFile, content: ByteArray? = null): KotlinMetadataStubBuilder.FileWithMetadata? {
if (!file.isValid) return null
return try {