KTIJ-2448 Correctly filter synthetic declarations in buildDecompiledText

We used to render any callable declaration that's either
a directly-declared one, or which name starts with `component*`.

It works incorrectly when there are delegated or fake overridden
callables named `component*` coming from base classes or interfaces.

This makes `buildDecompiledText` render only synthesised `component*`
functions (which should come only from the data-classes).

^KTIJ-2448 Fixed

GitOrigin-RevId: 5f4b0625eaf95424f268b776f5cfd8a2b6820338
This commit is contained in:
Roman Golyshev
2021-10-11 18:53:39 +00:00
committed by intellij-monorepo-bot
parent 89f559ea32
commit 5848cce95e
6 changed files with 45 additions and 5 deletions
@@ -54,6 +54,20 @@ fun buildDecompiledText(
textIndex.addToIndex(descriptor, TextRange(startOffset, endOffset))
}
fun CallableMemberDescriptor.isConsideredSynthetic(): Boolean {
return when (kind) {
CallableMemberDescriptor.Kind.DECLARATION -> false
CallableMemberDescriptor.Kind.FAKE_OVERRIDE,
CallableMemberDescriptor.Kind.DELEGATION -> true
CallableMemberDescriptor.Kind.SYNTHESIZED -> {
// Of all synthesized functions, only `component*` functions are rendered (for historical reasons)
!DataClassDescriptorResolver.isComponentLike(name)
}
}
}
fun appendDescriptor(descriptor: DeclarationDescriptor, indent: String, lastEnumEntry: Boolean? = null) {
val startOffset = builder.length
if (isEnumEntry(descriptor)) {
@@ -128,11 +142,7 @@ fun buildDecompiledText(
if (member == companionObject) {
continue
}
if (member is CallableMemberDescriptor
&& member.kind != CallableMemberDescriptor.Kind.DECLARATION
//TODO: not synthesized and component like
&& !DataClassDescriptorResolver.isComponentLike(member.name)
) {
if (member is CallableMemberDescriptor && member.isConsideredSynthetic()) {
continue
}
newlineExceptFirst()
@@ -54,6 +54,11 @@ public class CommonDecompiledTextFromJsMetadataTestGenerated extends AbstractCom
runTest("testData/decompiler/decompiledText/ClassWithClassObject/");
}
@TestMetadata("ClassWithDelegatedComponentFunctions")
public void testClassWithDelegatedComponentFunctions() throws Exception {
runTest("testData/decompiler/decompiledText/ClassWithDelegatedComponentFunctions/");
}
@TestMetadata("ClassWithNamedClassObject")
public void testClassWithNamedClassObject() throws Exception {
runTest("testData/decompiler/decompiledText/ClassWithNamedClassObject/");
@@ -53,6 +53,11 @@ public class CommonDecompiledTextTestGenerated extends AbstractCommonDecompiledT
runTest("testData/decompiler/decompiledText/ClassWithClassObject/");
}
@TestMetadata("ClassWithDelegatedComponentFunctions")
public void testClassWithDelegatedComponentFunctions() throws Exception {
runTest("testData/decompiler/decompiledText/ClassWithDelegatedComponentFunctions/");
}
@TestMetadata("ClassWithNamedClassObject")
public void testClassWithNamedClassObject() throws Exception {
runTest("testData/decompiler/decompiledText/ClassWithNamedClassObject/");
@@ -0,0 +1,7 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package test
public final class ClassWithDelegatedComponentFunctions public constructor(delegate: dependency.ComponentInterface) : dependency.ComponentInterface {
}
@@ -0,0 +1,5 @@
package test
import dependency.ComponentInterface
class ClassWithDelegatedComponentFunctions(delegate: ComponentInterface): ComponentInterface by delegate
@@ -0,0 +1,8 @@
package dependency
interface ComponentInterface {
operator fun component1(): Int
fun component2(): Int
val component3: Int
}