From f49bd55a33892227089d6050d8cda616423bd05b Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Mon, 29 Sep 2025 20:53:19 +0200 Subject: [PATCH] [kotlin] KTIJ-35779 Fix Implement members when body has no braces GitOrigin-RevId: bc8a0d005478d6bbdc86936718251ec2abe7473f --- .../kotlin/idea/core/generateUtils.kt | 13 ++++++++----- .../KtGenerateMembersHandler.kt | 2 +- .../codeInsight/FirOverrideImplementTest.kt | 4 ++++ .../idea/codeInsight/OverrideImplementTest.kt | 4 ++++ .../overrideFunctionPropertyWithoutBody.kt | 15 +++++++++++++++ ...verrideFunctionPropertyWithoutBody.kt.after | 18 ++++++++++++++++++ 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt create mode 100644 plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt.after diff --git a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/core/generateUtils.kt b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/core/generateUtils.kt index 9d126c56662f..2bb380c84705 100644 --- a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/core/generateUtils.kt +++ b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/core/generateUtils.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.psi.psiUtil.allChildren import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import kotlin.math.min fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) { @@ -222,11 +223,13 @@ fun insertMembersAfter( commentOrSpace.copy().also { commentOrSpace.delete() } } } - val body = classOrObject.getOrCreateBody() - val lBrace = body.lBrace - if (lBrace != null) { - tailComments.reversed().map { body.addAfter(it, lBrace) } + val existedBody = classOrObject.body + val body = existedBody?.takeIf { it.lBrace != null } ?: run { + existedBody?.delete() + classOrObject.getOrCreateBody() } + val lBrace = body.lBrace ?: throw KotlinExceptionWithAttachments("no lBrace").withPsiAttachment("classOrObject", classOrObject) + tailComments.reversed().forEach { body.addAfter(it, lBrace) } var afterAnchor = anchor ?: findInsertAfterAnchor(editor, body) ?: return emptyList() otherMembers.mapTo(insertedMembers) { @@ -242,7 +245,7 @@ fun insertMembersAfter( afterAnchor = bound } } else if (bound == null && body.declarations.isNotEmpty()) { - afterAnchor = body.lBrace!! + afterAnchor = lBrace } else if (bound != null && afterAnchor.startOffset > bound.startOffset) { afterAnchor = bound.prevSibling!! } diff --git a/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt b/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt index b90404d97b8e..2b10040d082c 100644 --- a/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt +++ b/plugins/kotlin/code-insight/override-implement-k2/src/org/jetbrains/kotlin/idea/core/overrideImplement/KtGenerateMembersHandler.kt @@ -182,7 +182,7 @@ abstract class KtGenerateMembersHandler( * implementation for the chosen symbol. */ context(_: KaSession) -private fun getMembersOrderedByRelativePositionsInSuperTypes( + private fun getMembersOrderedByRelativePositionsInSuperTypes( currentClass: KtClassOrObject, newMemberSymbolsAndGeneratedPsi: Map ): List { diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirOverrideImplementTest.kt b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirOverrideImplementTest.kt index 5bdc265e9c73..6873779f3493 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirOverrideImplementTest.kt +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/codeInsight/FirOverrideImplementTest.kt @@ -144,6 +144,10 @@ internal class FirOverrideImplementTest : OverrideImplementTest() super.testOverrideFunctionProperty() } + override fun testOverrideFunctionPropertyWithoutBody() { + super.testOverrideFunctionPropertyWithoutBody() + } + override fun testOverridePrimitiveProperty() { super.testOverridePrimitiveProperty() } diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt index 519df735144d..e7ecd966b877 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt @@ -133,6 +133,10 @@ abstract class OverrideImplementTest : AbstractOverrideImplemen doOverrideFileTest() } + open fun testOverrideFunctionPropertyWithoutBody() { + doOverrideFileTest() + } + open fun testOverridePrimitiveProperty() { doMultiImplementFileTest() } diff --git a/plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt b/plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt new file mode 100644 index 000000000000..48c75410dc78 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt @@ -0,0 +1,15 @@ +// FIR_IDENTICAL +open class A() { + open val method : () -> Unit? = {println("hello")} +} + +fun some() : A { + return object : A() +} + +// TODO: need better selection and caret + +// MEMBER: "method: () -> Unit?" +// MEMBER: "equals(other: Any?): Boolean" +// MEMBER: "hashCode(): Int" +// MEMBER: "toString(): String" \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt.after b/plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt.after new file mode 100644 index 000000000000..7db3bd77ea4f --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/codeInsight/overrideImplement/overrideFunctionPropertyWithoutBody.kt.after @@ -0,0 +1,18 @@ +// FIR_IDENTICAL +open class A() { + open val method : () -> Unit? = {println("hello")} +} + +fun some() : A { + return object : A() { + override val method: () -> Unit? + get() = super.method + } +} + +// TODO: need better selection and caret + +// MEMBER: "method: () -> Unit?" +// MEMBER: "equals(other: Any?): Boolean" +// MEMBER: "hashCode(): Int" +// MEMBER: "toString(): String" \ No newline at end of file