diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index c7fb48e9b3c..047fdd67103 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -1479,6 +1479,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.MergeElseIfIntention + Kotlin + + org.jetbrains.kotlin.idea.intentions.AddMissingDestructuringIntention Kotlin diff --git a/idea/resources/intentionDescriptions/MergeElseIfIntention/after.kt.template b/idea/resources/intentionDescriptions/MergeElseIfIntention/after.kt.template new file mode 100644 index 00000000000..963f2c33ed0 --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeElseIfIntention/after.kt.template @@ -0,0 +1,5 @@ +if (a) { + println("a") +} else if (b) { + println("not a and b") +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/MergeElseIfIntention/before.kt.template b/idea/resources/intentionDescriptions/MergeElseIfIntention/before.kt.template new file mode 100644 index 00000000000..52f7bc934ba --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeElseIfIntention/before.kt.template @@ -0,0 +1,7 @@ +if (a) { + println("a") +} else { + if (b) { + println("not a and b") + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/MergeElseIfIntention/description.html b/idea/resources/intentionDescriptions/MergeElseIfIntention/description.html new file mode 100644 index 00000000000..4b4c713b685 --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeElseIfIntention/description.html @@ -0,0 +1,5 @@ + + +This intention merges else and nested if statement without else branches into a single else if. + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/MergeElseIfIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/MergeElseIfIntention.kt new file mode 100644 index 00000000000..9bf1dd110d8 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/MergeElseIfIntention.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.intentions + +import com.intellij.openapi.editor.Editor +import org.jetbrains.kotlin.psi.* + + +class MergeElseIfIntention : SelfTargetingIntention(KtIfExpression::class.java, "Merge 'else if'") { + override fun isApplicableTo(element: KtIfExpression, caretOffset: Int): Boolean { + val elseBody = element.`else` ?: return false + val nestedIf = elseBody.nestedIf() ?: return false + return nestedIf.`else` == null + } + + override fun applyTo(element: KtIfExpression, editor: Editor?) { + val nestedIf = element.`else`?.nestedIf() ?: return + val condition = nestedIf.condition ?: return + val nestedBody = nestedIf.then ?: return + + val factory = KtPsiFactory(element) + element.`else`?.replace( + factory.createExpressionByPattern("if ($0) $1", condition, nestedBody) + ) + } + + companion object { + private fun KtExpression.nestedIf() = + if (this is KtBlockExpression) { + this.statements.singleOrNull() as? KtIfExpression + } else { + null + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/.intention b/idea/testData/intentions/mergeElseIf/.intention new file mode 100644 index 00000000000..02521a0360f --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.MergeElseIfIntention \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/comments.kt b/idea/testData/intentions/mergeElseIf/comments.kt new file mode 100644 index 00000000000..faa40a9ef27 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/comments.kt @@ -0,0 +1,11 @@ +fun foo() { + // comment 1 + if (true) { + + } else /* comment 2 */ { + if (true) { + // comment 4 + foo() + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/comments.kt.after b/idea/testData/intentions/mergeElseIf/comments.kt.after new file mode 100644 index 00000000000..34a5b6a7f29 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/comments.kt.after @@ -0,0 +1,9 @@ +fun foo() { + // comment 1 + if (true) { + + } else /* comment 2 */ if (true) { + // comment 4 + foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/else.kt b/idea/testData/intentions/mergeElseIf/else.kt new file mode 100644 index 00000000000..8d93114a58b --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/else.kt @@ -0,0 +1,13 @@ +// IS_APPLICABLE: false + +fun foo() { + if (true) { + + } else { + if (false) { + foo() + } else { + + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/expression.kt b/idea/testData/intentions/mergeElseIf/expression.kt new file mode 100644 index 00000000000..2f2f13a2517 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/expression.kt @@ -0,0 +1,7 @@ +fun foo() { + if (true) { + + } else { + if (false) foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/expression.kt.after b/idea/testData/intentions/mergeElseIf/expression.kt.after new file mode 100644 index 00000000000..d20c783c0f9 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/expression.kt.after @@ -0,0 +1,5 @@ +fun foo() { + if (true) { + + } else if (false) foo() +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/ifNotSingle.kt b/idea/testData/intentions/mergeElseIf/ifNotSingle.kt new file mode 100644 index 00000000000..1952b3fe6a0 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/ifNotSingle.kt @@ -0,0 +1,12 @@ +// IS_APPLICABLE: false + +fun foo() { + if (true) { + + } else { + if (false) { + foo() + } + val a = 5 + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/simple.kt b/idea/testData/intentions/mergeElseIf/simple.kt new file mode 100644 index 00000000000..8f189a25a63 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/simple.kt @@ -0,0 +1,9 @@ +fun foo() { + if (true) { + + } else { + if (false) { + foo() + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeElseIf/simple.kt.after b/idea/testData/intentions/mergeElseIf/simple.kt.after new file mode 100644 index 00000000000..8cf68c3ea38 --- /dev/null +++ b/idea/testData/intentions/mergeElseIf/simple.kt.after @@ -0,0 +1,7 @@ +fun foo() { + if (true) { + + } else if (false) { + foo() + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 4e929fdef61..ad78f2d63bb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -11722,6 +11722,44 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/mergeElseIf") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MergeElseIf extends AbstractIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInMergeElseIf() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/mergeElseIf"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("comments.kt") + public void testComments() throws Exception { + runTest("idea/testData/intentions/mergeElseIf/comments.kt"); + } + + @TestMetadata("else.kt") + public void testElse() throws Exception { + runTest("idea/testData/intentions/mergeElseIf/else.kt"); + } + + @TestMetadata("expression.kt") + public void testExpression() throws Exception { + runTest("idea/testData/intentions/mergeElseIf/expression.kt"); + } + + @TestMetadata("ifNotSingle.kt") + public void testIfNotSingle() throws Exception { + runTest("idea/testData/intentions/mergeElseIf/ifNotSingle.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/intentions/mergeElseIf/simple.kt"); + } + } + @TestMetadata("idea/testData/intentions/mergeIfs") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)