Decompilation support
- class header reader for KotlinMultifileClass, KotlinMultifileClassPart - proper implClassName for multifile class members
This commit is contained in:
@@ -27,10 +27,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage;
|
||||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
|
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
import org.jetbrains.kotlin.codegen.context.*;
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.PackageContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.PackageFacadeContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor;
|
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||||
@@ -163,15 +160,11 @@ public class FunctionCodegen {
|
|||||||
jvmSignature.getGenericsSignature(),
|
jvmSignature.getGenericsSignature(),
|
||||||
getThrownExceptions(functionDescriptor, typeMapper));
|
getThrownExceptions(functionDescriptor, typeMapper));
|
||||||
|
|
||||||
if (owner instanceof PackageFacadeContext) {
|
String implClassName = CodegenContextUtil.getImplClassNameByOwnerIfRequired(owner);
|
||||||
Type ownerType = ((PackageFacadeContext) owner).getDelegateToClassType();
|
if (implClassName != null) {
|
||||||
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, shortNameByAsmType(ownerType));
|
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, implClassName);
|
||||||
}
|
}
|
||||||
else {
|
if (CodegenContextUtil.isImplClassOwner(owner)) {
|
||||||
if (owner instanceof PackageContext) {
|
|
||||||
Type ownerType = ((PackageContext) owner).getPackagePartType();
|
|
||||||
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, shortNameByAsmType(ownerType));
|
|
||||||
}
|
|
||||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
|
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,15 +110,12 @@ public class PropertyCodegen {
|
|||||||
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL
|
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL
|
||||||
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
|
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
|
||||||
|
|
||||||
if (context instanceof PackageFacadeContext) {
|
Type implClassType = CodegenContextUtil.getImplClassTypeByOwnerIfRequired(context);
|
||||||
Type ownerType = ((PackageFacadeContext) context).getDelegateToClassType();
|
if (implClassType != null) {
|
||||||
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(ownerType));
|
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(implClassType));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (context instanceof PackageContext) {
|
if (CodegenContextUtil.isImplClassOwner(context)) {
|
||||||
Type ownerType = ((PackageContext) context).getPackagePartType();
|
|
||||||
v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(ownerType));
|
|
||||||
}
|
|
||||||
assert declaration != null : "Declaration is null for different context: " + context;
|
assert declaration != null : "Declaration is null for different context: " + context;
|
||||||
|
|
||||||
boolean hasBackingField = hasBackingField(declaration, descriptor);
|
boolean hasBackingField = hasBackingField(declaration, descriptor);
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.codegen.context
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
|
||||||
|
public object CodegenContextUtil {
|
||||||
|
public @JvmStatic fun getImplClassTypeByOwnerIfRequired(owner: CodegenContext<*>): Type? =
|
||||||
|
when (owner) {
|
||||||
|
is PackageFacadeContext ->
|
||||||
|
owner.delegateToClassType
|
||||||
|
is PackageContext ->
|
||||||
|
owner.packagePartType
|
||||||
|
is MultifileClassOrPartContext ->
|
||||||
|
owner.filePartType
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
public @JvmStatic fun getImplClassNameByOwnerIfRequired(owner: CodegenContext<*>): String? =
|
||||||
|
getImplClassTypeByOwnerIfRequired(owner)?.let{ AsmUtil.shortNameByAsmType(it) }
|
||||||
|
|
||||||
|
public @JvmStatic fun isImplClassOwner(owner: CodegenContext<*>): Boolean =
|
||||||
|
!(owner is PackageFacadeContext || owner is MultifileClassContext)
|
||||||
|
}
|
||||||
+2
-14
@@ -21,26 +21,14 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
public class MultifileClassContext extends FieldOwnerContext<PackageFragmentDescriptor> {
|
public class MultifileClassContext extends MultifileClassOrPartContext {
|
||||||
private final Type multifileClassType;
|
|
||||||
private final Type filePartType;
|
|
||||||
|
|
||||||
public MultifileClassContext(
|
public MultifileClassContext(
|
||||||
PackageFragmentDescriptor descriptor,
|
PackageFragmentDescriptor descriptor,
|
||||||
CodegenContext parent,
|
CodegenContext parent,
|
||||||
Type multifileClassType,
|
Type multifileClassType,
|
||||||
Type filePartType
|
Type filePartType
|
||||||
) {
|
) {
|
||||||
super(descriptor, OwnerKind.PACKAGE, parent, null, null, null);
|
super(descriptor, parent, multifileClassType, filePartType);
|
||||||
this.multifileClassType = multifileClassType;
|
|
||||||
this.filePartType = filePartType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getMultifileClassType() {
|
|
||||||
return multifileClassType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getFilePartType() {
|
|
||||||
return filePartType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.codegen.context;
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.OwnerKind;
|
||||||
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
public class MultifileClassOrPartContext extends FieldOwnerContext<PackageFragmentDescriptor> {
|
||||||
|
private final Type multifileClassType;
|
||||||
|
private final Type filePartType;
|
||||||
|
|
||||||
|
public MultifileClassOrPartContext(
|
||||||
|
PackageFragmentDescriptor descriptor,
|
||||||
|
CodegenContext parent,
|
||||||
|
Type multifileClassType,
|
||||||
|
Type filePartType
|
||||||
|
) {
|
||||||
|
super(descriptor, OwnerKind.PACKAGE, parent, null, null, null);
|
||||||
|
this.multifileClassType = multifileClassType;
|
||||||
|
this.filePartType = filePartType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getMultifileClassType() {
|
||||||
|
return multifileClassType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getFilePartType() {
|
||||||
|
return filePartType;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-14
@@ -21,26 +21,14 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
public class MultifileClassPartContext extends FieldOwnerContext<PackageFragmentDescriptor> {
|
public class MultifileClassPartContext extends MultifileClassOrPartContext {
|
||||||
private final Type multifileClassType;
|
|
||||||
private final Type filePartType;
|
|
||||||
|
|
||||||
public MultifileClassPartContext(
|
public MultifileClassPartContext(
|
||||||
PackageFragmentDescriptor descriptor,
|
PackageFragmentDescriptor descriptor,
|
||||||
CodegenContext parent,
|
CodegenContext parent,
|
||||||
Type multifileClassType,
|
Type multifileClassType,
|
||||||
Type filePartType
|
Type filePartType
|
||||||
) {
|
) {
|
||||||
super(descriptor, OwnerKind.PACKAGE, parent, null, null, null);
|
super(descriptor, parent, multifileClassType, filePartType);
|
||||||
this.multifileClassType = multifileClassType;
|
|
||||||
this.filePartType = filePartType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getMultifileClassType() {
|
|
||||||
return multifileClassType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getFilePartType() {
|
|
||||||
return filePartType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -226,7 +226,8 @@ public abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C
|
|||||||
nameResolver: NameResolver
|
nameResolver: NameResolver
|
||||||
): KotlinJvmBinaryClass? {
|
): KotlinJvmBinaryClass? {
|
||||||
if (proto.hasExtension(implClassName)) {
|
if (proto.hasExtension(implClassName)) {
|
||||||
return kotlinClassFinder.findKotlinClass(ClassId(packageFqName, nameResolver.getName(proto.getExtension(implClassName))))
|
val implClassName = nameResolver.getName(proto.getExtension(implClassName))
|
||||||
|
return kotlinClassFinder.findKotlinClass(ClassId(packageFqName, implClassName))
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -120,6 +120,10 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
return new PackageHeaderReader();
|
return new PackageHeaderReader();
|
||||||
case FILE_FACADE:
|
case FILE_FACADE:
|
||||||
return new FileFacadeHeaderReader();
|
return new FileFacadeHeaderReader();
|
||||||
|
case MULTIFILE_CLASS:
|
||||||
|
return new MultifileClassHeaderReader();
|
||||||
|
case MULTIFILE_CLASS_PART:
|
||||||
|
return new MultifileClassPartHeaderReader();
|
||||||
case SYNTHETIC_CLASS:
|
case SYNTHETIC_CLASS:
|
||||||
return new SyntheticClassHeaderReader();
|
return new SyntheticClassHeaderReader();
|
||||||
default:
|
default:
|
||||||
@@ -259,6 +263,18 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MultifileClassHeaderReader extends HeaderAnnotationArgumentVisitor {
|
||||||
|
public MultifileClassHeaderReader() {
|
||||||
|
super(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_MULTIFILE_CLASS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MultifileClassPartHeaderReader extends HeaderAnnotationArgumentVisitor {
|
||||||
|
public MultifileClassPartHeaderReader() {
|
||||||
|
super(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_MULTIFILE_CLASS_PART));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SyntheticClassHeaderReader extends HeaderAnnotationArgumentVisitor {
|
private class SyntheticClassHeaderReader extends HeaderAnnotationArgumentVisitor {
|
||||||
public SyntheticClassHeaderReader() {
|
public SyntheticClassHeaderReader() {
|
||||||
super(KotlinSyntheticClass.CLASS_NAME);
|
super(KotlinSyntheticClass.CLASS_NAME);
|
||||||
|
|||||||
@@ -21,10 +21,15 @@ import com.intellij.openapi.util.Key
|
|||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.ClassFileViewProvider
|
import com.intellij.psi.ClassFileViewProvider
|
||||||
import org.jetbrains.kotlin.idea.caches.JarUserDataManager
|
import org.jetbrains.kotlin.idea.caches.JarUserDataManager
|
||||||
|
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this file is a compiled Kotlin class file (not necessarily ABI-compatible with the current plugin)
|
* Checks if this file is a compiled Kotlin class file (not necessarily ABI-compatible with the current plugin)
|
||||||
@@ -83,3 +88,27 @@ public object HasCompiledKotlinInJar : JarUserDataManager.JarBooleanPropertyCoun
|
|||||||
fun isInNoKotlinJar(file: VirtualFile): Boolean =
|
fun isInNoKotlinJar(file: VirtualFile): Boolean =
|
||||||
JarUserDataManager.hasFileWithProperty(HasCompiledKotlinInJar, file) == false
|
JarUserDataManager.hasFileWithProperty(HasCompiledKotlinInJar, file) == false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ReadMultifileClassException(message: String): RuntimeException(message)
|
||||||
|
|
||||||
|
public fun findMultifileClassParts(file: VirtualFile, multifileClass: KotlinJvmBinaryClass): List<KotlinJvmBinaryClass> {
|
||||||
|
val result = arrayListOf<KotlinClassHeader>()
|
||||||
|
val packageFqName = multifileClass.classId.packageFqName
|
||||||
|
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
||||||
|
val partNames = multifileClass.classHeader.filePartClassNames ?: return emptyList()
|
||||||
|
return partNames.map {
|
||||||
|
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it)))
|
||||||
|
}.filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ReadMultifileClassException::class)
|
||||||
|
public fun readMultifileClassPartHeaders(file: VirtualFile, multifileClass: KotlinJvmBinaryClass): List<KotlinClassHeader> {
|
||||||
|
val classId = multifileClass.classId
|
||||||
|
val classHeader = multifileClass.classHeader
|
||||||
|
if (classHeader.filePartClassNames == null) {
|
||||||
|
throw ReadMultifileClassException("Multifile class $classId has no filePartClassNames or wrong ABI version: ${classHeader.version}")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return findMultifileClassParts(file, multifileClass).map { it.classHeader }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+11
-21
@@ -22,7 +22,9 @@ 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.idea.decompiler.ReadMultifileClassException
|
||||||
import org.jetbrains.kotlin.idea.decompiler.isKotlinInternalCompiledFile
|
import org.jetbrains.kotlin.idea.decompiler.isKotlinInternalCompiledFile
|
||||||
|
import org.jetbrains.kotlin.idea.decompiler.readMultifileClassPartHeaders
|
||||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
|
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
|
||||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedDataFinder
|
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedDataFinder
|
||||||
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
|
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
|
||||||
@@ -83,32 +85,20 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
|
|||||||
header.isCompatibleMultifileClassKind() -> {
|
header.isCompatibleMultifileClassKind() -> {
|
||||||
val packageData = JvmProtoBufUtil.readPackageDataFrom(annotationData)
|
val packageData = JvmProtoBufUtil.readPackageDataFrom(annotationData)
|
||||||
val context = components.createContext(packageData.nameResolver, packageFqName)
|
val context = components.createContext(packageData.nameResolver, packageFqName)
|
||||||
val partHeaders = readMultifileClassPartHeaders(file, header, packageFqName)
|
val partHeaders =
|
||||||
partHeaders?.let {
|
try {
|
||||||
createMultifileClassStub(it, classId.asSingleFqName(), context)
|
readMultifileClassPartHeaders(file, kotlinBinaryClass)
|
||||||
}
|
}
|
||||||
|
catch (e: ReadMultifileClassException) {
|
||||||
|
LOG.error(e.getMessage())
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
createMultifileClassStub(partHeaders, classId.asSingleFqName(), context)
|
||||||
}
|
}
|
||||||
else -> throw IllegalStateException("Should have processed " + file.getPath() + " with header $header")
|
else -> throw IllegalStateException("Should have processed " + file.getPath() + " with header $header")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readMultifileClassPartHeaders(file: VirtualFile, header: KotlinClassHeader, packageFqName: FqName): List<KotlinClassHeader>? {
|
|
||||||
val result = arrayListOf<KotlinClassHeader>()
|
|
||||||
val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
|
|
||||||
val partNames = header.filePartClassNames
|
|
||||||
if (partNames != null) {
|
|
||||||
for (partName in partNames) {
|
|
||||||
val partClass = partsFinder.findKotlinClass(ClassId.topLevel(packageFqName.child(Name.identifier(partName))))
|
|
||||||
if (partClass == null) {
|
|
||||||
LOG.error("Missing part class: $packageFqName.$partName")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
result.add(partClass.classHeader)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
|
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
|
||||||
val classFinder = DirectoryBasedClassFinder(file.getParent()!!, packageFqName)
|
val classFinder = DirectoryBasedClassFinder(file.getParent()!!, packageFqName)
|
||||||
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
|
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
|
||||||
|
|||||||
+15
@@ -19,12 +19,16 @@ package org.jetbrains.kotlin.idea.decompiler.textBuilder
|
|||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.decompiler.ReadMultifileClassException
|
||||||
|
import org.jetbrains.kotlin.idea.decompiler.findMultifileClassParts
|
||||||
import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils
|
import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils
|
||||||
|
import org.jetbrains.kotlin.idea.decompiler.readMultifileClassPartHeaders
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
|
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
|
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
@@ -47,6 +51,12 @@ public val INCOMPATIBLE_ABI_VERSION_COMMENT: String =
|
|||||||
"// Current compiler ABI version is $CURRENT_ABI_VERSION_MARKER\n" +
|
"// Current compiler ABI version is $CURRENT_ABI_VERSION_MARKER\n" +
|
||||||
"// File ABI version is $FILE_ABI_VERSION_MARKER"
|
"// File ABI version is $FILE_ABI_VERSION_MARKER"
|
||||||
|
|
||||||
|
private val REASON = "REASON"
|
||||||
|
public val FILE_CANT_BE_DECOMPILED_DUE_TO_ERRORS: String =
|
||||||
|
"// This class file has inconsistent Kotlin meta-information and can't be decompiled.\n" +
|
||||||
|
"//\n" +
|
||||||
|
"// $REASON"
|
||||||
|
|
||||||
public fun buildDecompiledText(
|
public fun buildDecompiledText(
|
||||||
classFile: VirtualFile,
|
classFile: VirtualFile,
|
||||||
resolver: ResolverForDecompiler = DeserializerForDecompiler(classFile)
|
resolver: ResolverForDecompiler = DeserializerForDecompiler(classFile)
|
||||||
@@ -70,6 +80,11 @@ public fun buildDecompiledText(
|
|||||||
buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())))
|
buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())))
|
||||||
classHeader.isCompatibleClassKind() ->
|
classHeader.isCompatibleClassKind() ->
|
||||||
buildDecompiledText(packageFqName, listOf(resolver.resolveTopLevelClass(classId)).filterNotNull())
|
buildDecompiledText(packageFqName, listOf(resolver.resolveTopLevelClass(classId)).filterNotNull())
|
||||||
|
classHeader.isCompatibleMultifileClassKind() -> {
|
||||||
|
val partClasses = findMultifileClassParts(classFile, kotlinClass)
|
||||||
|
val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) }
|
||||||
|
buildDecompiledText(packageFqName, partMembers)
|
||||||
|
}
|
||||||
else ->
|
else ->
|
||||||
throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}")
|
throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// IntelliJ API Decompiler stub source generated from a class file
|
||||||
|
// Implementation of methods is not available
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
public val p: kotlin.Int /* compiled code */
|
||||||
|
|
||||||
|
public fun f(): kotlin.Unit { /* compiled code */ }
|
||||||
|
|
||||||
|
private var i: kotlin.Int /* compiled code */
|
||||||
|
|
||||||
|
public fun kotlin.Int.plus(i: kotlin.Int /* = compiled code */): kotlin.Int { /* compiled code */ }
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
@file:JvmName("MultifileClass")
|
||||||
|
@file:JvmMultifileClass
|
||||||
|
package test
|
||||||
|
|
||||||
|
private var i = 2
|
||||||
|
|
||||||
|
fun Int.plus(i: Int = 1) = this + i
|
||||||
|
|
||||||
|
class ShouldNotBeVisible1
|
||||||
|
interface ShouldNotBeVisible2
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@file:JvmName("MultifileClass")
|
||||||
|
@file:JvmMultifileClass
|
||||||
|
package test
|
||||||
|
|
||||||
|
fun f() {}
|
||||||
|
val p = 3
|
||||||
+6
@@ -35,6 +35,12 @@ public class JvmDecompiledTextTestGenerated extends AbstractJvmDecompiledTextTes
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/decompiler/decompiledTextJvm"), Pattern.compile("^([^\\.]+)$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/decompiler/decompiledTextJvm"), Pattern.compile("^([^\\.]+)$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("MultifileClass")
|
||||||
|
public void testMultifileClass() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/decompiler/decompiledTextJvm/MultifileClass/");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("TestKt")
|
@TestMetadata("TestKt")
|
||||||
public void testTestKt() throws Exception {
|
public void testTestKt() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/decompiler/decompiledTextJvm/TestKt/");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/decompiler/decompiledTextJvm/TestKt/");
|
||||||
|
|||||||
Reference in New Issue
Block a user