Skip to content

Commit 956094e

Browse files
cypressiousyole
authored andcommitted
Add Merge ifs intention (JetBrains#975)
Fixes #KT-9912
1 parent 456037a commit 956094e

File tree

16 files changed

+179
-10
lines changed

16 files changed

+179
-10
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
if (a && b) {
2+
println("a and b")
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
if (a) {
2+
if (b) {
3+
println("a and b")
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<html>
2+
<body>
3+
This intention merges two nested 'if's without 'else' branches into a single one.
4+
</body>
5+
</html>

idea/src/META-INF/plugin.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,11 @@
15021502
<category>Kotlin</category>
15031503
</intentionAction>
15041504

1505+
<intentionAction>
1506+
<className>org.jetbrains.kotlin.idea.intentions.MergeIfsIntention</className>
1507+
<category>Kotlin</category>
1508+
</intentionAction>
1509+
15051510
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
15061511
displayName="Object literal can be converted to lambda"
15071512
groupName="Kotlin"
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2010-2016 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jetbrains.kotlin.idea.intentions
18+
19+
import com.intellij.openapi.editor.Editor
20+
import org.jetbrains.kotlin.psi.*
21+
22+
class MergeIfsIntention : SelfTargetingIntention<KtIfExpression>(KtIfExpression::class.java, "Merge 'if's") {
23+
24+
override fun isApplicableTo(element: KtIfExpression, caretOffset: Int): Boolean {
25+
if (element.`else` != null) return false
26+
val then = element.then ?: return false
27+
28+
val nestedIf = then.nestedIf() ?: return false
29+
if (nestedIf.`else` != null) return false
30+
31+
return true
32+
}
33+
34+
override fun applyTo(element: KtIfExpression, editor: Editor?) {
35+
applyTo(element)
36+
}
37+
38+
companion object {
39+
fun applyTo(element: KtIfExpression): Int {
40+
val nestedIf = element.then?.nestedIf() ?: return -1
41+
val condition = element.condition ?: return -1
42+
val secondCondition = nestedIf.condition ?: return -1
43+
val nestedBody = nestedIf.then ?: return -1
44+
45+
val factory = KtPsiFactory(element)
46+
47+
condition.replace(factory.createExpressionByPattern("$0 && $1", condition, secondCondition))
48+
val newBody = element.then!!.replace(nestedBody)
49+
50+
return newBody.textRange!!.startOffset
51+
}
52+
53+
private fun KtExpression.nestedIf() = when (this) {
54+
is KtBlockExpression -> this.statements.singleOrNull() as? KtIfExpression
55+
is KtIfExpression -> this
56+
else -> null
57+
}
58+
}
59+
}

idea/src/org/jetbrains/kotlin/idea/joinLines/JoinBlockIntoSingleStatementHandler.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2015 JetBrains s.r.o.
2+
* Copyright 2010-2016 JetBrains s.r.o.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.joinLines
1919
import com.intellij.codeInsight.editorActions.JoinRawLinesHandlerDelegate
2020
import com.intellij.openapi.editor.Document
2121
import com.intellij.psi.PsiFile
22+
import org.jetbrains.kotlin.idea.intentions.MergeIfsIntention
2223
import org.jetbrains.kotlin.lexer.KtTokens
2324
import org.jetbrains.kotlin.psi.*
2425

@@ -45,15 +46,7 @@ class JoinBlockIntoSingleStatementHandler : JoinRawLinesHandlerDelegate {
4546
// if outer if has else-branch and inner does not have it, do not remove braces otherwise else-branch will belong to different if!
4647
if (pparent.`else` != null) return -1
4748

48-
val condition1 = pparent.condition
49-
val condition2 = statement.condition
50-
val body = statement.then
51-
if (condition1 != null && condition2 != null && body != null) {
52-
val newCondition = KtPsiFactory(pparent).createExpressionByPattern("$0 && $1", condition1, condition2)
53-
condition1.replace(newCondition)
54-
val newBody = block.replace(body)
55-
return newBody.textRange!!.startOffset
56-
}
49+
return MergeIfsIntention.applyTo(pparent)
5750
}
5851

5952
val newStatement = block.replace(statement)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.jetbrains.kotlin.idea.intentions.MergeIfsIntention
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fun foo() {
2+
// comment 1
3+
<caret>if (/* comment 2 */ true /* comment 3 */) {
4+
if (false) {
5+
// comment 4
6+
foo()
7+
}
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {
2+
// comment 1
3+
<caret>if (/* comment 2 */ true && false /* comment 3 */) {
4+
// comment 4
5+
foo()
6+
}
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// IS_APPLICABLE: false
2+
3+
fun foo() {
4+
<caret>if (true) {
5+
if (false) {
6+
foo()
7+
}
8+
} else {
9+
}
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// IS_APPLICABLE: false
2+
3+
fun foo() {
4+
<caret>if (true) {
5+
if (false) {
6+
foo()
7+
} else {
8+
9+
}
10+
}
11+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {
2+
<caret>if (true) if (false) {
3+
foo()
4+
}
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {
2+
<caret>if (true && false) {
3+
foo()
4+
}
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {
2+
<caret>if (true) {
3+
if (false) {
4+
foo()
5+
}
6+
}
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {
2+
<caret>if (true && false) {
3+
foo()
4+
}
5+
}

idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10507,6 +10507,45 @@ public void testToSetWithMap() throws Exception {
1050710507
}
1050810508
}
1050910509

10510+
@TestMetadata("idea/testData/intentions/mergeIfs")
10511+
@TestDataPath("$PROJECT_ROOT")
10512+
@RunWith(JUnit3RunnerWithInners.class)
10513+
public static class MergeIfs extends AbstractIntentionTest {
10514+
public void testAllFilesPresentInMergeIfs() throws Exception {
10515+
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/mergeIfs"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
10516+
}
10517+
10518+
@TestMetadata("comments.kt")
10519+
public void testComments() throws Exception {
10520+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/comments.kt");
10521+
doTest(fileName);
10522+
}
10523+
10524+
@TestMetadata("else1.kt")
10525+
public void testElse1() throws Exception {
10526+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/else1.kt");
10527+
doTest(fileName);
10528+
}
10529+
10530+
@TestMetadata("else2.kt")
10531+
public void testElse2() throws Exception {
10532+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/else2.kt");
10533+
doTest(fileName);
10534+
}
10535+
10536+
@TestMetadata("expression.kt")
10537+
public void testExpression() throws Exception {
10538+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/expression.kt");
10539+
doTest(fileName);
10540+
}
10541+
10542+
@TestMetadata("simple.kt")
10543+
public void testSimple() throws Exception {
10544+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/mergeIfs/simple.kt");
10545+
doTest(fileName);
10546+
}
10547+
}
10548+
1051010549
@TestMetadata("idea/testData/intentions/moveLambdaInsideParentheses")
1051110550
@TestDataPath("$PROJECT_ROOT")
1051210551
@RunWith(JUnit3RunnerWithInners.class)

0 commit comments

Comments
 (0)