diff --git a/analysis/decompiled/decompiler-to-psi/src/org/jetbrains/kotlin/analysis/decompiler/psi/text/buildDecompiledText.kt b/analysis/decompiled/decompiler-to-psi/src/org/jetbrains/kotlin/analysis/decompiler/psi/text/buildDecompiledText.kt index 3933a580272..0108929b195 100644 --- a/analysis/decompiled/decompiler-to-psi/src/org/jetbrains/kotlin/analysis/decompiler/psi/text/buildDecompiledText.kt +++ b/analysis/decompiled/decompiler-to-psi/src/org/jetbrains/kotlin/analysis/decompiler/psi/text/buildDecompiledText.kt @@ -12,18 +12,14 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.contracts.description.ContractProviderKey import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRendererModifier import org.jetbrains.kotlin.renderer.DescriptorRendererOptions import org.jetbrains.kotlin.renderer.render -import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors import org.jetbrains.kotlin.types.isFlexible -import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly private const val DECOMPILED_CODE_COMMENT = "/* compiled code */" @@ -44,18 +40,35 @@ fun DescriptorRendererOptions.defaultDecompilerRendererOptions() { propertyConstantRenderer = { _ -> COMPILED_DEFAULT_INITIALIZER } } +/** + * @see org.jetbrains.kotlin.analysis.decompiler.stub.mustNotBeWrittenToStubs + */ internal fun CallableMemberDescriptor.mustNotBeWrittenToDecompiledText(): Boolean { return when (kind) { CallableMemberDescriptor.Kind.DECLARATION, CallableMemberDescriptor.Kind.DELEGATION -> false CallableMemberDescriptor.Kind.FAKE_OVERRIDE -> true - CallableMemberDescriptor.Kind.SYNTHESIZED -> { - // Of all synthesized functions, only `component*` functions are rendered (for historical reasons) - !DataClassDescriptorResolver.isComponentLike(name) && name !in listOf( - OperatorNameConventions.EQUALS, - StandardNames.HASHCODE_NAME, - OperatorNameConventions.TO_STRING + CallableMemberDescriptor.Kind.SYNTHESIZED -> syntheticMemberMustNotBeWrittenToDecompiledText() + } +} + +private fun CallableMemberDescriptor.syntheticMemberMustNotBeWrittenToDecompiledText(): Boolean { + val containingClass = containingDeclaration as? ClassDescriptor ?: return false + + return when { + containingClass.isData && containingClass.kind != ClassKind.OBJECT -> { + // we want to materialize every synthetic data class function except for the 'copy' (for historical reasons) + name == StandardNames.DATA_CLASS_COPY + } + + containingClass.kind == ClassKind.ENUM_CLASS -> { + name in arrayOf( + StandardNames.ENUM_VALUES, + StandardNames.ENUM_ENTRIES, + StandardNames.ENUM_VALUE_OF, ) } + + else -> false } } diff --git a/analysis/decompiled/decompiler-to-stubs/src/org/jetbrains/kotlin/analysis/decompiler/stub/CallableClsStubBuilder.kt b/analysis/decompiled/decompiler-to-stubs/src/org/jetbrains/kotlin/analysis/decompiler/stub/CallableClsStubBuilder.kt index 830416b0258..d9946046b61 100644 --- a/analysis/decompiled/decompiler-to-stubs/src/org/jetbrains/kotlin/analysis/decompiler/stub/CallableClsStubBuilder.kt +++ b/analysis/decompiled/decompiler-to-stubs/src/org/jetbrains/kotlin/analysis/decompiler/stub/CallableClsStubBuilder.kt @@ -26,12 +26,10 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.stubs.KotlinPropertyStub import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes import org.jetbrains.kotlin.psi.stubs.impl.* -import org.jetbrains.kotlin.resolve.DataClassResolver import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer import org.jetbrains.kotlin.serialization.deserialization.getName -import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.runIf @@ -55,14 +53,14 @@ fun createDeclarationsStubs( propertyProtos: List, ) { for (propertyProto in propertyProtos) { - if (mustNotBeWrittenToStubs(propertyProto.flags, outerContext.nameResolver.getName(propertyProto.name))) { + if (mustNotBeWrittenToStubs(propertyProto.flags, outerContext.nameResolver.getName(propertyProto.name), protoContainer)) { continue } PropertyClsStubBuilder(parentStub, outerContext, protoContainer, propertyProto).build() } for (functionProto in functionProtos) { - if (mustNotBeWrittenToStubs(functionProto.flags, outerContext.nameResolver.getName(functionProto.name))) { + if (mustNotBeWrittenToStubs(functionProto.flags, outerContext.nameResolver.getName(functionProto.name), protoContainer)) { continue } @@ -90,15 +88,27 @@ fun createConstructorStub( ConstructorClsStubBuilder(parentStub, outerContext, protoContainer, constructorProto).build() } -private fun mustNotBeWrittenToStubs(flags: Int, name: Name): Boolean { +/** + * @see org.jetbrains.kotlin.analysis.decompiler.psi.text.mustNotBeWrittenToDecompiledText + */ +private fun mustNotBeWrittenToStubs(flags: Int, name: Name, protoContainer: ProtoContainer): Boolean { return when (Flags.MEMBER_KIND.get(flags)) { MemberKind.FAKE_OVERRIDE -> true //TODO: fix decompiler to use sane criteria - MemberKind.SYNTHESIZED -> !DataClassResolver.isComponentLike(name) && name !in listOf( - OperatorNameConventions.EQUALS, - StandardNames.HASHCODE_NAME, - OperatorNameConventions.TO_STRING - ) + MemberKind.SYNTHESIZED -> syntheticMemberMustNotBeWrittenToStubs(name, protoContainer) + else -> false + } +} + +private fun syntheticMemberMustNotBeWrittenToStubs(name: Name, protoContainer: ProtoContainer): Boolean { + val containingClass = protoContainer as? ProtoContainer.Class ?: return false + + return when { + containingClass.isData && containingClass.kind != ProtoBuf.Class.Kind.OBJECT -> { + // we want to materialize every synthetic data class function except for the 'copy' (for historical reasons) + name == StandardNames.DATA_CLASS_COPY + } + else -> false } } diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt index 4368127d729..adf9b1f4686 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/stubs/KotlinStubVersions.kt @@ -17,7 +17,7 @@ object KotlinStubVersions { // Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed // or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder). // Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files). - private const val BINARY_STUB_VERSION = 97 + private const val BINARY_STUB_VERSION = 98 // Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile) // Increasing this version will lead to reindexing of all classfiles. diff --git a/core/deserialization.common/src/org/jetbrains/kotlin/serialization/deserialization/ProtoContainer.kt b/core/deserialization.common/src/org/jetbrains/kotlin/serialization/deserialization/ProtoContainer.kt index 74e9d4d956d..e460a09e47c 100644 --- a/core/deserialization.common/src/org/jetbrains/kotlin/serialization/deserialization/ProtoContainer.kt +++ b/core/deserialization.common/src/org/jetbrains/kotlin/serialization/deserialization/ProtoContainer.kt @@ -29,6 +29,7 @@ sealed class ProtoContainer( val kind: ProtoBuf.Class.Kind = Flags.CLASS_KIND.get(classProto.flags) ?: ProtoBuf.Class.Kind.CLASS val isInner: Boolean = Flags.IS_INNER.get(classProto.flags) + val isData: Boolean = Flags.IS_DATA.get(classProto.flags) override fun debugFqName(): FqName = classId.asSingleFqName() }