From 9f5ee13c20ec56dde0e0f4a3e1c533456df65385 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 18 Nov 2013 18:45:13 +0400 Subject: [PATCH] Implement "Merge when" intention --- .../jet/lang/psi/psiUtil/jetPsiUtil.kt | 20 ++++ .../jet/generators/tests/GenerateTests.java | 1 + .../MergeWhenIntention/after.kt.template | 14 +++ .../MergeWhenIntention/before.kt.template | 11 +++ .../MergeWhenIntention/description.html | 5 + idea/src/META-INF/plugin.xml | 5 + .../jetbrains/jet/plugin/JetBundle.properties | 2 + .../branchedTransformationUtils.kt | 73 +++++++++++++- .../intentions/MergeWhenIntention.kt | 30 ++++++ .../jet/plugin/util/JetPsiMatcher.java | 19 ++++ .../when/merge/mergeBlockWithBlock.kt | 33 +++++++ .../when/merge/mergeBlockWithBlock.kt.after | 24 +++++ .../when/merge/mergeBlockWithSingle.kt | 24 +++++ .../when/merge/mergeBlockWithSingle.kt.after | 21 ++++ .../merge/mergeWithConflictingDeclarations.kt | 37 +++++++ .../when/merge/mergeWithDeclarations.kt | 36 +++++++ .../when/merge/mergeWithDeclarations.kt.after | 27 ++++++ .../when/merge/mergeWithReturnAfter.kt | 18 ++++ .../when/merge/mergeWithReturnAfter.kt.after | 19 ++++ .../when/merge/mergeWithReturnBefore.kt | 19 ++++ .../branched/when/merge/mergeWithSubject.kt | 15 +++ .../when/merge/mergeWithSubject.kt.after | 18 ++++ .../merge/mergeWithUnmatchedConditions1.kt | 15 +++ .../merge/mergeWithUnmatchedConditions2.kt | 17 ++++ .../merge/mergeWithUnmatchedConditions3.kt | 16 ++++ .../merge/mergeWithUnmatchedConditions4.kt | 15 +++ .../merge/mergeWithUnmatchedConditions5.kt | 17 ++++ .../merge/mergeWithUnmatchedConditions6.kt | 16 ++++ .../merge/mergeWithUnmatchedConditions7.kt | 16 ++++ .../when/merge/mergeWithUnmatchedSubjects1.kt | 16 ++++ .../when/merge/mergeWithUnmatchedSubjects2.kt | 16 ++++ .../when/merge/mergeWithoutSubject.kt | 15 +++ .../when/merge/mergeWithoutSubject.kt.after | 18 ++++ .../AbstractCodeTransformationTest.java | 4 + .../CodeTransformationsTestGenerated.java | 96 ++++++++++++++++++- 35 files changed, 742 insertions(+), 6 deletions(-) create mode 100644 idea/resources/intentionDescriptions/MergeWhenIntention/after.kt.template create mode 100644 idea/resources/intentionDescriptions/MergeWhenIntention/before.kt.template create mode 100644 idea/resources/intentionDescriptions/MergeWhenIntention/description.html create mode 100644 idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/MergeWhenIntention.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt.after create mode 100644 idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt.after create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithConflictingDeclarations.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt.after create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt.after create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithReturnBefore.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithSubject.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithSubject.kt.after create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions1.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions2.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions3.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions4.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions5.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions6.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions7.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects1.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects2.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt create mode 100644 idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt.after diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt index f171d718d96..9b5621b9deb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/psiUtil/jetPsiUtil.kt @@ -23,6 +23,10 @@ import org.jetbrains.jet.lang.psi.JetDeclaration import org.jetbrains.jet.lang.psi.JetClass import org.jetbrains.jet.lang.psi.JetClassOrObject import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.lang.psi.JetElement +import org.jetbrains.jet.lang.psi.JetBlockExpression +import org.jetbrains.jet.lang.psi.JetPsiUtil +import org.jetbrains.jet.lang.psi.JetPsiFactory fun PsiElement.getParentByTypeAndPredicate( parentClass : Class, strict : Boolean = false, predicate: (T) -> Boolean @@ -72,3 +76,19 @@ fun JetClass.isAbstract() = isTrait() || hasModifier(JetTokens.ABSTRACT_KEYWORD) [suppress("UNCHECKED_CAST")] fun PsiElement.replaced(newElement: T): T = replace(newElement)!! as T + +fun JetElement.blockExpressionsOrSingle(): Iterator = + if (this is JetBlockExpression) getStatements().iterator() else SingleIterator(this) + +fun JetElement.outermostLastBlockElement(predicate: (JetElement) -> Boolean = { true }): JetElement? { + return JetPsiUtil.getOutermostLastBlockElement(this) { e -> e != null && predicate(e) } +} + +fun JetBlockExpression.appendElement(element: JetElement): JetElement = + addAfter(element, getRBrace()!!.getPrevSibling()!!)!! as JetElement + +fun JetElement.wrapInBlock(): JetBlockExpression { + val block = JetPsiFactory.createEmptyBody(getProject()) as JetBlockExpression + block.appendElement(this) + return block +} \ No newline at end of file diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java index 49269fd68e7..b9094f25f9f 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.java @@ -387,6 +387,7 @@ public class GenerateTests { testModel("idea/testData/intentions/branched/ifWhen/ifToWhen", "doTestIfToWhen"), testModel("idea/testData/intentions/branched/ifWhen/whenToIf", "doTestWhenToIf"), testModel("idea/testData/intentions/branched/when/flatten", "doTestFlattenWhen"), + testModel("idea/testData/intentions/branched/when/merge", "doTestMergeWhen"), testModel("idea/testData/intentions/branched/when/introduceSubject", "doTestIntroduceWhenSubject"), testModel("idea/testData/intentions/branched/when/eliminateSubject", "doTestEliminateWhenSubject"), testModel("idea/testData/intentions/declarations/split", "doTestSplitProperty"), diff --git a/idea/resources/intentionDescriptions/MergeWhenIntention/after.kt.template b/idea/resources/intentionDescriptions/MergeWhenIntention/after.kt.template new file mode 100644 index 00000000000..76595697fb0 --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeWhenIntention/after.kt.template @@ -0,0 +1,14 @@ +when (n) { + 1 -> { + res = "one" + println("A") + } + 2 -> { + res = "two" + println("B") + } + else -> { + res = "unknown" + println("C") + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/MergeWhenIntention/before.kt.template b/idea/resources/intentionDescriptions/MergeWhenIntention/before.kt.template new file mode 100644 index 00000000000..826bdd878ba --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeWhenIntention/before.kt.template @@ -0,0 +1,11 @@ +when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" +} + +when (n) { + 1 -> println("A") + 2 -> println("B") + else -> println("C") +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/MergeWhenIntention/description.html b/idea/resources/intentionDescriptions/MergeWhenIntention/description.html new file mode 100644 index 00000000000..d0286ec14c7 --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeWhenIntention/description.html @@ -0,0 +1,5 @@ + + +This intention merges two successive 'when' expressions with equivalent branches into the single one + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 7dcd637e835..d6624290458 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -444,6 +444,11 @@ Kotlin + + org.jetbrains.jet.plugin.intentions.branchedTransformations.intentions.MergeWhenIntention + Kotlin + + org.jetbrains.jet.plugin.intentions.RemoveUnnecessaryParenthesesIntention Kotlin diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index 4f48da60aad..1656029b3ec 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -195,6 +195,8 @@ when.to.if=Replace 'when' with 'if' when.to.if.family=Replace 'when' with 'if' flatten.when=Flatten 'when' expression flatten.when.family=Flatten 'when' Expression +merge.when=Merge 'when' expressions +merge.when.family=Merge 'when' Expression introduce.when.subject=Introduce argument to 'when' introduce.when.subject.family=Introduce Argument to 'when' eliminate.when.subject=Eliminate argument of 'when' diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/branchedTransformationUtils.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/branchedTransformationUtils.kt index f618e6c5f45..5d1452b1d8b 100644 --- a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/branchedTransformationUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/branchedTransformationUtils.kt @@ -23,6 +23,10 @@ import org.jetbrains.jet.plugin.util.JetPsiMatcher import org.jetbrains.jet.lang.psi.JetPsiUnparsingUtils.* import org.jetbrains.jet.lang.psi.psiUtil.* import java.util.ArrayList +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.PsiWhiteSpace +import java.util.Collections +import com.intellij.util.containers.ContainerUtil public val TRANSFORM_WITHOUT_CHECK: String = "Expression must be checked before applying transformation" @@ -129,11 +133,11 @@ public fun JetWhenExpression.canEliminateSubject(): Boolean { public fun JetWhenExpression.flatten(): JetWhenExpression { val subjectExpression = getSubjectExpression() val elseBranch = getElseExpression() - + assert(elseBranch is JetWhenExpression, TRANSFORM_WITHOUT_CHECK) - + val nestedWhenExpression = (elseBranch as JetWhenExpression) - + val outerEntries = getEntries() val innerEntries = nestedWhenExpression.getEntries() val builder = JetPsiFactory.WhenBuilder(subjectExpression) @@ -152,7 +156,7 @@ public fun JetWhenExpression.flatten(): JetWhenExpression { public fun JetWhenExpression.introduceSubject(): JetWhenExpression { val subject = getSubjectCandidate()!! - + val builder = JetPsiFactory.WhenBuilder(subject) for (entry in getEntries()) { val branchExpression = entry.getExpression() @@ -163,7 +167,7 @@ public fun JetWhenExpression.introduceSubject(): JetWhenExpression { for (condition in entry.getConditions()) { assert(condition is JetWhenConditionWithExpression, TRANSFORM_WITHOUT_CHECK) - + val conditionExpression = ((condition as JetWhenConditionWithExpression)).getExpression() when (conditionExpression) { is JetIsExpression -> { @@ -316,3 +320,62 @@ public fun JetWhenExpression.transformToIf() { replace(builder.toExpression(getProject())) } + +public fun JetWhenExpression.canMergeWithNext(): Boolean { + fun checkConditions(e1: JetWhenEntry, e2: JetWhenEntry): Boolean { + if (e1.isElse() != e2.isElse()) return false + + val conditions1 = e1.getConditions() + val conditions2 = e2.getConditions() + return conditions1.size == conditions2.size && + (conditions1.iterator() zip conditions2.iterator()).all { pair -> JetPsiMatcher.checkElementMatch(pair.first, pair.second)} + } + + fun JetWhenEntry.declarationNames(): Set = + getExpression()?.blockExpressionsOrSingle() + ?.filterIsInstance(javaClass()) + ?.map { decl -> decl.getName() } + ?.filterNotNull()?.toHashSet() ?: Collections.emptySet() + + fun checkBodies(e1: JetWhenEntry, e2: JetWhenEntry): Boolean { + if (ContainerUtil.intersects(e1.declarationNames(), e2.declarationNames())) return false + + return when (e1.getExpression()?.outermostLastBlockElement()) { + is JetReturnExpression, is JetThrowExpression, is JetBreakExpression, is JetContinueExpression -> false + else -> true + } + } + + val sibling = PsiTreeUtil.skipSiblingsForward(this, javaClass()) + + if (sibling !is JetWhenExpression) return false + if (!JetPsiMatcher.checkElementMatch(getSubjectExpression(), sibling.getSubjectExpression())) return false + + val entries1 = getEntries() + val entries2 = sibling.getEntries() + return entries1.size == entries2.size && (entries1.iterator() zip entries2.iterator()).all { pair -> + checkConditions(pair.first, pair.second) && checkBodies(pair.first, pair.second) + } +} + +public fun JetWhenExpression.mergeWithNext() { + fun JetExpression?.mergeWith(that: JetExpression?): JetExpression? = when { + this == null -> that + that == null -> this + else -> { + val block = if (this is JetBlockExpression) this else replaced(wrapInBlock()) + for (element in that.blockExpressionsOrSingle()) { + val expression = block.appendElement(element) + block.addBefore(JetPsiFactory.createNewLine(getProject()), expression) + } + block + } + } + + val sibling = PsiTreeUtil.skipSiblingsForward(this, javaClass()) as JetWhenExpression + for ((entry1, entry2) in getEntries().iterator() zip sibling.getEntries().iterator()) { + entry1.getExpression() mergeWith entry2.getExpression() + } + + getParent()?.deleteChildRange(getNextSibling(), sibling) +} diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/MergeWhenIntention.kt b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/MergeWhenIntention.kt new file mode 100644 index 00000000000..cbd6979e8f4 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/intentions/branchedTransformations/intentions/MergeWhenIntention.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2013 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.jet.plugin.intentions.branchedTransformations.intentions + +import org.jetbrains.jet.plugin.intentions.JetSelfTargetingIntention +import org.jetbrains.jet.plugin.intentions.branchedTransformations.* +import org.jetbrains.jet.lang.psi.JetWhenExpression +import com.intellij.openapi.editor.Editor + +public class MergeWhenIntention : JetSelfTargetingIntention("merge.when", javaClass()) { + override fun isApplicableTo(element: JetWhenExpression): Boolean = element.canMergeWithNext() + + override fun applyTo(element: JetWhenExpression, editor: Editor) { + element.mergeWithNext() + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/util/JetPsiMatcher.java b/idea/src/org/jetbrains/jet/plugin/util/JetPsiMatcher.java index 41e7d80ac98..c859a1db641 100644 --- a/idea/src/org/jetbrains/jet/plugin/util/JetPsiMatcher.java +++ b/idea/src/org/jetbrains/jet/plugin/util/JetPsiMatcher.java @@ -235,6 +235,25 @@ public class JetPsiMatcher { public Boolean visitNullableType(@NotNull JetNullableType nullableType, JetElement data) { return checkElementMatch(nullableType.getInnerType(), ((JetNullableType) data).getInnerType()); } + + @Override + public Boolean visitWhenConditionExpression(@NotNull JetWhenConditionWithExpression condition, JetElement data) { + return checkElementMatch(condition.getExpression(), ((JetWhenConditionWithExpression) data).getExpression()); + } + + @Override + public Boolean visitWhenConditionInRange(@NotNull JetWhenConditionInRange condition, JetElement data) { + JetWhenConditionInRange other = (JetWhenConditionInRange) data; + return condition.isNegated() == other.isNegated() && + checkElementMatch(condition.getRangeExpression(), other.getRangeExpression()); + } + + @Override + public Boolean visitWhenConditionIsPattern(@NotNull JetWhenConditionIsPattern condition, JetElement data) { + JetWhenConditionIsPattern other = (JetWhenConditionIsPattern) data; + return condition.isNegated() == other.isNegated() && + checkElementMatch(condition.getTypeRef(), other.getTypeRef()); + } }; private static JetElement unwrap(JetElement e) { diff --git a/idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt b/idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt new file mode 100644 index 00000000000..3d0fb62df72 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt @@ -0,0 +1,33 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + println("A") + } + 2 -> { + res = "two" + println("B") + } + else -> { + res = "unknown" + println("C") + } + } + + when (n) { + 1 -> { + println("A") + println("AA") + } + 2 -> { + println("B") + println("BB") + } + else -> { + println("C") + println("CC") + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt.after b/idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt.after new file mode 100644 index 00000000000..556689e3ec9 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt.after @@ -0,0 +1,24 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + println("A") + println("A") + println("AA") + } + 2 -> { + res = "two" + println("B") + println("B") + println("BB") + } + else -> { + res = "unknown" + println("C") + println("C") + println("CC") + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt b/idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt new file mode 100644 index 00000000000..1b1441e5f47 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt @@ -0,0 +1,24 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + println("A") + } + 2 -> { + res = "two" + println("B") + } + else -> { + res = "unknown" + println("C") + } + } + + when (n) { + 1 -> println("AA") + 2 -> println("BB") + else -> println("CC") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt.after b/idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt.after new file mode 100644 index 00000000000..fb1151646af --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt.after @@ -0,0 +1,21 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + println("A") + println("AA") + } + 2 -> { + res = "two" + println("B") + println("BB") + } + else -> { + res = "unknown" + println("C") + println("CC") + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithConflictingDeclarations.kt b/idea/testData/intentions/branched/when/merge/mergeWithConflictingDeclarations.kt new file mode 100644 index 00000000000..a77ed71f010 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithConflictingDeclarations.kt @@ -0,0 +1,37 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + val x = "A" + println(x) + } + 2 -> { + res = "two" + val x = "B" + println(x) + } + else -> { + res = "unknown" + val x = "C" + println(x) + } + } + + when (n) { + 1 -> { + val x = "AA" + println(x) + } + 2 -> { + val x = "BB" + println(x) + } + else -> { + val x = "CC" + println(x) + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt b/idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt new file mode 100644 index 00000000000..45c7289c3a7 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt @@ -0,0 +1,36 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + val x = "A" + println(x) + } + 2 -> { + res = "two" + val x = "B" + println(x) + } + else -> { + res = "unknown" + val x = "C" + println(x) + } + } + + when (n) { + 1 -> { + val y = "AA" + println(y) + } + 2 -> { + val y = "BB" + println(y) + } + else -> { + val y = "CC" + println(y) + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt.after b/idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt.after new file mode 100644 index 00000000000..493f68f5df4 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt.after @@ -0,0 +1,27 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + val x = "A" + println(x) + val y = "AA" + println(y) + } + 2 -> { + res = "two" + val x = "B" + println(x) + val y = "BB" + println(y) + } + else -> { + res = "unknown" + val x = "C" + println(x) + val y = "CC" + println(y) + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt b/idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt new file mode 100644 index 00000000000..9096c170fc9 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt @@ -0,0 +1,18 @@ +fun test(n: Int) { + var res: String = "" + + when (n) { + 1 -> println("A") + 2 -> println("B") + else -> println("C") + } + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> { + res = "unknown" + return + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt.after b/idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt.after new file mode 100644 index 00000000000..54dd4bf46f4 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt.after @@ -0,0 +1,19 @@ +fun test(n: Int) { + var res: String = "" + + when (n) { + 1 -> { + println("A") + res = "one" + } + 2 -> { + println("B") + res = "two" + } + else -> { + println("C") + res = "unknown" + return + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithReturnBefore.kt b/idea/testData/intentions/branched/when/merge/mergeWithReturnBefore.kt new file mode 100644 index 00000000000..56959a635c6 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithReturnBefore.kt @@ -0,0 +1,19 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + var res: String = "" + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> { + res = "unknown" + return + } + } + + when (n) { + 1 -> println("A") + 2 -> println("B") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithSubject.kt b/idea/testData/intentions/branched/when/merge/mergeWithSubject.kt new file mode 100644 index 00000000000..1b106e5650c --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithSubject.kt @@ -0,0 +1,15 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" + } + + when (n) { + 1 -> println("A") + 2 -> println("B") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithSubject.kt.after b/idea/testData/intentions/branched/when/merge/mergeWithSubject.kt.after new file mode 100644 index 00000000000..324f04e98bf --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithSubject.kt.after @@ -0,0 +1,18 @@ +fun test(n: Int) { + val res: String + + when (n) { + 1 -> { + res = "one" + println("A") + } + 2 -> { + res = "two" + println("B") + } + else -> { + res = "unknown" + println("C") + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions1.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions1.kt new file mode 100644 index 00000000000..a6f308f70d6 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions1.kt @@ -0,0 +1,15 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" + } + + when (n) { + 1 -> println("A") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions2.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions2.kt new file mode 100644 index 00000000000..e1428893c8d --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions2.kt @@ -0,0 +1,17 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" + } + + when (n) { + 1 -> println("A") + 2 -> println("B") + 3 -> println("D") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions3.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions3.kt new file mode 100644 index 00000000000..40621363476 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions3.kt @@ -0,0 +1,16 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" + } + + when (n) { + 2 -> println("B") + 1 -> println("A") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions4.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions4.kt new file mode 100644 index 00000000000..075e5231db8 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions4.kt @@ -0,0 +1,15 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when { + n == 1 -> res = "one" + n == 2 -> res = "two" + else -> res = "unknown" + } + + when { + n == 1 -> println("A") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions5.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions5.kt new file mode 100644 index 00000000000..820b106bd29 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions5.kt @@ -0,0 +1,17 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when { + n == 1 -> res = "one" + n == 2 -> res = "two" + else -> res = "unknown" + } + + when { + n == 1 -> println("A") + n == 2 -> println("B") + n == 3 -> println("D") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions6.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions6.kt new file mode 100644 index 00000000000..23f33e2d45f --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions6.kt @@ -0,0 +1,16 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when { + n == 1 -> res = "one" + n == 2 -> res = "two" + else -> res = "unknown" + } + + when { + n == 2 -> println("B") + n == 1 -> println("A") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions7.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions7.kt new file mode 100644 index 00000000000..38a2b861d59 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions7.kt @@ -0,0 +1,16 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when { + n == 1 -> res = "one" + n == 2 -> res = "two" + else -> res = "unknown" + } + + when { + n + 1 == 2 -> println("B") + n + 1 == 3 -> println("A") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects1.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects1.kt new file mode 100644 index 00000000000..872141c0db3 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects1.kt @@ -0,0 +1,16 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" + } + + when { + n == 1 -> println("A") + n == 2 -> println("B") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects2.kt b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects2.kt new file mode 100644 index 00000000000..ff4e5a08df5 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects2.kt @@ -0,0 +1,16 @@ +// IS_APPLICABLE: false +fun test(n: Int) { + val res: String + + when (n) { + 1 -> res = "one" + 2 -> res = "two" + else -> res = "unknown" + } + + when (n + 1) { + 1 -> println("A") + 2 -> println("B") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt b/idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt new file mode 100644 index 00000000000..3152c239c05 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt @@ -0,0 +1,15 @@ +fun test(n: Int) { + val res: String + + when { + n == 1 -> res = "one" + n == 2 -> res = "two" + else -> res = "unknown" + } + + when { + n == 1 -> println("A") + n == 2 -> println("B") + else -> println("C") + } +} \ No newline at end of file diff --git a/idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt.after b/idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt.after new file mode 100644 index 00000000000..6eb01385b81 --- /dev/null +++ b/idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt.after @@ -0,0 +1,18 @@ +fun test(n: Int) { + val res: String + + when { + n == 1 -> { + res = "one" + println("A") + } + n == 2 -> { + res = "two" + println("B") + } + else -> { + res = "unknown" + println("C") + } + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java index 71997f24fe3..50a2ad7bd5e 100644 --- a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java @@ -86,6 +86,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes doTestIntention(path, new FlattenWhenIntention()); } + public void doTestMergeWhen(@NotNull String path) throws Exception { + doTestIntention(path, new MergeWhenIntention()); + } + public void doTestIntroduceWhenSubject(@NotNull String path) throws Exception { doTestIntention(path, new IntroduceWhenSubjectIntention()); } diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java index d0a0fef1155..d51c7978391 100644 --- a/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java @@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.intentions.AbstractCodeTransformationTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@InnerTestClasses({CodeTransformationsTestGenerated.IfToAssignment.class, CodeTransformationsTestGenerated.IfToReturn.class, CodeTransformationsTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationsTestGenerated.WhenToAssignment.class, CodeTransformationsTestGenerated.WhenToReturn.class, CodeTransformationsTestGenerated.AssignmentToIf.class, CodeTransformationsTestGenerated.AssignmentToWhen.class, CodeTransformationsTestGenerated.PropertyToIf.class, CodeTransformationsTestGenerated.PropertyToWhen.class, CodeTransformationsTestGenerated.ReturnToIf.class, CodeTransformationsTestGenerated.ReturnToWhen.class, CodeTransformationsTestGenerated.IfToWhen.class, CodeTransformationsTestGenerated.WhenToIf.class, CodeTransformationsTestGenerated.Flatten.class, CodeTransformationsTestGenerated.IntroduceSubject.class, CodeTransformationsTestGenerated.EliminateSubject.class, CodeTransformationsTestGenerated.Split.class, CodeTransformationsTestGenerated.Join.class, CodeTransformationsTestGenerated.ConvertMemberToExtension.class, CodeTransformationsTestGenerated.ReconstructedType.class, CodeTransformationsTestGenerated.RemoveUnnecessaryParentheses.class}) +@InnerTestClasses({CodeTransformationsTestGenerated.IfToAssignment.class, CodeTransformationsTestGenerated.IfToReturn.class, CodeTransformationsTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationsTestGenerated.WhenToAssignment.class, CodeTransformationsTestGenerated.WhenToReturn.class, CodeTransformationsTestGenerated.AssignmentToIf.class, CodeTransformationsTestGenerated.AssignmentToWhen.class, CodeTransformationsTestGenerated.PropertyToIf.class, CodeTransformationsTestGenerated.PropertyToWhen.class, CodeTransformationsTestGenerated.ReturnToIf.class, CodeTransformationsTestGenerated.ReturnToWhen.class, CodeTransformationsTestGenerated.IfToWhen.class, CodeTransformationsTestGenerated.WhenToIf.class, CodeTransformationsTestGenerated.Flatten.class, CodeTransformationsTestGenerated.Merge.class, CodeTransformationsTestGenerated.IntroduceSubject.class, CodeTransformationsTestGenerated.EliminateSubject.class, CodeTransformationsTestGenerated.Split.class, CodeTransformationsTestGenerated.Join.class, CodeTransformationsTestGenerated.ConvertMemberToExtension.class, CodeTransformationsTestGenerated.ReconstructedType.class, CodeTransformationsTestGenerated.RemoveUnnecessaryParentheses.class}) public class CodeTransformationsTestGenerated extends AbstractCodeTransformationTest { @TestMetadata("idea/testData/intentions/branched/folding/ifToAssignment") public static class IfToAssignment extends AbstractCodeTransformationTest { @@ -544,6 +544,99 @@ public class CodeTransformationsTestGenerated extends AbstractCodeTransformation } + @TestMetadata("idea/testData/intentions/branched/when/merge") + public static class Merge extends AbstractCodeTransformationTest { + public void testAllFilesPresentInMerge() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/intentions/branched/when/merge"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("mergeBlockWithBlock.kt") + public void testMergeBlockWithBlock() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeBlockWithBlock.kt"); + } + + @TestMetadata("mergeBlockWithSingle.kt") + public void testMergeBlockWithSingle() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeBlockWithSingle.kt"); + } + + @TestMetadata("mergeWithConflictingDeclarations.kt") + public void testMergeWithConflictingDeclarations() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithConflictingDeclarations.kt"); + } + + @TestMetadata("mergeWithDeclarations.kt") + public void testMergeWithDeclarations() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithDeclarations.kt"); + } + + @TestMetadata("mergeWithReturnAfter.kt") + public void testMergeWithReturnAfter() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithReturnAfter.kt"); + } + + @TestMetadata("mergeWithReturnBefore.kt") + public void testMergeWithReturnBefore() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithReturnBefore.kt"); + } + + @TestMetadata("mergeWithSubject.kt") + public void testMergeWithSubject() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithSubject.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions1.kt") + public void testMergeWithUnmatchedConditions1() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions1.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions2.kt") + public void testMergeWithUnmatchedConditions2() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions2.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions3.kt") + public void testMergeWithUnmatchedConditions3() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions3.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions4.kt") + public void testMergeWithUnmatchedConditions4() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions4.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions5.kt") + public void testMergeWithUnmatchedConditions5() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions5.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions6.kt") + public void testMergeWithUnmatchedConditions6() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions6.kt"); + } + + @TestMetadata("mergeWithUnmatchedConditions7.kt") + public void testMergeWithUnmatchedConditions7() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedConditions7.kt"); + } + + @TestMetadata("mergeWithUnmatchedSubjects1.kt") + public void testMergeWithUnmatchedSubjects1() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects1.kt"); + } + + @TestMetadata("mergeWithUnmatchedSubjects2.kt") + public void testMergeWithUnmatchedSubjects2() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithUnmatchedSubjects2.kt"); + } + + @TestMetadata("mergeWithoutSubject.kt") + public void testMergeWithoutSubject() throws Exception { + doTestMergeWhen("idea/testData/intentions/branched/when/merge/mergeWithoutSubject.kt"); + } + + } + @TestMetadata("idea/testData/intentions/branched/when/introduceSubject") public static class IntroduceSubject extends AbstractCodeTransformationTest { public void testAllFilesPresentInIntroduceSubject() throws Exception { @@ -1101,6 +1194,7 @@ public class CodeTransformationsTestGenerated extends AbstractCodeTransformation suite.addTestSuite(IfToWhen.class); suite.addTestSuite(WhenToIf.class); suite.addTestSuite(Flatten.class); + suite.addTestSuite(Merge.class); suite.addTestSuite(IntroduceSubject.class); suite.addTestSuite(EliminateSubject.class); suite.addTestSuite(Split.class);