diff --git a/idea/resources/intentionDescriptions/MergeIfsIntention/after.kt.template b/idea/resources/intentionDescriptions/MergeIfsIntention/after.kt.template new file mode 100644 index 00000000000..39a4a8cd01d --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeIfsIntention/after.kt.template @@ -0,0 +1,3 @@ +if (a && b) { + println("a and b") +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/MergeIfsIntention/before.kt.template b/idea/resources/intentionDescriptions/MergeIfsIntention/before.kt.template new file mode 100644 index 00000000000..5f676d9cb4a --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeIfsIntention/before.kt.template @@ -0,0 +1,5 @@ +if (a) { + if (b) { + println("a and b") + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/MergeIfsIntention/description.html b/idea/resources/intentionDescriptions/MergeIfsIntention/description.html new file mode 100644 index 00000000000..2ad1232c69c --- /dev/null +++ b/idea/resources/intentionDescriptions/MergeIfsIntention/description.html @@ -0,0 +1,5 @@ + + +This intention merges two nested 'if's without 'else' branches into a 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 f9579e44fd5..ea107f62ece 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1502,6 +1502,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.MergeIfsIntention + Kotlin + + (KtIfExpression::class.java, "Merge 'if's") { + + override fun isApplicableTo(element: KtIfExpression, caretOffset: Int): Boolean { + if (element.`else` != null) return false + val then = element.then ?: return false + + val nestedIf = then.nestedIf() ?: return false + if (nestedIf.`else` != null) return false + + return true + } + + override fun applyTo(element: KtIfExpression, editor: Editor?) { + applyTo(element) + } + + companion object { + fun applyTo(element: KtIfExpression): Int { + val nestedIf = element.then?.nestedIf() ?: return -1 + val condition = element.condition ?: return -1 + val secondCondition = nestedIf.condition ?: return -1 + val nestedBody = nestedIf.then ?: return -1 + + val factory = KtPsiFactory(element) + + condition.replace(factory.createExpressionByPattern("$0 && $1", condition, secondCondition)) + val newBody = element.then!!.replace(nestedBody) + + return newBody.textRange!!.startOffset + } + + private fun KtExpression.nestedIf() = when (this) { + is KtBlockExpression -> this.statements.singleOrNull() as? KtIfExpression + is KtIfExpression -> this + else -> null + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/joinLines/JoinBlockIntoSingleStatementHandler.kt b/idea/src/org/jetbrains/kotlin/idea/joinLines/JoinBlockIntoSingleStatementHandler.kt index f53fecad418..b0eda87fbd2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/joinLines/JoinBlockIntoSingleStatementHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/joinLines/JoinBlockIntoSingleStatementHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 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. @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.joinLines import com.intellij.codeInsight.editorActions.JoinRawLinesHandlerDelegate import com.intellij.openapi.editor.Document import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.intentions.MergeIfsIntention import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -45,15 +46,7 @@ class JoinBlockIntoSingleStatementHandler : JoinRawLinesHandlerDelegate { // if outer if has else-branch and inner does not have it, do not remove braces otherwise else-branch will belong to different if! if (pparent.`else` != null) return -1 - val condition1 = pparent.condition - val condition2 = statement.condition - val body = statement.then - if (condition1 != null && condition2 != null && body != null) { - val newCondition = KtPsiFactory(pparent).createExpressionByPattern("$0 && $1", condition1, condition2) - condition1.replace(newCondition) - val newBody = block.replace(body) - return newBody.textRange!!.startOffset - } + return MergeIfsIntention.applyTo(pparent) } val newStatement = block.replace(statement) diff --git a/idea/testData/intentions/mergeIfs/.intention b/idea/testData/intentions/mergeIfs/.intention new file mode 100644 index 00000000000..afd0e52ad24 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.MergeIfsIntention \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/comments.kt b/idea/testData/intentions/mergeIfs/comments.kt new file mode 100644 index 00000000000..17c50d4adc1 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/comments.kt @@ -0,0 +1,9 @@ +fun foo() { + // comment 1 + if (/* comment 2 */ true /* comment 3 */) { + if (false) { + // comment 4 + foo() + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/comments.kt.after b/idea/testData/intentions/mergeIfs/comments.kt.after new file mode 100644 index 00000000000..ad30a82ba14 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/comments.kt.after @@ -0,0 +1,7 @@ +fun foo() { + // comment 1 + if (/* comment 2 */ true && false /* comment 3 */) { + // comment 4 + foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/else1.kt b/idea/testData/intentions/mergeIfs/else1.kt new file mode 100644 index 00000000000..9a17430a835 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/else1.kt @@ -0,0 +1,10 @@ +// IS_APPLICABLE: false + +fun foo() { + if (true) { + if (false) { + foo() + } + } else { + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/else2.kt b/idea/testData/intentions/mergeIfs/else2.kt new file mode 100644 index 00000000000..3401aa33bda --- /dev/null +++ b/idea/testData/intentions/mergeIfs/else2.kt @@ -0,0 +1,11 @@ +// IS_APPLICABLE: false + +fun foo() { + if (true) { + if (false) { + foo() + } else { + + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/expression.kt b/idea/testData/intentions/mergeIfs/expression.kt new file mode 100644 index 00000000000..2dc0335d523 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/expression.kt @@ -0,0 +1,5 @@ +fun foo() { + if (true) if (false) { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/expression.kt.after b/idea/testData/intentions/mergeIfs/expression.kt.after new file mode 100644 index 00000000000..96ba55fd1d4 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/expression.kt.after @@ -0,0 +1,5 @@ +fun foo() { + if (true && false) { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/simple.kt b/idea/testData/intentions/mergeIfs/simple.kt new file mode 100644 index 00000000000..e77cd753b93 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/simple.kt @@ -0,0 +1,7 @@ +fun foo() { + if (true) { + if (false) { + foo() + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/mergeIfs/simple.kt.after b/idea/testData/intentions/mergeIfs/simple.kt.after new file mode 100644 index 00000000000..96ba55fd1d4 --- /dev/null +++ b/idea/testData/intentions/mergeIfs/simple.kt.after @@ -0,0 +1,5 @@ +fun foo() { + if (true && 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 045af0251fc..cc75996ecae 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -10507,6 +10507,45 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/mergeIfs") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MergeIfs extends AbstractIntentionTest { + public void testAllFilesPresentInMergeIfs() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/mergeIfs"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("comments.kt") + public void testComments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/comments.kt"); + doTest(fileName); + } + + @TestMetadata("else1.kt") + public void testElse1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/else1.kt"); + doTest(fileName); + } + + @TestMetadata("else2.kt") + public void testElse2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/else2.kt"); + doTest(fileName); + } + + @TestMetadata("expression.kt") + public void testExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/expression.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/moveLambdaInsideParentheses") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)