To ordinary string literal: remove 'trimIndent()' if string is single line
#KT-32616 Fixed
This commit is contained in:
committed by
Ilya Kirillov
parent
fbe66c3496
commit
d4e4a4c3e7
@@ -20,16 +20,21 @@ import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.kotlin.idea.inspections.collections.isCalling
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention<KtStringTemplateExpression>(
|
||||
KtStringTemplateExpression::class.java,
|
||||
"To ordinary string literal"
|
||||
), LowPriorityAction {
|
||||
companion object {
|
||||
private val TRIM_INDENT_FUNCTIONS = listOf(FqName("kotlin.text.trimIndent"), FqName("kotlin.text.trimMargin"))
|
||||
}
|
||||
|
||||
override fun isApplicableTo(element: KtStringTemplateExpression): Boolean {
|
||||
return element.text.startsWith("\"\"\"")
|
||||
}
|
||||
@@ -39,24 +44,20 @@ class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention
|
||||
val endOffset = element.endOffset
|
||||
val currentOffset = editor?.caretModel?.currentCaret?.offset ?: startOffset
|
||||
|
||||
val entries = element.entries
|
||||
val trimIndentCall = getTrimIndentCall(element, entries)
|
||||
val text = buildString {
|
||||
append("\"")
|
||||
|
||||
for (entry in element.entries) {
|
||||
if (entry is KtLiteralStringTemplateEntry) {
|
||||
var text = entry.text
|
||||
text = text.replace("\\", "\\\\")
|
||||
text = text.replace("\"", "\\\"")
|
||||
text = StringUtil.convertLineSeparators(text, "\\n")
|
||||
append(text)
|
||||
} else {
|
||||
append(entry.text)
|
||||
if (trimIndentCall != null) {
|
||||
append(trimIndentCall.stringTemplateText)
|
||||
} else {
|
||||
entries.joinTo(buffer = this, separator = "") {
|
||||
if (it is KtLiteralStringTemplateEntry) it.text.escape() else it.text
|
||||
}
|
||||
}
|
||||
|
||||
append("\"")
|
||||
}
|
||||
val replaced = element.replaced(KtPsiFactory(element).createExpression(text))
|
||||
val replaced = (trimIndentCall?.qualifiedExpression ?: element).replaced(KtPsiFactory(element).createExpression(text))
|
||||
|
||||
val offset = when {
|
||||
currentOffset - startOffset < 2 -> startOffset
|
||||
@@ -65,4 +66,42 @@ class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention
|
||||
}
|
||||
editor?.caretModel?.moveToOffset(offset)
|
||||
}
|
||||
|
||||
private fun String.escape(): String {
|
||||
var text = this
|
||||
text = text.replace("\\", "\\\\")
|
||||
text = text.replace("\"", "\\\"")
|
||||
return StringUtil.convertLineSeparators(text, "\\n")
|
||||
}
|
||||
|
||||
private fun getTrimIndentCall(
|
||||
element: KtStringTemplateExpression,
|
||||
entries: Array<KtStringTemplateEntry>
|
||||
): TrimIndentCall? {
|
||||
val qualifiedExpression = element.getQualifiedExpressionForReceiver()?.takeIf {
|
||||
it.callExpression?.isCalling(TRIM_INDENT_FUNCTIONS) == true
|
||||
} ?: return null
|
||||
|
||||
val marginPrefix = if (qualifiedExpression.calleeName == "trimMargin") {
|
||||
when (val arg = qualifiedExpression.callExpression?.valueArguments?.singleOrNull()?.getArgumentExpression()) {
|
||||
null -> "|"
|
||||
is KtStringTemplateExpression -> arg.entries.singleOrNull()?.takeIf { it is KtLiteralStringTemplateEntry }?.text
|
||||
else -> null
|
||||
} ?: return null
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val stringTemplateText = entries
|
||||
.joinToString(separator = "") { it.text }
|
||||
.let { if (marginPrefix != null) it.trimMargin(marginPrefix) else it.trimIndent() }
|
||||
.escape()
|
||||
|
||||
return TrimIndentCall(qualifiedExpression, stringTemplateText)
|
||||
}
|
||||
|
||||
private data class TrimIndentCall(
|
||||
val qualifiedExpression: KtQualifiedExpression,
|
||||
val stringTemplateText: String
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
foo
|
||||
""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo"
|
||||
@@ -0,0 +1,3 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""foo
|
||||
""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo"
|
||||
@@ -0,0 +1,3 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
foo""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo"
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""foo""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo"
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>""
|
||||
@@ -0,0 +1,3 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>""
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
val s = """
|
||||
<caret>
|
||||
""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = " "<caret>
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
foo
|
||||
bar
|
||||
""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo\nbar"
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
\foo
|
||||
\\bar
|
||||
""".trimIndent()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"\\foo\n \\\\bar"
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
|foo
|
||||
""".trimMargin()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo"
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
_foo
|
||||
_bar
|
||||
""".trimMargin("_")
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"foo\nbar"
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"""
|
||||
|\foo
|
||||
| \\bar
|
||||
""".trimMargin()
|
||||
@@ -0,0 +1,2 @@
|
||||
// WITH_RUNTIME
|
||||
val s = <caret>"\\foo\n \\\\bar"
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
val prefix = "|"
|
||||
val s = <caret>"""
|
||||
|foo
|
||||
|bar
|
||||
""".trimMargin(prefix)
|
||||
@@ -0,0 +1,3 @@
|
||||
// WITH_RUNTIME
|
||||
val prefix = "|"
|
||||
val s = <caret>"\n |foo\n |bar\n".trimMargin(prefix)
|
||||
@@ -15761,6 +15761,71 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
public void testSimple() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/simple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent1.kt")
|
||||
public void testTrimIndent1() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent2.kt")
|
||||
public void testTrimIndent2() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent3.kt")
|
||||
public void testTrimIndent3() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent4.kt")
|
||||
public void testTrimIndent4() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent5.kt")
|
||||
public void testTrimIndent5() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent5.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent6.kt")
|
||||
public void testTrimIndent6() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent6.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent7.kt")
|
||||
public void testTrimIndent7() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent7.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent8.kt")
|
||||
public void testTrimIndent8() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent8.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimIndent9.kt")
|
||||
public void testTrimIndent9() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimIndent9.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimMargin1.kt")
|
||||
public void testTrimMargin1() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimMargin1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimMargin2.kt")
|
||||
public void testTrimMargin2() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimMargin2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimMargin3.kt")
|
||||
public void testTrimMargin3() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimMargin3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("trimMargin4.kt")
|
||||
public void testTrimMargin4() throws Exception {
|
||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/trimMargin4.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/toRawStringLiteral")
|
||||
|
||||
Reference in New Issue
Block a user