Combine cls stub builders for built-ins and JS

This commit is contained in:
Alexander Udalov
2017-02-01 17:24:24 +03:00
parent 297eb952bc
commit f120865350
6 changed files with 38 additions and 108 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata
import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDecompiler import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDecompiler
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
@@ -31,8 +32,9 @@ import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmen
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
class KotlinBuiltInDecompiler : KotlinMetadataDecompiler<BuiltInsBinaryVersion>( class KotlinBuiltInDecompiler : KotlinMetadataDecompiler<BuiltInsBinaryVersion>(
KotlinBuiltInFileType, KotlinBuiltInStubBuilder(), TargetPlatform.Default, BuiltInSerializerProtocol, KotlinBuiltInFileType, TargetPlatform.Default, BuiltInSerializerProtocol,
FlexibleTypeDeserializer.ThrowException, BuiltInsBinaryVersion.INSTANCE, BuiltInsBinaryVersion.INVALID_VERSION FlexibleTypeDeserializer.ThrowException, BuiltInsBinaryVersion.INSTANCE, BuiltInsBinaryVersion.INVALID_VERSION,
KotlinStubVersions.BUILTIN_STUB_VERSION
) { ) {
override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? { override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? {
return BuiltInDefinitionFile.read(bytes, file) return BuiltInDefinitionFile.read(bytes, file)
@@ -21,7 +21,6 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.FileViewProvider import com.intellij.psi.FileViewProvider
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.compiled.ClassFileDecompilers import com.intellij.psi.compiled.ClassFileDecompilers
import com.intellij.psi.compiled.ClsStubBuilder
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
@@ -41,13 +40,15 @@ import java.io.IOException
abstract class KotlinMetadataDecompiler<out V : BinaryVersion>( abstract class KotlinMetadataDecompiler<out V : BinaryVersion>(
private val fileType: FileType, private val fileType: FileType,
private val stubBuilder: ClsStubBuilder,
private val targetPlatform: TargetPlatform, private val targetPlatform: TargetPlatform,
private val serializerProtocol: SerializerExtensionProtocol, private val serializerProtocol: SerializerExtensionProtocol,
private val flexibleTypeDeserializer: FlexibleTypeDeserializer, private val flexibleTypeDeserializer: FlexibleTypeDeserializer,
private val expectedBinaryVersion: V, private val expectedBinaryVersion: V,
private val invalidBinaryVersion: V private val invalidBinaryVersion: V,
stubVersion: Int
) : ClassFileDecompilers.Full() { ) : ClassFileDecompilers.Full() {
private val stubBuilder = KotlinMetadataStubBuilder(stubVersion, fileType, serializerProtocol, this::readFile)
private val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() } private val renderer = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
abstract fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? abstract fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata?
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,28 +14,32 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.idea.decompiler.builtIns package org.jetbrains.kotlin.idea.decompiler.common
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.compiled.ClsStubBuilder import com.intellij.psi.compiled.ClsStubBuilder
import com.intellij.psi.impl.compiled.ClassFileStubBuilder import com.intellij.psi.impl.compiled.ClassFileStubBuilder
import com.intellij.psi.stubs.PsiFileStub import com.intellij.psi.stubs.PsiFileStub
import com.intellij.util.indexing.FileContent import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
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.idea.decompiler.stubBuilder.*
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.deserialization.TypeTable
class KotlinBuiltInStubBuilder : ClsStubBuilder() { open class KotlinMetadataStubBuilder(
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + KotlinStubVersions.BUILTIN_STUB_VERSION private val version: Int,
private val fileType: FileType,
private val serializerProtocol: SerializerExtensionProtocol,
private val readFile: (ByteArray, VirtualFile) -> FileWithMetadata?
) : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + version
override fun buildFileStub(content: FileContent): PsiFileStub<*>? { override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
val virtualFile = content.file val virtualFile = content.file
assert(virtualFile.fileType == KotlinBuiltInFileType) { "Unexpected file type ${virtualFile.fileType}" } assert(virtualFile.fileType == fileType) { "Unexpected file type ${virtualFile.fileType}" }
val file = BuiltInDefinitionFile.read(content.content, virtualFile) ?: return null val file = readFile(content.content, virtualFile) ?: return null
when (file) { when (file) {
is FileWithMetadata.Incompatible -> { is FileWithMetadata.Incompatible -> {
@@ -47,7 +51,7 @@ class KotlinBuiltInStubBuilder : ClsStubBuilder() {
val nameResolver = file.nameResolver val nameResolver = file.nameResolver
val components = ClsStubBuilderComponents( val components = ClsStubBuilderComponents(
ProtoBasedClassDataFinder(file.proto, nameResolver), ProtoBasedClassDataFinder(file.proto, nameResolver),
AnnotationLoaderForStubBuilderImpl(BuiltInSerializerProtocol), AnnotationLoaderForStubBuilderImpl(serializerProtocol),
virtualFile virtualFile
) )
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable)) val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
@@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata import org.jetbrains.kotlin.idea.decompiler.common.FileWithMetadata
import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDecompiler import org.jetbrains.kotlin.idea.decompiler.common.KotlinMetadataDecompiler
import org.jetbrains.kotlin.js.resolve.JsPlatform import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
import org.jetbrains.kotlin.serialization.js.JsProtoBuf import org.jetbrains.kotlin.serialization.js.JsProtoBuf
@@ -28,27 +29,20 @@ import org.jetbrains.kotlin.utils.JsMetadataVersion
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
class KotlinJavaScriptMetaFileDecompiler : KotlinMetadataDecompiler<JsMetadataVersion>( class KotlinJavaScriptMetaFileDecompiler : KotlinMetadataDecompiler<JsMetadataVersion>(
KotlinJavaScriptMetaFileType, KotlinJavaScriptStubBuilder(), JsPlatform, JsSerializerProtocol, DynamicTypeDeserializer, KotlinJavaScriptMetaFileType, JsPlatform, JsSerializerProtocol, DynamicTypeDeserializer,
JsMetadataVersion.INSTANCE, JsMetadataVersion.INVALID_VERSION JsMetadataVersion.INSTANCE, JsMetadataVersion.INVALID_VERSION, KotlinStubVersions.JS_STUB_VERSION
) { ) {
override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? { override fun readFile(bytes: ByteArray, file: VirtualFile): FileWithMetadata? {
return KjsmFile.read(bytes) val stream = ByteArrayInputStream(bytes)
}
}
class KjsmFile(proto: ProtoBuf.PackageFragment) : FileWithMetadata.Compatible(proto, JsSerializerProtocol) { val version = JsMetadataVersion.readFrom(stream)
companion object { if (!version.isCompatible()) {
fun read(bytes: ByteArray): FileWithMetadata? { return FileWithMetadata.Incompatible(version)
val stream = ByteArrayInputStream(bytes)
val version = JsMetadataVersion.readFrom(stream)
if (!version.isCompatible()) {
return FileWithMetadata.Incompatible(version)
}
JsProtoBuf.Header.parseDelimitedFrom(stream)
return KjsmFile(ProtoBuf.PackageFragment.parseFrom(stream, JsSerializerProtocol.extensionRegistry))
} }
JsProtoBuf.Header.parseDelimitedFrom(stream)
val proto = ProtoBuf.PackageFragment.parseFrom(stream, JsSerializerProtocol.extensionRegistry)
return FileWithMetadata.Compatible(proto, JsSerializerProtocol)
} }
} }
@@ -1,71 +0,0 @@
/*
* Copyright 2010-2016 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.js
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.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
// TODO: deduplicate code with KotlinBuiltInStubBuilder
class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + KotlinStubVersions.JS_STUB_VERSION
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
val virtualFile = content.file
assert(virtualFile.fileType == KotlinJavaScriptMetaFileType) { "Unexpected file type ${virtualFile.fileType}" }
val file = KjsmFile.read(content.content) ?: return null
when (file) {
is FileWithMetadata.Incompatible -> {
return createIncompatibleAbiVersionFileStub()
}
is FileWithMetadata.Compatible -> {
val packageProto = file.proto.`package`
val packageFqName = file.packageFqName
val nameResolver = file.nameResolver
val components = ClsStubBuilderComponents(
ProtoBasedClassDataFinder(file.proto, nameResolver),
AnnotationLoaderForStubBuilderImpl(JsSerializerProtocol),
virtualFile
)
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
val fileStub = createFileStub(packageFqName, isScript = false)
createDeclarationsStubs(
fileStub, context,
ProtoContainer.Package(packageFqName, context.nameResolver, context.typeTable, source = null),
packageProto
)
for (classProto in file.classesToDecompile) {
createClassStub(
fileStub, classProto, nameResolver, nameResolver.getClassId(classProto.fqName), source = null, context = context
)
}
return fileStub
}
}
}
}
@@ -21,7 +21,7 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.util.indexing.FileContentImpl import com.intellij.util.indexing.FileContentImpl
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.builtins.BuiltInsBinaryVersion import org.jetbrains.kotlin.builtins.BuiltInsBinaryVersion
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInStubBuilder import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInDecompiler
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -49,7 +49,7 @@ class BuiltInDecompilerTest : AbstractBuiltInDecompilerTest() {
val dirInRuntime = findDir(packageFqName, project) val dirInRuntime = findDir(packageFqName, project)
val kotlinBuiltInsVirtualFile = dirInRuntime.children.single { it.extension == BuiltInSerializerProtocol.BUILTINS_FILE_EXTENSION } val kotlinBuiltInsVirtualFile = dirInRuntime.children.single { it.extension == BuiltInSerializerProtocol.BUILTINS_FILE_EXTENSION }
myFixture.configureFromExistingVirtualFile(kotlinBuiltInsVirtualFile) myFixture.configureFromExistingVirtualFile(kotlinBuiltInsVirtualFile)
return KotlinBuiltInStubBuilder().buildFileStub(FileContentImpl.createByFile(kotlinBuiltInsVirtualFile))!! return KotlinBuiltInDecompiler().stubBuilder.buildFileStub(FileContentImpl.createByFile(kotlinBuiltInsVirtualFile))!!
} }
fun testBuiltInStubTreeEqualToStubTreeFromDecompiledText() { fun testBuiltInStubTreeEqualToStubTreeFromDecompiledText() {
@@ -63,7 +63,7 @@ class BuiltInDecompilerForWrongAbiVersionTest : AbstractBuiltInDecompilerTest()
override fun configureAndBuildFileStub(packageFqName: String): PsiFileStub<*> { override fun configureAndBuildFileStub(packageFqName: String): PsiFileStub<*> {
myFixture.configureByFile(testDataPath + BuiltInSerializerProtocol.getBuiltInsFilePath(FqName(packageFqName))) myFixture.configureByFile(testDataPath + BuiltInSerializerProtocol.getBuiltInsFilePath(FqName(packageFqName)))
return KotlinBuiltInStubBuilder().buildFileStub(FileContentImpl.createByFile(myFixture.file.virtualFile))!! return KotlinBuiltInDecompiler().stubBuilder.buildFileStub(FileContentImpl.createByFile(myFixture.file.virtualFile))!!
} }
fun testStubTreesEqualForIncompatibleAbiVersion() { fun testStubTreesEqualForIncompatibleAbiVersion() {