Fix the problem with ConvertPrimaryConstructorToSecondaryIntention for enum #KT-15406 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
245f23e7c2
commit
ad9bf1626f
+32
-6
@@ -17,11 +17,14 @@
|
|||||||
package org.jetbrains.kotlin.idea.intentions
|
package org.jetbrains.kotlin.idea.intentions
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.THIS_KEYWORD
|
import org.jetbrains.kotlin.lexer.KtTokens.THIS_KEYWORD
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.VARARG_KEYWORD
|
import org.jetbrains.kotlin.lexer.KtTokens.VARARG_KEYWORD
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -29,6 +32,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactory.CallableBuilder
|
|||||||
import org.jetbrains.kotlin.psi.KtPsiFactory.CallableBuilder.Target.CONSTRUCTOR
|
import org.jetbrains.kotlin.psi.KtPsiFactory.CallableBuilder.Target.CONSTRUCTOR
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||||
|
|
||||||
@@ -118,9 +122,26 @@ class ConvertPrimaryConstructorToSecondaryIntention : SelfTargetingIntention<KtP
|
|||||||
}
|
}
|
||||||
}.asString()
|
}.asString()
|
||||||
)
|
)
|
||||||
with (klass.addDeclarationBefore(constructor, null)) {
|
|
||||||
commentSaver.restore(this)
|
val lastEnumEntry = klass.declarations.lastOrNull { it is KtEnumEntry } as? KtEnumEntry
|
||||||
|
val secondaryConstructor =
|
||||||
|
lastEnumEntry?.let { klass.addDeclarationAfter(constructor, it) } ?: klass.addDeclarationBefore(constructor, null)
|
||||||
|
commentSaver.restore(secondaryConstructor)
|
||||||
|
|
||||||
|
convertValueParametersToProperties(element, klass, factory, lastEnumEntry)
|
||||||
|
if (klass.isEnum()) {
|
||||||
|
addSemicolonIfNotExist(klass, factory, lastEnumEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (anonymousInitializer in klass.getAnonymousInitializers()) {
|
||||||
|
anonymousInitializer.delete()
|
||||||
|
}
|
||||||
|
element.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertValueParametersToProperties(
|
||||||
|
element: KtPrimaryConstructor, klass: KtClass, factory: KtPsiFactory, anchorBefore: PsiElement?
|
||||||
|
) {
|
||||||
for (valueParameter in element.valueParameters.reversed()) {
|
for (valueParameter in element.valueParameters.reversed()) {
|
||||||
if (!valueParameter.hasValOrVar()) continue
|
if (!valueParameter.hasValOrVar()) continue
|
||||||
val isVararg = valueParameter.hasModifier(VARARG_KEYWORD)
|
val isVararg = valueParameter.hasModifier(VARARG_KEYWORD)
|
||||||
@@ -129,11 +150,16 @@ class ConvertPrimaryConstructorToSecondaryIntention : SelfTargetingIntention<KtP
|
|||||||
val property = factory.createProperty(valueParameter.modifierList?.text, valueParameter.name!!,
|
val property = factory.createProperty(valueParameter.modifierList?.text, valueParameter.name!!,
|
||||||
if (isVararg && typeText != null) "Array<out $typeText>" else typeText,
|
if (isVararg && typeText != null) "Array<out $typeText>" else typeText,
|
||||||
valueParameter.isMutable, null)
|
valueParameter.isMutable, null)
|
||||||
klass.addDeclarationBefore(property, null)
|
if (anchorBefore == null) klass.addDeclarationBefore(property, null) else klass.addDeclarationAfter(property, anchorBefore)
|
||||||
}
|
}
|
||||||
for (anonymousInitializer in klass.getAnonymousInitializers()) {
|
}
|
||||||
anonymousInitializer.delete()
|
|
||||||
|
private fun addSemicolonIfNotExist(klass: KtClass, factory: KtPsiFactory, lastEnumEntry: KtEnumEntry?) {
|
||||||
|
if (lastEnumEntry == null) {
|
||||||
|
klass.getOrCreateBody().let { it.addAfter(factory.createSemicolon(), it.lBrace) }
|
||||||
|
}
|
||||||
|
else if (lastEnumEntry.getChildrenOfType<LeafPsiElement>().none { it.elementType == KtTokens.SEMICOLON }) {
|
||||||
|
lastEnumEntry.add(factory.createSemicolon())
|
||||||
}
|
}
|
||||||
element.delete()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
enum class A(<caret>v: Int) {
|
||||||
|
E1(0), E2(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
enum class A {
|
||||||
|
E1(0), E2(1);
|
||||||
|
|
||||||
|
constructor(v: Int)
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
enum class A(<caret>v: Int) {
|
||||||
|
E1(0), E2(1);
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
enum class A {
|
||||||
|
E1(0), E2(1);
|
||||||
|
|
||||||
|
constructor(v: Int)
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
enum class A(val <caret>a: Int, val b: Int) {
|
||||||
|
E1(0, 0), E2(1, 1);
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
enum class A {
|
||||||
|
E1(0, 0), E2(1, 1);
|
||||||
|
|
||||||
|
val a: Int
|
||||||
|
val b: Int
|
||||||
|
|
||||||
|
constructor(a: Int, b: Int) {
|
||||||
|
this.a = a
|
||||||
|
this.b = b
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
enum class A(<caret>v: Int) {
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
enum class A {;
|
||||||
|
|
||||||
|
constructor(v: Int)
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
enum class A(<caret>v: Int) {
|
||||||
|
E1(0), E2(1)
|
||||||
|
}
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
enum class A {
|
||||||
|
E1(0), E2(1);
|
||||||
|
|
||||||
|
constructor(v: Int)
|
||||||
|
}
|
||||||
@@ -4826,6 +4826,36 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enum.kt")
|
||||||
|
public void testEnum() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/enum.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumWIthFunction.kt")
|
||||||
|
public void testEnumWIthFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/enumWIthFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumWithParams.kt")
|
||||||
|
public void testEnumWithParams() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/enumWithParams.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumWithoutEntries.kt")
|
||||||
|
public void testEnumWithoutEntries() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/enumWithoutEntries.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumWithoutSemicolon.kt")
|
||||||
|
public void testEnumWithoutSemicolon() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/enumWithoutSemicolon.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("independentProperty.kt")
|
@TestMetadata("independentProperty.kt")
|
||||||
public void testIndependentProperty() throws Exception {
|
public void testIndependentProperty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/independentProperty.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/independentProperty.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user