[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:
committed by
Space Team
parent
866368cf69
commit
9ea344fe76
+14
-1
@@ -12,11 +12,17 @@ import com.intellij.psi.impl.compiled.ClassFileStubBuilder
|
||||
import com.intellij.psi.stubs.PsiFileStub
|
||||
import com.intellij.util.indexing.FileContent
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
|
||||
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder
|
||||
@@ -56,7 +62,12 @@ open class KotlinMetadataStubBuilder(
|
||||
val fileStub = createFileStub(packageFqName, isScript = false)
|
||||
createPackageDeclarationsStubs(
|
||||
fileStub, context,
|
||||
ProtoContainer.Package(packageFqName, context.nameResolver, context.typeTable, source = null),
|
||||
ProtoContainer.Package(
|
||||
packageFqName,
|
||||
context.nameResolver,
|
||||
context.typeTable,
|
||||
source = createCallableSource(file, content.fileName)
|
||||
),
|
||||
packageProto
|
||||
)
|
||||
for (classProto in file.classesToDecompile) {
|
||||
@@ -69,6 +80,8 @@ open class KotlinMetadataStubBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun createCallableSource(file: FileWithMetadata.Compatible, filename: String): SourceElement? = null
|
||||
|
||||
sealed class FileWithMetadata {
|
||||
class Incompatible(val version: BinaryVersion) : FileWithMetadata()
|
||||
|
||||
|
||||
+23
-1
@@ -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 ->
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+2
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.providers.createPackageProvider
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.caches.FirCache
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
|
||||
import org.jetbrains.kotlin.fir.java.deserialization.KotlinBuiltins
|
||||
@@ -28,7 +29,6 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
|
||||
typealias DeserializedTypeAliasPostProcessor = (FirTypeAliasSymbol) -> Unit
|
||||
|
||||
@@ -124,7 +124,7 @@ internal open class StubBasedFirDeserializedSymbolProvider(
|
||||
StubBasedAnnotationDeserializer(session),
|
||||
kotlinScopeProvider,
|
||||
parentContext = context,
|
||||
containerSource = if (initialOrigin == FirDeclarationOrigin.BuiltIns) null else JvmStubDeserializedContainerSource(classId),
|
||||
containerSource = JvmStubDeserializedContainerSource(classId),
|
||||
deserializeNestedClass = this::getClass,
|
||||
initialOrigin = initialOrigin
|
||||
)
|
||||
|
||||
+1
-1
@@ -169,7 +169,7 @@ internal class StubBasedFirDeserializationContext(
|
||||
callableId.packageName,
|
||||
callableId.className,
|
||||
parameterListOwner,
|
||||
containerSource = containerSource.takeIf { initialOrigin != FirDeclarationOrigin.BuiltIns },
|
||||
containerSource = containerSource,
|
||||
outerClassSymbol = null,
|
||||
symbol,
|
||||
initialOrigin
|
||||
|
||||
@@ -36,7 +36,7 @@ object KotlinStubVersions {
|
||||
|
||||
// BuiltIn stub version should be increased if changes are made to builtIn stub building subsystem (org.jetbrains.kotlin.idea.decompiler.builtIns)
|
||||
// Increasing this version will lead to reindexing of all builtIn files (see KotlinBuiltInFileType).
|
||||
const val BUILTIN_STUB_VERSION = BINARY_STUB_VERSION + 3
|
||||
const val BUILTIN_STUB_VERSION = BINARY_STUB_VERSION + 4
|
||||
|
||||
// JS stub version should be increased if changes are made to js stub building subsystem (org.jetbrains.kotlin.idea.decompiler.js)
|
||||
// Increasing this version will lead to reindexing of js binary files (see KotlinJavaScriptMetaFileType).
|
||||
|
||||
Reference in New Issue
Block a user