diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt index 896af1a7dc0..77a485d5048 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/BuiltInsBinaryVersion.kt @@ -31,6 +31,9 @@ class BuiltInsBinaryVersion(vararg numbers: Int) : BinaryVersion(*numbers) { @JvmField val INSTANCE = BuiltInsBinaryVersion(1, 0, 0) + @JvmField + val INVALID_VERSION = BuiltInsBinaryVersion() + fun readFrom(stream: InputStream): BuiltInsBinaryVersion { val dataInput = DataInputStream(stream) return BuiltInsBinaryVersion(*(1..dataInput.readInt()).map { dataInput.readInt() }.toIntArray()) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInDecompiler.kt index be8adbe3144..3240934c3c7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInDecompiler.kt @@ -18,130 +18,59 @@ package org.jetbrains.kotlin.idea.decompiler.builtIns import com.intellij.ide.highlighter.JavaClassFileType import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.FileViewProvider -import com.intellij.psi.PsiManager -import com.intellij.psi.compiled.ClassFileDecompilers import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.builtins.BuiltInsBinaryVersion -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider -import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile -import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDeserializerForDecompiler -import org.jetbrains.kotlin.idea.decompiler.common.createIncompatibleAbiVersionDecompiledText -import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText -import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText -import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions +import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata +import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDecompiler import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.serialization.ProtoBuf -import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf -import org.jetbrains.kotlin.serialization.deserialization.ClassDeserializer import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment -import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl -import org.jetbrains.kotlin.utils.addIfNotNull import java.io.ByteArrayInputStream -class KotlinBuiltInDecompiler : ClassFileDecompilers.Full() { - private val stubBuilder = KotlinBuiltInStubBuilder() - - override fun accepts(file: VirtualFile): Boolean { - return file.fileType == KotlinBuiltInFileType - } - - override fun getStubBuilder() = stubBuilder - - override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean): FileViewProvider { - return KotlinDecompiledFileViewProvider(manager, file, physical) { provider -> - if (BuiltInDefinitionFile.read(provider.virtualFile) == null) { - null - } - else { - KtDecompiledFile(provider) { file -> - buildDecompiledTextForBuiltIns(file) - } - } - } +class KotlinBuiltInDecompiler : KotlinMetadataDecompiler( + KotlinBuiltInFileType, KotlinBuiltInStubBuilder(), TargetPlatform.Default, BuiltInSerializerProtocol, + FlexibleTypeDeserializer.ThrowException, BuiltInsBinaryVersion.INSTANCE, BuiltInsBinaryVersion.INVALID_VERSION +) { + override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? { + return BuiltInDefinitionFile.read(bytes, file) } } -private val decompilerRendererForBuiltIns = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() } - -fun buildDecompiledTextForBuiltIns(builtInFile: VirtualFile): DecompiledText { - if (builtInFile.fileType != KotlinBuiltInFileType) { - error("Unexpected file type ${builtInFile.fileType}") - } - - val file = BuiltInDefinitionFile.read(builtInFile) - ?: error("Unexpectedly empty built-in file: $builtInFile") - - when (file) { - is BuiltInDefinitionFile.Incompatible -> { - return createIncompatibleAbiVersionDecompiledText(BuiltInsBinaryVersion.INSTANCE, file.version) - } - is BuiltInDefinitionFile.Compatible -> { - val packageFqName = file.packageFqName - val resolver = KotlinMetadataDeserializerForDecompiler( - packageFqName, file.proto, file.nameResolver, - TargetPlatform.Default, BuiltInSerializerProtocol, FlexibleTypeDeserializer.ThrowException - ) - val declarations = arrayListOf() - declarations.addAll(resolver.resolveDeclarationsInFacade(packageFqName)) - for (classProto in file.classesToDecompile) { - val classId = file.nameResolver.getClassId(classProto.fqName) - declarations.addIfNotNull(resolver.resolveTopLevelClass(classId)) +class BuiltInDefinitionFile( + proto: ProtoBuf.PackageFragment, + val packageDirectory: VirtualFile, + val isMetadata: Boolean +) : FileWithMetadata.Compatible(proto, BuiltInSerializerProtocol) { + override val classesToDecompile: List + get() = super.classesToDecompile.let { classes -> + if (isMetadata || !FILTER_OUT_CLASSES_EXISTING_AS_JVM_CLASS_FILES) classes + else classes.filter { classProto -> + shouldDecompileBuiltInClass(nameResolver.getClassId(classProto.fqName)) } - return buildDecompiledText(packageFqName, declarations, decompilerRendererForBuiltIns) } - } -} -sealed class BuiltInDefinitionFile { - class Incompatible(val version: BuiltInsBinaryVersion) : BuiltInDefinitionFile() - - class Compatible(val proto: ProtoBuf.PackageFragment, - val packageDirectory: VirtualFile, - val isMetadata: Boolean) : BuiltInDefinitionFile() { - val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames) - val packageFqName = nameResolver.getPackageFqName(proto.`package`.getExtension(BuiltInsProtoBuf.packageFqName)) - - val classesToDecompile = - proto.class_List.filter { proto -> - val classId = nameResolver.getClassId(proto.fqName) - !classId.isNestedClass && classId !in ClassDeserializer.BLACK_LIST - }.let { classes -> - if (isMetadata || !FILTER_OUT_CLASSES_EXISTING_AS_JVM_CLASS_FILES) classes - else classes.filter { classProto -> - shouldDecompileBuiltInClass(nameResolver.getClassId(classProto.fqName)) - } - } - - private fun shouldDecompileBuiltInClass(classId: ClassId): Boolean { - val realJvmClassFileName = classId.shortClassName.asString() + "." + JavaClassFileType.INSTANCE.defaultExtension - return packageDirectory.findChild(realJvmClassFileName) == null - } + private fun shouldDecompileBuiltInClass(classId: ClassId): Boolean { + val realJvmClassFileName = classId.shortClassName.asString() + "." + JavaClassFileType.INSTANCE.defaultExtension + return packageDirectory.findChild(realJvmClassFileName) == null } companion object { var FILTER_OUT_CLASSES_EXISTING_AS_JVM_CLASS_FILES = true @TestOnly set - fun read(file: VirtualFile): BuiltInDefinitionFile? { - return read(file.contentsToByteArray(), file) - } - - fun read(contents: ByteArray, file: VirtualFile): BuiltInDefinitionFile? { + fun read(contents: ByteArray, file: VirtualFile): FileWithMetadata? { val stream = ByteArrayInputStream(contents) val version = BuiltInsBinaryVersion.readFrom(stream) if (!version.isCompatible()) { - return BuiltInDefinitionFile.Incompatible(version) + return FileWithMetadata.Incompatible(version) } val proto = ProtoBuf.PackageFragment.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry) - val result = BuiltInDefinitionFile.Compatible(proto, file.parent, file.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION) + val result = BuiltInDefinitionFile(proto, file.parent, file.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION) val packageProto = result.proto.`package` if (result.classesToDecompile.isEmpty() && packageProto.typeAliasCount == 0 && packageProto.functionCount == 0 && packageProto.propertyCount == 0) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInStubBuilder.kt index fa405e30738..c455a5e98da 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/builtIns/KotlinBuiltInStubBuilder.kt @@ -21,10 +21,11 @@ import com.intellij.psi.impl.compiled.ClassFileStubBuilder import com.intellij.psi.stubs.PsiFileStub import com.intellij.util.indexing.FileContent import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol -import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder import org.jetbrains.kotlin.idea.decompiler.common.AnnotationLoaderForStubBuilderImpl +import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata import org.jetbrains.kotlin.idea.decompiler.stubBuilder.* import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions +import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer import org.jetbrains.kotlin.serialization.deserialization.TypeTable @@ -37,10 +38,10 @@ class KotlinBuiltInStubBuilder : ClsStubBuilder() { val file = BuiltInDefinitionFile.read(content.content, virtualFile) ?: return null when (file) { - is BuiltInDefinitionFile.Incompatible -> { + is FileWithMetadata.Incompatible -> { return createIncompatibleAbiVersionFileStub() } - is BuiltInDefinitionFile.Compatible -> { + is FileWithMetadata.Compatible -> { val packageProto = file.proto.`package` val packageFqName = file.packageFqName val nameResolver = file.nameResolver diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/KotlinMetadataDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/KotlinMetadataDecompiler.kt new file mode 100644 index 00000000000..81ea5a5ba3d --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/KotlinMetadataDecompiler.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.decompiler.common + +import com.intellij.openapi.fileTypes.FileType +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.FileViewProvider +import com.intellij.psi.PsiManager +import com.intellij.psi.compiled.ClassFileDecompilers +import com.intellij.psi.compiled.ClsStubBuilder +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider +import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile +import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText +import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText +import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.TargetPlatform +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol +import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion +import org.jetbrains.kotlin.serialization.deserialization.ClassDeserializer +import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer +import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl +import org.jetbrains.kotlin.utils.addIfNotNull +import java.io.IOException + +abstract class KotlinMetadataDecompiler( + private val fileType: FileType, + private val stubBuilder: ClsStubBuilder, + private val targetPlatform: TargetPlatform, + private val serializerProtocol: SerializerExtensionProtocol, + private val flexibleTypeDeserializer: FlexibleTypeDeserializer, + private val expectedBinaryVersion: V, + private val invalidBinaryVersion: V +) : ClassFileDecompilers.Full() { + private val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() } + + abstract fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? + + override fun accepts(file: VirtualFile) = file.fileType == fileType + + override fun getStubBuilder() = stubBuilder + + override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean): FileViewProvider { + return KotlinDecompiledFileViewProvider(manager, file, physical) { provider -> + if (readFile(provider.virtualFile) == null) { + null + } + else { + KtDecompiledFile(provider, this::buildDecompiledText) + } + } + } + + private fun readFile(file: VirtualFile): FileWithMetadata? { + if (!file.isValid) return null + + return try { + readFile(file.contentsToByteArray(), file) + } + catch (e: IOException) { + // This is needed because sometimes we're given VirtualFile instances that point to non-existent .jar entries. + // Such files are valid (isValid() returns true), but an attempt to read their contents results in a FileNotFoundException. + // Note that although calling "refresh()" instead of catching an exception would seem more correct here, + // it's not always allowed and also is likely to degrade performance + null + } + } + + private fun buildDecompiledText(virtualFile: VirtualFile): DecompiledText { + if (virtualFile.fileType != fileType) { + error("Unexpected file type ${virtualFile.fileType}") + } + + val file = readFile(virtualFile) + + return when (file) { + null -> { + createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion, invalidBinaryVersion) + } + is FileWithMetadata.Incompatible -> { + createIncompatibleAbiVersionDecompiledText(expectedBinaryVersion, file.version) + } + is FileWithMetadata.Compatible -> { + val packageFqName = file.packageFqName + val resolver = KotlinMetadataDeserializerForDecompiler( + packageFqName, file.proto, file.nameResolver, + targetPlatform, serializerProtocol, flexibleTypeDeserializer + ) + val declarations = arrayListOf() + declarations.addAll(resolver.resolveDeclarationsInFacade(packageFqName)) + for (classProto in file.classesToDecompile) { + val classId = file.nameResolver.getClassId(classProto.fqName) + declarations.addIfNotNull(resolver.resolveTopLevelClass(classId)) + } + buildDecompiledText(packageFqName, declarations, renderer) + } + } + } +} + +sealed class FileWithMetadata { + class Incompatible(val version: BinaryVersion) : FileWithMetadata() + + open class Compatible( + val proto: ProtoBuf.PackageFragment, + serializerProtocol: SerializerExtensionProtocol + ) : FileWithMetadata() { + val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames) + val packageFqName = nameResolver.getPackageFqName(proto.`package`.getExtension(serializerProtocol.packageFqName)) + + open val classesToDecompile: List = + proto.class_List.filter { proto -> + val classId = nameResolver.getClassId(proto.fqName) + !classId.isNestedClass && classId !in ClassDeserializer.BLACK_LIST + } + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.kt index f3cdc9bc019..69f0a78e9bf 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.kt @@ -17,123 +17,38 @@ package org.jetbrains.kotlin.idea.decompiler.js import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.FileViewProvider -import com.intellij.psi.PsiManager -import com.intellij.psi.compiled.ClassFileDecompilers -import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider -import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile -import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDeserializerForDecompiler -import org.jetbrains.kotlin.idea.decompiler.common.createIncompatibleAbiVersionDecompiledText -import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText -import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText -import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions +import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata +import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDecompiler import org.jetbrains.kotlin.js.resolve.JsPlatform -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.renderer.DescriptorRenderer -import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.serialization.ProtoBuf -import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer -import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer import org.jetbrains.kotlin.serialization.js.JsProtoBuf import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol import org.jetbrains.kotlin.utils.JsMetadataVersion -import org.jetbrains.kotlin.utils.addIfNotNull import java.io.ByteArrayInputStream -import java.io.IOException -class KotlinJavaScriptMetaFileDecompiler : ClassFileDecompilers.Full() { - private val stubBuilder = KotlinJavaScriptStubBuilder() - - override fun accepts(file: VirtualFile): Boolean { - return file.fileType == KotlinJavaScriptMetaFileType - } - - override fun getStubBuilder() = stubBuilder - - override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean): FileViewProvider { - return KotlinDecompiledFileViewProvider(manager, file, physical) { provider -> - KtDecompiledFile(provider, ::buildDecompiledTextFromJsMetadata) - } +class KotlinJavaScriptMetaFileDecompiler : KotlinMetadataDecompiler( + KotlinJavaScriptMetaFileType, KotlinJavaScriptStubBuilder(), JsPlatform, JsSerializerProtocol, DynamicTypeDeserializer, + JsMetadataVersion.INSTANCE, JsMetadataVersion.INVALID_VERSION +) { + override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? { + return KjsmFile.read(bytes) } } -private val decompilerRendererForJS = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() } - -// TODO: deduplicate code with KotlinBuiltInDecompiler -fun buildDecompiledTextFromJsMetadata(kjsmFile: VirtualFile): DecompiledText { - if (kjsmFile.fileType != KotlinJavaScriptMetaFileType) { - error("Unexpected file type ${kjsmFile.fileType}") - } - - val file = KjsmFile.read(kjsmFile) - - when (file) { - null -> { - return createIncompatibleAbiVersionDecompiledText(JsMetadataVersion.INSTANCE, JsMetadataVersion.INVALID_VERSION) - } - is KjsmFile.Incompatible -> { - return createIncompatibleAbiVersionDecompiledText(JsMetadataVersion.INSTANCE, file.version) - } - is KjsmFile.Compatible -> { - val packageFqName = file.packageFqName - val resolver = KotlinMetadataDeserializerForDecompiler( - packageFqName, file.proto, file.nameResolver, - JsPlatform, JsSerializerProtocol, DynamicTypeDeserializer - ) - val declarations = arrayListOf() - declarations.addAll(resolver.resolveDeclarationsInFacade(packageFqName)) - for (klass in file.classesToDecompile) { - val classId = file.nameResolver.getClassId(klass.fqName) - declarations.addIfNotNull(resolver.resolveTopLevelClass(classId)) - } - return buildDecompiledText(packageFqName, declarations, decompilerRendererForJS) - } - } -} - -// TODO: deduplicate code with BuiltInDefinitionFile -sealed class KjsmFile { - class Incompatible(val version: JsMetadataVersion) : KjsmFile() - - class Compatible(val header: JsProtoBuf.Header, val proto: ProtoBuf.PackageFragment) : KjsmFile() { - val packageFqName = FqName(header.packageFqName) - val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames) - - val classesToDecompile = - proto.class_List.filterNot { proto -> nameResolver.getClassId(proto.fqName).isNestedClass } - } - +class KjsmFile(proto: ProtoBuf.PackageFragment) : FileWithMetadata.Compatible(proto, JsSerializerProtocol) { companion object { - fun read(file: VirtualFile): KjsmFile? { - val stream = ByteArrayInputStream(readFileContentsSafely(file) ?: return null) + fun read(bytes: ByteArray): FileWithMetadata? { + val stream = ByteArrayInputStream(bytes) val version = JsMetadataVersion.readFrom(stream) if (!version.isCompatible()) { - return Incompatible(version) + return FileWithMetadata.Incompatible(version) } - val header = JsProtoBuf.Header.parseDelimitedFrom(stream) - val proto = ProtoBuf.PackageFragment.parseFrom(stream, JsSerializerProtocol.extensionRegistry) + JsProtoBuf.Header.parseDelimitedFrom(stream) - return Compatible(header, proto) - } - - private fun readFileContentsSafely(file: VirtualFile): ByteArray? { - if (!file.isValid) return null - - return try { - file.contentsToByteArray() - } - catch (e: IOException) { - // This is needed because sometimes we're given VirtualFile instances that point to non-existent .jar entries. - // Such files are valid (isValid() returns true), but an attempt to read their contents results in a FileNotFoundException. - // Note that although calling "refresh()" instead of catching an exception would seem more correct here, - // it's not always allowed and also is likely to degrade performance - null - } + return KjsmFile(ProtoBuf.PackageFragment.parseFrom(stream, JsSerializerProtocol.extensionRegistry)) } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt index c7b9c2a10c2..4bc9930f50a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt @@ -20,10 +20,11 @@ import com.intellij.psi.compiled.ClsStubBuilder import com.intellij.psi.impl.compiled.ClassFileStubBuilder import com.intellij.psi.stubs.PsiFileStub import com.intellij.util.indexing.FileContent -import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder import org.jetbrains.kotlin.idea.decompiler.common.AnnotationLoaderForStubBuilderImpl +import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata import org.jetbrains.kotlin.idea.decompiler.stubBuilder.* import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions +import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol @@ -35,13 +36,13 @@ class KotlinJavaScriptStubBuilder : ClsStubBuilder() { override fun buildFileStub(content: FileContent): PsiFileStub<*>? { val virtualFile = content.file assert(virtualFile.fileType == KotlinJavaScriptMetaFileType) { "Unexpected file type ${virtualFile.fileType}" } - val file = KjsmFile.read(virtualFile) ?: return null + val file = KjsmFile.read(content.content) ?: return null when (file) { - is KjsmFile.Incompatible -> { + is FileWithMetadata.Incompatible -> { return createIncompatibleAbiVersionFileStub() } - is KjsmFile.Compatible -> { + is FileWithMetadata.Compatible -> { val packageProto = file.proto.`package` val packageFqName = file.packageFqName val nameResolver = file.nameResolver diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt index 164a1db781b..33428253b20 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt @@ -127,7 +127,7 @@ open class KotlinMetadataFileIndexBase(classOfIndex: Class, indexFunction: private val INDEXER = indexer { fileContent -> if (fileContent.fileType == KotlinBuiltInFileType && fileContent.fileName.endsWith(MetadataPackageFragment.DOT_METADATA_FILE_EXTENSION)) { val builtins = BuiltInDefinitionFile.read(fileContent.content, fileContent.file.parent) - (builtins as? BuiltInDefinitionFile.Compatible)?.let { builtinDefFile -> + (builtins as? BuiltInDefinitionFile)?.let { builtinDefFile -> val proto = builtinDefFile.proto proto.class_List.singleOrNull()?.let { cls -> indexFunction(builtinDefFile.nameResolver.getClassId(cls.fqName))