diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java index 707a85efd62..bbf84709919 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.java @@ -49,6 +49,7 @@ import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil; import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil; import org.jetbrains.kotlin.idea.util.ProjectRootsUtil; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; +import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; @@ -306,10 +307,9 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport } } else { - PsiClass clsClass = getLightClassForDecompiledFacade(packageFqName, files); - if (clsClass != null) { - result.add(clsClass); - } + FqName packageFacadeFqName = PackageClassUtils.getPackageClassFqName(packageFqName); + List clsClasses = getLightClassesForDecompiledFacadeFiles(packageFacadeFqName, files); + result.addAll(clsClasses); } } return result; @@ -339,10 +339,8 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport } } else { - PsiClass clsClass = getLightClassForDecompiledFacade(facadeFqName, files); - if (clsClass != null) { - result.add(clsClass); - } + List clsClasses = getLightClassesForDecompiledFacadeFiles(facadeFqName, files); + result.addAll(clsClasses); } } return result; @@ -377,15 +375,14 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport } @Nullable - private static PsiClass getLightClassForDecompiledFacade(@NotNull FqName facadeFqName, @NotNull List filesWithCallables) { - JetFile firstFile = filesWithCallables.iterator().next(); - if (firstFile.isCompiled()) { - if (filesWithCallables.size() > 1) { - LOG.error("Several files with callables for facade: " + facadeFqName); + private static List getLightClassesForDecompiledFacadeFiles(@NotNull FqName facadeFqName, @NotNull List filesWithCallables) { + List lightClasses = new ArrayList(); + for (JetFile file : filesWithCallables) { + if (file.isCompiled()) { + lightClasses.add(createLightClassForDecompiledKotlinFile(file)); } - return createLightClassForDecompiledKotlinFile(firstFile); } - return null; + return lightClasses; } @NotNull diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt index 805ba1bf97c..cc1edc19ac7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt @@ -22,7 +22,9 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache +import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind +import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.renderer.DescriptorRenderer @@ -64,7 +66,11 @@ public fun buildDecompiledText( mapOf()) } classHeader.isCompatiblePackageFacadeKind() -> - buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInPackage(packageFqName))) + buildDecompiledText(packageFqName, + ArrayList(resolver.resolveDeclarationsInFacade(PackageClassUtils.getPackageClassFqName(packageFqName)))) + classHeader.isCompatibleFileFacadeKind() -> + buildDecompiledText(packageFqName, + ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName()))) classHeader.isCompatibleClassKind() -> buildDecompiledText(packageFqName, listOf(resolver.resolveTopLevelClass(classId)).filterNotNull()) else -> @@ -80,7 +86,9 @@ public fun buildDecompiledTextFromJsMetadata( val isPackageHeader = JsMetaFileUtils.isPackageHeader(classFile) if (isPackageHeader) { - return buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInPackage(packageFqName)), descriptorRendererForKotlinJavascriptDecompiler) + return buildDecompiledText(packageFqName, + resolveDeclarationsInPackage(packageFqName, resolver), + descriptorRendererForKotlinJavascriptDecompiler) } else { val classId = JsMetaFileUtils.getClassId(classFile) @@ -88,6 +96,9 @@ public fun buildDecompiledTextFromJsMetadata( } } +private fun resolveDeclarationsInPackage(packageFqName: FqName, resolver: ResolverForDecompiler) = + ArrayList(resolver.resolveDeclarationsInFacade(PackageClassUtils.getPackageClassFqName(packageFqName))) + private val DECOMPILED_CODE_COMMENT = "/* compiled code */" private val DECOMPILED_COMMENT_FOR_PARAMETER = "/* = compiled code */" private val FLEXIBLE_TYPE_COMMENT = "/* platform type */" 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 45bde4c59ee..b891cea41b8 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 @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.load.kotlin.BinaryClassAnnotationAndConstantLoaderIm 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.serialization.deserialization.ClassDescriptorFactory import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents @@ -53,12 +54,15 @@ public class DeserializerForDecompiler( ResolveEverythingToKotlinAnyLocalClassResolver, JavaFlexibleTypeCapabilitiesDeserializer, ClassDescriptorFactory.EMPTY ) - override fun resolveDeclarationsInPackage(packageFqName: FqName): Collection { - assert(packageFqName == directoryPackageFqName) { "Was called for $packageFqName but only $directoryPackageFqName is expected" } - val binaryClassForPackageClass = classFinder.findKotlinClass(PackageClassUtils.getPackageClassId(packageFqName)) + override fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection { + val packageFqName = facadeFqName.parent() + assert(packageFqName == directoryPackageFqName) { + "Was called for $facadeFqName; only members of $directoryPackageFqName package are expected." + } + val binaryClassForPackageClass = classFinder.findKotlinClass(ClassId.topLevel(facadeFqName)) val annotationData = binaryClassForPackageClass?.getClassHeader()?.annotationData if (annotationData == null) { - LOG.error("Could not read annotation data for $packageFqName from ${binaryClassForPackageClass?.getClassId()}") + LOG.error("Could not read annotation data for $facadeFqName from ${binaryClassForPackageClass?.getClassId()}") return emptyList() } val packageData = JvmProtoBufUtil.readPackageDataFrom(annotationData) 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 index 363b34a88eb..1dfa5dead78 100644 --- 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 @@ -21,6 +21,7 @@ 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.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.serialization.deserialization.ClassDescriptorFactory import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents @@ -55,11 +56,14 @@ public class KotlinJavaScriptDeserializerForDecompiler( ResolveEverythingToKotlinAnyLocalClassResolver, FlexibleTypeCapabilitiesDeserializer.Dynamic, ClassDescriptorFactory.EMPTY ) - 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)) + override fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection { + val packageFqName = facadeFqName.parent() + assert(packageFqName == directoryPackageFqName) { + "Was called for $facadeFqName; only members of $directoryPackageFqName package are expected." + } + val file = metaFileFinder.findKotlinJavascriptMetaFile(ClassId.topLevel(facadeFqName)) if (file == null) { - LOG.error("Could not read data for $packageFqName") + LOG.error("Could not read data for $facadeFqName") return emptyList() } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/ResolverForDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/ResolverForDecompiler.kt index 6299d4a1df5..9250a6d13e6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/ResolverForDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/ResolverForDecompiler.kt @@ -24,5 +24,5 @@ import org.jetbrains.kotlin.name.ClassId public interface ResolverForDecompiler { public fun resolveTopLevelClass(classId: ClassId): ClassDescriptor? - public fun resolveDeclarationsInPackage(packageFqName: FqName): Collection + public fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection } diff --git a/idea/testData/debugger/tinyApp/outs/stepIntoStdlibFacadeClass.out b/idea/testData/debugger/tinyApp/outs/stepIntoStdlibFacadeClass.out index 8fde5157a9a..c38579f8fc3 100644 --- a/idea/testData/debugger/tinyApp/outs/stepIntoStdlibFacadeClass.out +++ b/idea/testData/debugger/tinyApp/outs/stepIntoStdlibFacadeClass.out @@ -2,7 +2,7 @@ LineBreakpoint created at stepIntoStdlibFacadeClass.kt:6 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! stepIntoStdlibFacadeClass.StepIntoStdlibFacadeClassPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' stepIntoStdlibFacadeClass.kt:6 -KotlinPackage.!EXT! +SequenceKt.!EXT! _Mapping.!EXT! Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/TextConsistencyBaseTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/TextConsistencyBaseTest.kt index d081e644a41..bd48fa363f9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/TextConsistencyBaseTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/TextConsistencyBaseTest.kt @@ -67,8 +67,9 @@ private class ResolverForDecompilerImpl(val module: ModuleDescriptor) : Resolver return module.resolveTopLevelClass(classId.asSingleFqName(), NoLookupLocation.FROM_TEST) } - override fun resolveDeclarationsInPackage(packageFqName: FqName): Collection { - return module.getPackage(packageFqName).memberScope.getAllDescriptors() filter { + override fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection { + // TODO how to handle non-package facades properly here? + return module.getPackage(facadeFqName.parent()).memberScope.getAllDescriptors() filter { it is CallableMemberDescriptor && it.module != KotlinBuiltIns.getInstance().getBuiltInsModule() } sortBy MemberComparator.INSTANCE } diff --git a/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt b/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt index 7334b17c2ca..4155f6742ca 100644 --- a/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt +++ b/jps-plugin/test/org/jetbrains/kotlin/jps/build/classFilesComparison/classFilesComparison.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.serialization.DebugProtoBuf import java.util.Arrays import org.jetbrains.kotlin.jps.incremental.LocalFileKotlinClass import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind +import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind // Set this to true if you want to dump all bytecode (test will fail in this case) @@ -144,7 +145,8 @@ fun classFileToString(classFile: File): String { when { classHeader!!.isCompatiblePackageFacadeKind() -> out.write("\n------ package proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") - + classHeader.isCompatibleFileFacadeKind() -> + out.write("\n------ file facade proto -----\n${DebugProtoBuf.Package.parseFrom(input, getExtensionRegistry())}") classHeader.isCompatibleClassKind() -> out.write("\n------ class proto -----\n${DebugProtoBuf.Class.parseFrom(input, getExtensionRegistry())}")