From 18afa8f2d5dd9ee16d172f67dbe782605bee6d11 Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Fri, 17 Apr 2015 19:35:27 +0300 Subject: [PATCH] add KotlinJavaScriptDeserializeForDecompiler --- .../textBuilder/DeserializerForDecompiler.kt | 66 +++------------ .../DeserializerForDecompilerBase.kt | 82 +++++++++++++++++++ ...tlinJavaScriptDeserializerForDecompiler.kt | 80 ++++++++++++++++++ 3 files changed, 175 insertions(+), 53 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompiler.kt index 75da2d3d810..b2ccdc47099 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompiler.kt @@ -18,24 +18,15 @@ package org.jetbrains.kotlin.idea.decompiler.textBuilder import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.vfs.VirtualFile -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleParameters -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentProvider -import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor import org.jetbrains.kotlin.load.kotlin.BinaryClassAnnotationAndConstantLoaderImpl import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeCapabilitiesDeserializer import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.PackageClassUtils -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil -import org.jetbrains.kotlin.storage.LockBasedStorageManager public fun DeserializerForDecompiler(classFile: VirtualFile): DeserializerForDecompiler { val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) @@ -44,14 +35,22 @@ public fun DeserializerForDecompiler(classFile: VirtualFile): DeserializerForDec return DeserializerForDecompiler(classFile.getParent()!!, packageFqName) } -public class DeserializerForDecompiler(val packageDirectory: VirtualFile, val directoryPackageFqName: FqName) : ResolverForDecompiler { +public class DeserializerForDecompiler( + packageDirectory: VirtualFile, + directoryPackageFqName: FqName +) : DeserializerForDecompilerBase(packageDirectory, directoryPackageFqName) { - private val storageManager = LockBasedStorageManager.NO_LOCKS - private val moduleDescriptor = createDummyModule("module for building decompiled sources") + private val classFinder = DirectoryBasedClassFinder(packageDirectory, directoryPackageFqName) - private fun createDummyModule(name: String) = ModuleDescriptorImpl(Name.special("<$name>"), storageManager, ModuleParameters.Empty) + override val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG) - override fun resolveTopLevelClass(classId: ClassId) = deserializationComponents.deserializeClass(classId) + override val annotationAndConstantLoader = + BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, storageManager, classFinder, LoggingErrorReporter(LOG)) + + override val deserializationComponents: DeserializationComponents = DeserializationComponents( + storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, + ResolveEverythingToKotlinAnyLocalClassResolver, JavaFlexibleTypeCapabilitiesDeserializer + ) override fun resolveDeclarationsInPackage(packageFqName: FqName): Collection { assert(packageFqName == directoryPackageFqName) { "Was called for $packageFqName but only $directoryPackageFqName is expected" } @@ -71,45 +70,6 @@ public class DeserializerForDecompiler(val packageDirectory: VirtualFile, val di return membersScope.getDescriptors() } - private val classFinder = DirectoryBasedClassFinder(packageDirectory, directoryPackageFqName) - private val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG) - - private val annotationAndConstantLoader = - BinaryClassAnnotationAndConstantLoaderImpl(moduleDescriptor, storageManager, classFinder, LoggingErrorReporter(LOG)) - - private val packageFragmentProvider = object : PackageFragmentProvider { - override fun getPackageFragments(fqName: FqName): List { - return listOf(createDummyPackageFragment(fqName)) - } - - override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection { - throw UnsupportedOperationException("This method is not supposed to be called.") - } - } - - init { - moduleDescriptor.initialize(packageFragmentProvider) - moduleDescriptor.addDependencyOnModule(moduleDescriptor) - moduleDescriptor.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule()) - val moduleContainingMissingDependencies = createDummyModule("module containing missing dependencies for decompiled sources") - moduleContainingMissingDependencies.addDependencyOnModule(moduleContainingMissingDependencies) - moduleContainingMissingDependencies.initialize( - PackageFragmentProviderForMissingDependencies(moduleContainingMissingDependencies) - ) - moduleDescriptor.addDependencyOnModule(moduleContainingMissingDependencies) - moduleDescriptor.seal() - moduleContainingMissingDependencies.seal() - } - - private val deserializationComponents = DeserializationComponents( - storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, - ResolveEverythingToKotlinAnyLocalClassResolver, JavaFlexibleTypeCapabilitiesDeserializer - ) - - private fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor { - return MutablePackageFragmentDescriptor(moduleDescriptor, fqName) - } - companion object { private val LOG = Logger.getInstance(javaClass()) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt new file mode 100644 index 00000000000..c704d9408e0 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2010-2015 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.textBuilder + +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ModuleParameters +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentProvider +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant +import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantLoader +import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder +import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents +import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.storage.StorageManager + +public abstract class DeserializerForDecompilerBase( + val packageDirectory: VirtualFile , + val directoryPackageFqName: FqName +) : ResolverForDecompiler { + + protected abstract val deserializationComponents: DeserializationComponents + + protected abstract val classDataFinder: ClassDataFinder + + protected abstract val annotationAndConstantLoader: AnnotationAndConstantLoader> + + protected val storageManager: StorageManager = LockBasedStorageManager.NO_LOCKS + + protected val moduleDescriptor: ModuleDescriptorImpl = createDummyModule("module for building decompiled sources") + + protected val packageFragmentProvider: PackageFragmentProvider = object : PackageFragmentProvider { + override fun getPackageFragments(fqName: FqName): List { + return listOf(createDummyPackageFragment(fqName)) + } + + override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection { + throw UnsupportedOperationException("This method is not supposed to be called.") + } + } + + override fun resolveTopLevelClass(classId: ClassId) = deserializationComponents.deserializeClass(classId) + + protected fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor = + MutablePackageFragmentDescriptor(moduleDescriptor, fqName) + + private fun createDummyModule(name: String) = ModuleDescriptorImpl(Name.special("<$name>"), storageManager, ModuleParameters.Empty) + + init { + moduleDescriptor.initialize(packageFragmentProvider) + moduleDescriptor.addDependencyOnModule(moduleDescriptor) + moduleDescriptor.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule()) + val moduleContainingMissingDependencies = createDummyModule("module containing missing dependencies for decompiled sources") + moduleContainingMissingDependencies.addDependencyOnModule(moduleContainingMissingDependencies) + moduleContainingMissingDependencies.initialize( + PackageFragmentProviderForMissingDependencies(moduleContainingMissingDependencies) + ) + moduleDescriptor.addDependencyOnModule(moduleContainingMissingDependencies) + moduleDescriptor.seal() + moduleContainingMissingDependencies.seal() + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt new file mode 100644 index 00000000000..36d367516ea --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2015 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.textBuilder + +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils +import org.jetbrains.kotlin.load.kotlin.PackageClassUtils +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents +import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeCapabilitiesDeserializer +import org.jetbrains.kotlin.serialization.deserialization.NameResolver +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope +import org.jetbrains.kotlin.serialization.js.KotlinJavascriptAnnotationAndConstantLoader +import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializedResourcePaths +import org.jetbrains.kotlin.serialization.js.toPackageData +import java.io.ByteArrayInputStream + +public class KotlinJavaScriptDeserializerForDecompiler( + classFile: VirtualFile +) : DeserializerForDecompilerBase(classFile.getParent()!!, JsMetaFileUtils.getPackageFqName(classFile)) { + + private val nameResolver = run { + val moduleDirectory = JsMetaFileUtils.getModuleDirectory(packageDirectory) + val stringsFileName = KotlinJavascriptSerializedResourcePaths.getStringTableFilePath(directoryPackageFqName) + val stringsFile = moduleDirectory.findFileByRelativePath(stringsFileName) + assert(stringsFile != null, "strings file not found: $stringsFileName") + NameResolver.read(ByteArrayInputStream(stringsFile!!.contentsToByteArray(false))) + } + + private val metaFileFinder = DirectoryBasedKotlinJavaScriptMetaFileFinder(packageDirectory, directoryPackageFqName, nameResolver) + + override val classDataFinder = DirectoryBasedKotlinJavaScriptDataFinder(metaFileFinder, LOG) + + override val annotationAndConstantLoader = KotlinJavascriptAnnotationAndConstantLoader(moduleDescriptor) + + override val deserializationComponents = DeserializationComponents( + storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, + ResolveEverythingToKotlinAnyLocalClassResolver, FlexibleTypeCapabilitiesDeserializer.Dynamic + ) + + override fun resolveDeclarationsInPackage(packageFqName: FqName): Collection { + assert(packageFqName == directoryPackageFqName, "Was called for $packageFqName but only $directoryPackageFqName is expected.") + val file = metaFileFinder.findKotlinJavascriptMetaFile(PackageClassUtils.getPackageClassId(packageFqName)) + if (file == null) { + LOG.error("Could not read data for $packageFqName") + return emptyList() + } + + val content = file.contentsToByteArray(false) + val packageData = content.toPackageData(nameResolver) + + val membersScope = DeserializedPackageMemberScope( + createDummyPackageFragment(packageFqName), + packageData.getPackageProto(), + packageData.getNameResolver(), + deserializationComponents + ) { emptyList() } + return membersScope.getDescriptors() + } + + companion object { + private val LOG = Logger.getInstance(javaClass()) + } +}