add KotlinJavaScriptDeserializeForDecompiler

This commit is contained in:
Michael Nedzelsky
2015-04-17 19:35:27 +03:00
parent f1a0d86f87
commit 18afa8f2d5
3 changed files with 175 additions and 53 deletions
@@ -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<DeclarationDescriptor> {
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<PackageFragmentDescriptor> {
return listOf(createDummyPackageFragment(fqName))
}
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> {
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<DeserializerForDecompiler>())
}
@@ -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<AnnotationDescriptor, CompileTimeConstant<*>>
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<PackageFragmentDescriptor> {
return listOf(createDummyPackageFragment(fqName))
}
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> {
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()
}
}
@@ -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<DeclarationDescriptor> {
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<KotlinJavaScriptDeserializerForDecompiler>())
}
}