From 2499e95d3838885d3bfaa99e7bae172ce2db4e9f Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Wed, 26 Feb 2014 15:09:23 +0400 Subject: [PATCH] Refactor DecompiledDataFactory --- .../plugin/libraries/DecompiledDataFactory.kt | 114 ++++++++---------- .../plugin/libraries/JetDecompiledData.java | 6 +- .../ProjectBasedResolverForDecompiler.kt | 2 +- 3 files changed, 58 insertions(+), 64 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.kt b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.kt index 1731b5606ea..ed4062540a5 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.kt @@ -34,59 +34,64 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry import org.jetbrains.jet.lang.resolve.DescriptorUtils.isSyntheticClassObject import org.jetbrains.jet.plugin.libraries.JetDecompiledData.descriptorToKey -public class DecompiledDataFactory(val classFile: VirtualFile, val project: Project, val resolver: ResolverForDecompiler) { +public fun buildDecompiledData(classFile: VirtualFile, project: Project): JetDecompiledData { + return buildDecompiledData(classFile, project, ProjectBasedResolverForDecompiler(project)) +} - private val classFqName: FqName - private val classFileHeader: KotlinClassHeader - - { - val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) - this.classFqName = kotlinClass.getClassName().getFqNameForClassNameWithoutDollars() - val header = kotlinClass.getClassHeader() - assert(header != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } - this.classFileHeader = header!! +public fun buildDecompiledData(classFile: VirtualFile, project: Project, resolver: ResolverForDecompiler): JetDecompiledData { + val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) + val classFqName = kotlinClass.getClassName().getFqNameForClassNameWithoutDollars() + val classFileHeader = kotlinClass.getClassHeader() + assert(classFileHeader != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } + val kind = classFileHeader!!.getKind() + val packageFqName = classFqName.parent() + val (text, renderedDescriptorsToRange) = + if (kind == KotlinClassHeader.Kind.PACKAGE_FACADE) { + buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInPackage(packageFqName))) + } + else if (kind == KotlinClassHeader.Kind.CLASS) { + buildDecompiledText(packageFqName, listOf(resolver.resolveClass(classFqName)).filterNotNull()) + } + else { + // TODO: support other header kinds: for trait-impl show the trait, for package fragment - the whole package + throw UnsupportedOperationException("Unknown header kind: " + kind) } - private val renderedDescriptorsToRange = HashMap() - private val builder = StringBuilder() + val jetFile = JetDummyClassFileViewProvider.createJetFile(PsiManager.getInstance(project), classFile, text) + return JetDecompiledData(jetFile, renderedDescriptorsToRange) +} - fun build(): JetDecompiledData { - val packageFqName = classFqName.parent() - appendDecompiledTextAndPackageName(packageFqName) - val kind = classFileHeader.getKind() - if (kind == KotlinClassHeader.Kind.PACKAGE_FACADE) { - for (member in sortDeclarations(resolver.resolveDeclarationsInPackage(packageFqName))) { - if (member !is ClassDescriptor) { - appendDescriptor(member, "") - builder.append("\n") - } - } - } - else - if (kind == KotlinClassHeader.Kind.CLASS) { - val cd = resolver.resolveClass(classFqName) - if (cd != null) { - appendDescriptor(cd, "") - } - } - else { - // TODO: support other header kinds: for trait-impl show the trait, for package fragment - the whole package - throw UnsupportedOperationException("Unknown header kind: " + kind) - } +private val DECOMPILED_COMMENT: String = "/* compiled code */" +public val descriptorRendererForDecompiler: DescriptorRenderer = DescriptorRendererBuilder() + .setWithDefinedIn(false) + .setClassWithPrimaryConstructor(true) + .build() - val jetFile = JetDummyClassFileViewProvider.createJetFile(PsiManager.getInstance(project), classFile, builder.toString()) - return JetDecompiledData(jetFile, renderedDescriptorsToRange) - } +private data class DecompiledText(val text: String, val renderedDescriptorsToRange: Map) - private fun appendDecompiledTextAndPackageName(packageName: FqName) { +private fun buildDecompiledText(packageFqName: FqName, descriptors: List): DecompiledText { + val builder = StringBuilder() + val renderedDescriptorsToRange = HashMap() + + fun appendDecompiledTextAndPackageName() { builder.append("// IntelliJ API Decompiler stub source generated from a class file\n" + "// Implementation of methods is not available") builder.append("\n\n") - if (!packageName.isRoot()) { - builder.append("package ").append(packageName).append("\n\n") + if (!packageFqName.isRoot()) { + builder.append("package ").append(packageFqName).append("\n\n") } } - private fun appendDescriptor(descriptor: DeclarationDescriptor, indent: String) { + fun sortDeclarations(input: Collection): List { + val r = ArrayList(input) + Collections.sort(r, MemberComparator.INSTANCE) + return r + } + + fun saveDescriptorToRange(descriptor: DeclarationDescriptor, startOffset: Int, endOffset: Int) { + renderedDescriptorsToRange[descriptorToKey(descriptor)] = TextRange(startOffset, endOffset) + } + + fun appendDescriptor(descriptor: DeclarationDescriptor, indent: String) { val startOffset = builder.length() val header = if (isEnumEntry(descriptor)) descriptor.getName().asString() @@ -150,24 +155,11 @@ public class DecompiledDataFactory(val classFile: VirtualFile, val project: Proj } } - private fun saveDescriptorToRange(descriptor: DeclarationDescriptor, startOffset: Int, endOffset: Int) { - renderedDescriptorsToRange[descriptorToKey(descriptor)] = TextRange(startOffset, endOffset) + appendDecompiledTextAndPackageName() + for (member in sortDeclarations(descriptors)) { + appendDescriptor(member, "") + builder.append("\n") } - private fun sortDeclarations(input: Collection): List { - val r = ArrayList(input) - Collections.sort(r, MemberComparator.INSTANCE) - return r - } - -} -private val DECOMPILED_COMMENT: String = "/* compiled code */" - -public val descriptorRendererForDecompiler: DescriptorRenderer = DescriptorRendererBuilder() - .setWithDefinedIn(false) - .setClassWithPrimaryConstructor(true) - .build() - -fun createDecompiledData(virtualFile: VirtualFile, project: Project): JetDecompiledData { - return DecompiledDataFactory(virtualFile, project, ProjectBasedResolverForDecompiler(project)).build() -} + return DecompiledText(builder.toString(), renderedDescriptorsToRange) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetDecompiledData.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetDecompiledData.java index 930b31eed91..e1f11c0d92e 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetDecompiledData.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/JetDecompiledData.java @@ -30,6 +30,8 @@ import org.jetbrains.jet.lang.psi.JetFile; import java.util.Map; +import static org.jetbrains.jet.plugin.libraries.LibrariesPackage.buildDecompiledData; + @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized") public class JetDecompiledData { @@ -57,7 +59,7 @@ public class JetDecompiledData { JetDecompiledData cachedData = virtualFile.getUserData(USER_DATA_KEY); //TODO: use cached value that keeps modification tracking for this virtual file if (cachedData == null || cachedData.getProject() != project) { - virtualFile.putUserData(USER_DATA_KEY, DecompiledDataFactory.createDecompiledData(virtualFile, project)); + virtualFile.putUserData(USER_DATA_KEY, buildDecompiledData(virtualFile, project)); } JetDecompiledData decompiledData = virtualFile.getUserData(USER_DATA_KEY); assert decompiledData != null; @@ -84,7 +86,7 @@ public class JetDecompiledData { //TODO: should use more accurate way to identify descriptors @NotNull static String descriptorToKey(@NotNull DeclarationDescriptor descriptor) { - return DecompiledDataFactory.DESCRIPTOR_RENDERER.render(descriptor); + return LibrariesPackage.getDescriptorRendererForDecompiler().render(descriptor); } @NotNull diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/ProjectBasedResolverForDecompiler.kt b/idea/src/org/jetbrains/jet/plugin/libraries/ProjectBasedResolverForDecompiler.kt index f094cbf7d61..2584d28f5bc 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/ProjectBasedResolverForDecompiler.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/ProjectBasedResolverForDecompiler.kt @@ -36,6 +36,6 @@ public class ProjectBasedResolverForDecompiler(project: Project) : ResolverForDe if (packageFragment == null) { return Collections.emptyList() } - return packageFragment.getMemberScope().getAllDescriptors() + return packageFragment.getMemberScope().getAllDescriptors() filter { it !is ClassDescriptor } } } \ No newline at end of file