Skip to content

Commit 4726b44

Browse files
t-kameyamamglukhikh
authored andcommitted
Add braces to 'if' statement: save/restore comments correctly
So #KT-16332 Fixed
1 parent b436ee6 commit 4726b44

File tree

17 files changed

+178
-5
lines changed

17 files changed

+178
-5
lines changed

compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,10 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
815815
return createFunction("fun foo() {\n$bodyText\n}").bodyExpression as KtBlockExpression
816816
}
817817

818-
fun createSingleStatementBlock(statement: KtExpression): KtBlockExpression {
819-
return createDeclarationByPattern<KtNamedFunction>("fun foo() {\n$0\n}", statement).bodyExpression as KtBlockExpression
818+
fun createSingleStatementBlock(statement: KtExpression, prevComment: String? = null, nextComment: String? = null): KtBlockExpression {
819+
val prev = if (prevComment == null) "" else " $prevComment "
820+
val next = if (nextComment == null) "" else " $nextComment "
821+
return createDeclarationByPattern<KtNamedFunction>("fun foo() {\n$prev$0$next\n}", statement).bodyExpression as KtBlockExpression
820822
}
821823

822824
fun createComment(text: String): PsiComment {

idea/src/org/jetbrains/kotlin/idea/intentions/AddBracesIntention.kt

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,15 @@
1717
package org.jetbrains.kotlin.idea.intentions
1818

1919
import com.intellij.openapi.editor.Editor
20+
import com.intellij.psi.PsiComment
21+
import com.intellij.psi.PsiElement
2022
import com.intellij.psi.PsiWhiteSpace
23+
import org.jetbrains.kotlin.KtNodeTypes
24+
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
25+
import org.jetbrains.kotlin.j2k.isInSingleLine
2126
import org.jetbrains.kotlin.psi.*
27+
import org.jetbrains.kotlin.psi.psiUtil.nextLeafs
28+
import org.jetbrains.kotlin.psi.psiUtil.prevLeafs
2229
import org.jetbrains.kotlin.psi.psiUtil.startOffset
2330
import java.lang.IllegalArgumentException
2431

@@ -52,8 +59,10 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
5259
element.nextSibling!!.delete()
5360
}
5461

62+
val (prevComment, nextComment) = deleteCommentsOnSameLine(expression, element)
63+
5564
val psiFactory = KtPsiFactory(element)
56-
expression.replace(psiFactory.createSingleStatementBlock(expression))
65+
expression.replace(psiFactory.createSingleStatementBlock(expression, prevComment, nextComment))
5766

5867
if (element is KtDoWhileExpression) { // remove new line between '}' and while
5968
(element.body!!.parent.nextSibling as? PsiWhiteSpace)?.delete()
@@ -67,8 +76,7 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
6776
val elseExpr = `else`
6877
if (elseExpr != null && caretLocation >= elseKeyword!!.startOffset) {
6978
elseExpr
70-
}
71-
else {
79+
} else {
7280
thenExpr
7381
}
7482
}
@@ -78,4 +86,35 @@ class AddBracesIntention : SelfTargetingIntention<KtElement>(KtElement::class.ja
7886
else -> null
7987
}
8088
}
89+
90+
private fun deleteCommentsOnSameLine(expression: KtExpression, element: KtElement): Pair<String?, String?> {
91+
val lineNumber = expression.getLineNumber()
92+
93+
val prevComments = getCommentsOnSameLine(lineNumber, expression.prevLeafs).reversed()
94+
val prevCommentText = createCommentText(prevComments)
95+
96+
val nextLeafs = when {
97+
expression.parent.node.elementType == KtNodeTypes.THEN && (element as? KtIfExpression)?.`else` != null -> expression.nextLeafs
98+
element is KtDoWhileExpression -> expression.nextLeafs
99+
else -> expression.nextLeafs
100+
}
101+
val nextComments = getCommentsOnSameLine(lineNumber, nextLeafs)
102+
val nextCommentText = createCommentText(nextComments)
103+
104+
(prevComments + nextComments).forEach { (it as? PsiComment)?.delete() }
105+
106+
return prevCommentText to nextCommentText
107+
}
108+
109+
private fun getCommentsOnSameLine(lineNumber: Int, elements: Sequence<PsiElement>): List<PsiElement> {
110+
return elements
111+
.takeWhile { (it is PsiWhiteSpace || it is PsiComment) && lineNumber == it.getLineNumber() && it.isInSingleLine() }
112+
.dropWhile { it is PsiWhiteSpace }
113+
.toList()
114+
.dropLastWhile { it is PsiWhiteSpace }
115+
}
116+
117+
private fun createCommentText(comments: List<PsiElement>): String? =
118+
if (comments.isEmpty()) null else comments.joinToString("") { it.text }
119+
81120
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fun foo() {}
2+
3+
fun test() {
4+
<caret>do /* aaa */ foo() // comment
5+
while(true)
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test() {
4+
do {
5+
/* aaa */ foo() // comment
6+
} while(true)
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
if (b) foo() <caret>else
5+
/* aaa */ foo() // bbb
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
if (b) foo() else {
5+
/* aaa */ foo() // bbb
6+
}
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {}
2+
3+
fun test() {
4+
<caret>for (i in 1..4) /* aaa */ foo() // bbb
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test() {
4+
for (i in 1..4) {
5+
/* aaa */ foo() // bbb
6+
}
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
<caret>if (b) foo() /* if comment */ else foo() // else comment
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
if (b) {
5+
foo() /* if comment */
6+
} else foo() // else comment
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
<caret>if (b) /* aaa */ /* bbb */ foo() // ccc
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
if (b) {
5+
/* aaa */ /* bbb */ foo() // ccc
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test(a: Int) {
4+
when (a) {
5+
<caret>1 -> /* aaa */ foo() // bbb
6+
}
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fun foo() {}
2+
3+
fun test(a: Int) {
4+
when (a) {
5+
1 -> {
6+
/* aaa */ foo() // bbb
7+
}
8+
}
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
<caret>while (b) /* aaa */ foo() // bbb
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fun foo() {}
2+
3+
fun test(b: Boolean) {
4+
while (b) {
5+
/* aaa */ foo() // bbb
6+
}
7+
}

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

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)