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.editor.Editor
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
|
import org.jetbrains.kotlin.idea.inspections.collections.isCalling
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
|
||||||
class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention<KtStringTemplateExpression>(
|
class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention<KtStringTemplateExpression>(
|
||||||
KtStringTemplateExpression::class.java,
|
KtStringTemplateExpression::class.java,
|
||||||
"To ordinary string literal"
|
"To ordinary string literal"
|
||||||
), LowPriorityAction {
|
), LowPriorityAction {
|
||||||
|
companion object {
|
||||||
|
private val TRIM_INDENT_FUNCTIONS = listOf(FqName("kotlin.text.trimIndent"), FqName("kotlin.text.trimMargin"))
|
||||||
|
}
|
||||||
|
|
||||||
override fun isApplicableTo(element: KtStringTemplateExpression): Boolean {
|
override fun isApplicableTo(element: KtStringTemplateExpression): Boolean {
|
||||||
return element.text.startsWith("\"\"\"")
|
return element.text.startsWith("\"\"\"")
|
||||||
}
|
}
|
||||||
@@ -39,24 +44,20 @@ class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention
|
|||||||
val endOffset = element.endOffset
|
val endOffset = element.endOffset
|
||||||
val currentOffset = editor?.caretModel?.currentCaret?.offset ?: startOffset
|
val currentOffset = editor?.caretModel?.currentCaret?.offset ?: startOffset
|
||||||
|
|
||||||
|
val entries = element.entries
|
||||||
|
val trimIndentCall = getTrimIndentCall(element, entries)
|
||||||
val text = buildString {
|
val text = buildString {
|
||||||
append("\"")
|
append("\"")
|
||||||
|
if (trimIndentCall != null) {
|
||||||
for (entry in element.entries) {
|
append(trimIndentCall.stringTemplateText)
|
||||||
if (entry is KtLiteralStringTemplateEntry) {
|
} else {
|
||||||
var text = entry.text
|
entries.joinTo(buffer = this, separator = "") {
|
||||||
text = text.replace("\\", "\\\\")
|
if (it is KtLiteralStringTemplateEntry) it.text.escape() else it.text
|
||||||
text = text.replace("\"", "\\\"")
|
|
||||||
text = StringUtil.convertLineSeparators(text, "\\n")
|
|
||||||
append(text)
|
|
||||||
} else {
|
|
||||||
append(entry.text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
append("\"")
|
append("\"")
|
||||||
}
|
}
|
||||||
val replaced = element.replaced(KtPsiFactory(element).createExpression(text))
|
val replaced = (trimIndentCall?.qualifiedExpression ?: element).replaced(KtPsiFactory(element).createExpression(text))
|
||||||
|
|
||||||
val offset = when {
|
val offset = when {
|
||||||
currentOffset - startOffset < 2 -> startOffset
|
currentOffset - startOffset < 2 -> startOffset
|
||||||
@@ -65,4 +66,42 @@ class ToOrdinaryStringLiteralIntention : SelfTargetingOffsetIndependentIntention
|
|||||||
}
|
}
|
||||||
editor?.caretModel?.moveToOffset(offset)
|
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 {
|
public void testSimple() throws Exception {
|
||||||
runTest("idea/testData/intentions/toOrdinaryStringLiteral/simple.kt");
|
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")
|
@TestMetadata("idea/testData/intentions/toRawStringLiteral")
|
||||||
|
|||||||
Reference in New Issue
Block a user