diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt index fd1315665e0..edda66f5a66 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetPsiFactory.kt @@ -261,6 +261,11 @@ public class JetPsiFactory(private val project: Project) { return createDeclaration("enum class E {$text}").getDeclarations()[0] as JetEnumEntry } + public fun createEnumEntrySuperclassReferenceExpression(): JetEnumEntrySuperclassReferenceExpression { + val userType = createEnumEntry("Entry()").getInitializerList()!!.getInitializers()[0].getTypeReference()!!.getTypeElement() as JetUserType + return userType.getReferenceExpression() as JetEnumEntrySuperclassReferenceExpression + } + public fun createWhenEntry(entryText: String): JetWhenEntry { val function = createFunction("fun foo() { when(12) { " + entryText + " } }") val whenEntry = PsiTreeUtil.findChildOfType(function, javaClass()) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedEnumEntrySuperConstructorSyntaxFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedEnumEntrySuperConstructorSyntaxFix.kt new file mode 100644 index 00000000000..ed6540c833b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedEnumEntrySuperConstructorSyntaxFix.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.JetNodeTypes +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.psi +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getChildOfType +import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes +import org.jetbrains.kotlin.resolve.DeclarationsChecker + +class DeprecatedEnumEntrySuperConstructorSyntaxFix(element: JetEnumEntry): JetIntentionAction(element) { + override fun getFamilyName(): String = getText() + + override fun getText(): String = "Change to short enum entry super constructor" + + override fun invoke(project: Project, editor: Editor?, file: JetFile?) = changeConstructorToShort(element) + + companion object: JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? = + diagnostic.createIntentionForFirstParentOfType(::DeprecatedEnumEntrySuperConstructorSyntaxFix) + + public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory { + JetWholeProjectForEachElementOfTypeFix.createByPredicate( + predicate = { DeclarationsChecker.enumEntryUsesDeprecatedSuperConstructor(it) }, + taskProcessor = { changeConstructorToShort(it) }, + modalTitle = "Replacing deprecated enum constructor syntax", + name = "Change to short enum entry super constructor in the whole project", + familyName = "Change to short enum entry super constructor in the whole project" + ) + } + + private fun transformInitializerList(list: JetInitializerList) { + val psiFactory = JetPsiFactory(list) + val userType = list.getInitializers()[0].getTypeReference()!!.getTypeElement() as JetUserType + userType.getReferenceExpression()!!.replace(psiFactory.createEnumEntrySuperclassReferenceExpression()) + } + + private fun changeConstructorToShort(entry: JetEnumEntry) { + val list = entry.getInitializerList()!! + transformInitializerList(list) + // Delete everything between name and initializer (colon with whitespaces) + entry.deleteChildRange(entry.getFirstChild().getNextSibling(), list.getPrevSibling()) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java index 5b0221d9bac..57d4b3c8d9e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.java @@ -325,5 +325,8 @@ public class QuickFixRegistrar { QuickFixes.factories.put(DEPRECATED_ANNOTATION_SYNTAX, DeprecatedAnnotationSyntaxFix.Companion); QuickFixes.factories.put(DEPRECATED_ANNOTATION_SYNTAX, DeprecatedAnnotationSyntaxFix.Companion.createWholeProjectFixFactory()); + + QuickFixes.factories.put(ENUM_ENTRY_USES_DEPRECATED_SUPER_CONSTRUCTOR, DeprecatedEnumEntrySuperConstructorSyntaxFix.Companion); + QuickFixes.factories.put(ENUM_ENTRY_USES_DEPRECATED_SUPER_CONSTRUCTOR, DeprecatedEnumEntrySuperConstructorSyntaxFix.Companion.createWholeProjectFixFactory()); } } diff --git a/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt b/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt index 36abff1bfd5..34c2c851668 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/parameter/parameterFromEnumEntryDelegationSpecifier.kt @@ -3,5 +3,5 @@ // ACTION: Create property 'x' enum class E(n: Int) { - X: E(x) + X(x) } \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt new file mode 100644 index 00000000000..419d4ad506c --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt @@ -0,0 +1,8 @@ +// "Change to short enum entry super constructor" "true" + +enum class MyEnum(val z: Int) { + A: MyEnum(3) + B(7) + C(12) + fun foo() = z * 2 +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt.after b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt.after new file mode 100644 index 00000000000..92d6cb59538 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt.after @@ -0,0 +1,8 @@ +// "Change to short enum entry super constructor" "true" + +enum class MyEnum(val z: Int) { + A(3) + B(7) + C(12) + fun foo() = z * 2 +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt new file mode 100644 index 00000000000..2345cc9fa3c --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt @@ -0,0 +1,8 @@ +// "Change to short enum entry super constructor" "true" + +enum class MyEnum(val z: Int) { + A(3) + B(7) + C: MyEnum(12) + fun foo() = z * 2 +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt.after b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt.after new file mode 100644 index 00000000000..92d6cb59538 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt.after @@ -0,0 +1,8 @@ +// "Change to short enum entry super constructor" "true" + +enum class MyEnum(val z: Int) { + A(3) + B(7) + C(12) + fun foo() = z * 2 +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/singleEntry.kt b/idea/testData/quickfix/migration/enumConstructor/singleEntry.kt new file mode 100644 index 00000000000..a2a87402e19 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/singleEntry.kt @@ -0,0 +1,5 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String) { + UNIQUE: SimpleEnum("42") +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/singleEntry.kt.after b/idea/testData/quickfix/migration/enumConstructor/singleEntry.kt.after new file mode 100644 index 00000000000..06430d47cd0 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/singleEntry.kt.after @@ -0,0 +1,5 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String) { + UNIQUE("42") +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/wholeProject.kt b/idea/testData/quickfix/migration/enumConstructor/wholeProject.kt new file mode 100644 index 00000000000..f469abda2e6 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/wholeProject.kt @@ -0,0 +1,24 @@ +// "Change to short enum entry super constructor in the whole project" "true" + +enum class First(val colorCode: Int) { + RED: First(0xff0000), + GREEN: First(0x00ff00), BLUE: First(0x0000ff) +} + +enum class Second(val dirCode: Int) { + NORTH: Second(1) { + override fun dir(): String = "N" + }, + SOUTH: Second(2) { + override fun dir(): String = "S" + }, + WEST : Second(3) { + override fun dir(): String = "W" + }, + EAST: Second(4) { + override fun dir(): String = "E" + }; + + + abstract fun dir(): String +} diff --git a/idea/testData/quickfix/migration/enumConstructor/wholeProject.kt.after b/idea/testData/quickfix/migration/enumConstructor/wholeProject.kt.after new file mode 100644 index 00000000000..8366e0f3d0c --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/wholeProject.kt.after @@ -0,0 +1,24 @@ +// "Change to short enum entry super constructor in the whole project" "true" + +enum class First(val colorCode: Int) { + RED(0xff0000), + GREEN(0x00ff00), BLUE(0x0000ff) +} + +enum class Second(val dirCode: Int) { + NORTH(1) { + override fun dir(): String = "N" + }, + SOUTH(2) { + override fun dir(): String = "S" + }, + WEST(3) { + override fun dir(): String = "W" + }, + EAST(4) { + override fun dir(): String = "E" + }; + + + abstract fun dir(): String +} diff --git a/idea/testData/quickfix/migration/enumConstructor/withCommas.kt b/idea/testData/quickfix/migration/enumConstructor/withCommas.kt new file mode 100644 index 00000000000..a466e08dd30 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/withCommas.kt @@ -0,0 +1,9 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String = "xxx") { + FIRST(), + SECOND: SimpleEnum("42"), + LAST("13"); + + fun foo() = z +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/withCommas.kt.after b/idea/testData/quickfix/migration/enumConstructor/withCommas.kt.after new file mode 100644 index 00000000000..987bb1835ba --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/withCommas.kt.after @@ -0,0 +1,9 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String = "xxx") { + FIRST(), + SECOND("42"), + LAST("13"); + + fun foo() = z +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt b/idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt new file mode 100644 index 00000000000..9062c3cbb45 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt @@ -0,0 +1,9 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String = "xxx") { + FIRST(), + SECOND: SimpleEnum(z = "42"), + LAST("13"); + + fun foo() = z +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt.after b/idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt.after new file mode 100644 index 00000000000..56e8b8d06c5 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt.after @@ -0,0 +1,9 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String = "xxx") { + FIRST(), + SECOND(z = "42"), + LAST("13"); + + fun foo() = z +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/withOverloads.kt b/idea/testData/quickfix/migration/enumConstructor/withOverloads.kt new file mode 100644 index 00000000000..d42f249eb13 --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/withOverloads.kt @@ -0,0 +1,13 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String = "xxx") { + FIRST: SimpleEnum() { + override fun foo(): String = "abc" + }, + SECOND() { + override fun foo(): String = "xyz" + }, + LAST("13"); + + open fun foo(): String = z +} \ No newline at end of file diff --git a/idea/testData/quickfix/migration/enumConstructor/withOverloads.kt.after b/idea/testData/quickfix/migration/enumConstructor/withOverloads.kt.after new file mode 100644 index 00000000000..e4033e0b3ea --- /dev/null +++ b/idea/testData/quickfix/migration/enumConstructor/withOverloads.kt.after @@ -0,0 +1,13 @@ +// "Change to short enum entry super constructor" "true" + +enum class SimpleEnum(val z: String = "xxx") { + FIRST() { + override fun foo(): String = "abc" + }, + SECOND() { + override fun foo(): String = "xyz" + }, + LAST("13"); + + open fun foo(): String = z +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index fe07fd5d6d4..4d4157ea9fa 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3031,6 +3031,57 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/migration/enumConstructor") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class EnumConstructor extends AbstractQuickFixTest { + public void testAllFilesPresentInEnumConstructor() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/enumConstructor"), Pattern.compile("^(\\w+)\\.kt$"), true); + } + + @TestMetadata("noDelimiterWithInitializerFirst.kt") + public void testNoDelimiterWithInitializerFirst() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerFirst.kt"); + doTest(fileName); + } + + @TestMetadata("noDelimiterWithInitializerLast.kt") + public void testNoDelimiterWithInitializerLast() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/noDelimiterWithInitializerLast.kt"); + doTest(fileName); + } + + @TestMetadata("singleEntry.kt") + public void testSingleEntry() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/singleEntry.kt"); + doTest(fileName); + } + + @TestMetadata("wholeProject.kt") + public void testWholeProject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/wholeProject.kt"); + doTest(fileName); + } + + @TestMetadata("withCommas.kt") + public void testWithCommas() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/withCommas.kt"); + doTest(fileName); + } + + @TestMetadata("withNamedArgument.kt") + public void testWithNamedArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/withNamedArgument.kt"); + doTest(fileName); + } + + @TestMetadata("withOverloads.kt") + public void testWithOverloads() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/enumConstructor/withOverloads.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/migration/lambdaSyntax") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)