"Join lines" works incorrectly in case of line with more than one string literal (KT-22374)
#KT-22374 Fixed
This commit is contained in:
committed by
Nikolay Krasko
parent
c06aaf6128
commit
4232ad8dfe
@@ -57,7 +57,7 @@ open class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentInte
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression {
|
||||
protected fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression {
|
||||
val rightText = buildText(expression.right, false)
|
||||
return fold(expression.left, rightText, KtPsiFactory(expression))
|
||||
}
|
||||
@@ -75,7 +75,7 @@ open class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentInte
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildText(expr: KtExpression?, forceBraces: Boolean): String {
|
||||
fun buildText(expr: KtExpression?, forceBraces: Boolean): String {
|
||||
if (expr == null) return ""
|
||||
val expression = KtPsiUtil.safeDeparenthesize(expr)
|
||||
val expressionText = expression.text
|
||||
@@ -130,7 +130,7 @@ open class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentInte
|
||||
return "\${$expressionText}"
|
||||
}
|
||||
|
||||
fun isApplicableToNoParentCheck(expression: KtBinaryExpression): Boolean {
|
||||
private fun isApplicableToNoParentCheck(expression: KtBinaryExpression): Boolean {
|
||||
if (expression.operationToken != KtTokens.PLUS) return false
|
||||
val expressionType = expression.analyze(BodyResolveMode.PARTIAL).getType(expression)
|
||||
if (!KotlinBuiltIns.isString(expressionType)) return false
|
||||
|
||||
@@ -20,10 +20,10 @@ import com.intellij.codeInsight.editorActions.JoinRawLinesHandlerDelegate
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.intentions.ConvertToStringTemplateIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.lineCount
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineCount
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
|
||||
class JoinToStringTemplateHandler : JoinRawLinesHandlerDelegate {
|
||||
@@ -35,16 +35,61 @@ class JoinToStringTemplateHandler : JoinRawLinesHandlerDelegate {
|
||||
val index = if (c == '\n') start - 1 else start
|
||||
|
||||
val plus = file.findElementAt(index)?.takeIf { it.node?.elementType == KtTokens.PLUS } ?: return -1
|
||||
val expression = (plus.parent.parent as? KtBinaryExpression) ?: return -1
|
||||
val left = expression.left ?: return -1
|
||||
val right = expression.right ?: return -1
|
||||
if (left !is KtStringTemplateExpression || right !is KtStringTemplateExpression) return -1
|
||||
if (!ConvertToStringTemplateIntention.isApplicableToNoParentCheck(expression)) return -1
|
||||
var binaryExpr = (plus.parent.parent as? KtBinaryExpression) ?: return -1
|
||||
if (!binaryExpr.joinable()) return -1
|
||||
|
||||
val offset = left.endOffset - 1
|
||||
expression.replace(ConvertToStringTemplateIntention.buildReplacement(expression))
|
||||
return offset
|
||||
val lineCount = binaryExpr.getLineCount()
|
||||
val nextLineCount = lineCount + 1
|
||||
|
||||
var parent = binaryExpr.parent
|
||||
while (parent is KtBinaryExpression && parent.joinable() && parent.lineCount() == nextLineCount) {
|
||||
binaryExpr = parent
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
var rightText = ConvertToStringTemplateIntention.buildText(binaryExpr.right, false)
|
||||
var left = binaryExpr.left
|
||||
while (left is KtBinaryExpression && left.joinable() && left.parent.getLineCount() >= lineCount) {
|
||||
rightText = ConvertToStringTemplateIntention.buildText(left.right, false) + rightText
|
||||
left = left.left
|
||||
}
|
||||
|
||||
return when (left) {
|
||||
is KtStringTemplateExpression -> {
|
||||
val offset = left.endOffset - 1
|
||||
binaryExpr.replace(createStringTemplate(left, rightText))
|
||||
offset
|
||||
}
|
||||
is KtBinaryExpression -> {
|
||||
val leftRight = left.right
|
||||
if (leftRight is KtStringTemplateExpression) {
|
||||
val offset = leftRight.endOffset - 1
|
||||
leftRight.replace(createStringTemplate(leftRight, rightText))
|
||||
binaryExpr.replace(left)
|
||||
offset
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStringTemplate(left: KtStringTemplateExpression, rightText: String): KtStringTemplateExpression {
|
||||
val leftText = ConvertToStringTemplateIntention.buildText(left, false)
|
||||
return KtPsiFactory(left).createExpression("\"$leftText$rightText\"") as KtStringTemplateExpression
|
||||
}
|
||||
|
||||
override fun tryJoinLines(document: Document, file: PsiFile, start: Int, end: Int): Int = -1
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtBinaryExpression.joinable(): Boolean {
|
||||
if (operationToken != KtTokens.PLUS) return false
|
||||
if (right !is KtStringTemplateExpression) return false
|
||||
val left = left
|
||||
return when (left) {
|
||||
is KtStringTemplateExpression -> true
|
||||
is KtBinaryExpression -> left.right is KtStringTemplateExpression
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
val s = "1" + "2" +
|
||||
"3" + "4" +<caret>
|
||||
"5" + "6" +
|
||||
"7" + "8"
|
||||
@@ -0,0 +1,3 @@
|
||||
val s = "1" + "2" +
|
||||
"3<caret>456" +
|
||||
"7" + "8"
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
val foo = "test"
|
||||
val s = "1" + "2" +
|
||||
foo + "4" +<caret>
|
||||
"5" + foo +
|
||||
"7" + "8"
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
val foo = "test"
|
||||
val s = "1" + "2" +
|
||||
foo + "4<caret>5" + foo +
|
||||
"7" + "8"
|
||||
+12
@@ -429,6 +429,18 @@ public class JoinLinesTestGenerated extends AbstractJoinLinesTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lineWithMultiStringLiteral.kt")
|
||||
public void testLineWithMultiStringLiteral() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/joinLines/stringTemplate/lineWithMultiStringLiteral.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lineWithMultiStringLiteralAndVariable.kt")
|
||||
public void testLineWithMultiStringLiteralAndVariable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/joinLines/stringTemplate/lineWithMultiStringLiteralAndVariable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("secondLineVariable.kt")
|
||||
public void testSecondLineVariable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/joinLines/stringTemplate/secondLineVariable.kt");
|
||||
|
||||
Reference in New Issue
Block a user