ConvertToConcatenatedStringIntention - minor code improvements + fixed bug
This commit is contained in:
@@ -339,8 +339,6 @@ convert.to.for.each.function.call.intention=Replace with a forEach function call
|
|||||||
convert.to.for.each.function.call.intention.family=Replace with a forEach Function Call
|
convert.to.for.each.function.call.intention.family=Replace with a forEach Function Call
|
||||||
convert.to.string.template=Convert concatenation to template
|
convert.to.string.template=Convert concatenation to template
|
||||||
convert.to.string.template.family=Convert Concatenation to Template
|
convert.to.string.template.family=Convert Concatenation to Template
|
||||||
convert.to.concatenated.string.intention=Convert template to concatenated string
|
|
||||||
convert.to.concatenated.string.intention.family=Convert Template to Concatenated String
|
|
||||||
|
|
||||||
property.is.implemented.too.many=Has implementations
|
property.is.implemented.too.many=Has implementations
|
||||||
property.is.overridden.too.many=Is overridden in subclasses
|
property.is.overridden.too.many=Is overridden in subclasses
|
||||||
|
|||||||
+26
-25
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.lexer.JetTokens
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||||
|
|
||||||
public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndependentIntention<JetStringTemplateExpression>("convert.to.concatenated.string.intention", javaClass()) {
|
public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndependentIntention<JetStringTemplateExpression>(javaClass(), "Convert template to concatenated string") {
|
||||||
override fun isApplicableTo(element: JetStringTemplateExpression): Boolean {
|
override fun isApplicableTo(element: JetStringTemplateExpression): Boolean {
|
||||||
if (element.getLastChild().getNode().getElementType() != JetTokens.CLOSING_QUOTE) return false // not available for unclosed literal
|
if (element.getLastChild().getNode().getElementType() != JetTokens.CLOSING_QUOTE) return false // not available for unclosed literal
|
||||||
return element.getEntries().any { it is JetStringTemplateEntryWithExpression }
|
return element.getEntries().any { it is JetStringTemplateEntryWithExpression }
|
||||||
@@ -34,46 +34,47 @@ public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndepe
|
|||||||
val quote = if (tripleQuoted) "\"\"\"" else "\""
|
val quote = if (tripleQuoted) "\"\"\"" else "\""
|
||||||
val entries = element.getEntries()
|
val entries = element.getEntries()
|
||||||
|
|
||||||
val result = entries.sequence()
|
val text = entries
|
||||||
|
.filterNot { it is JetStringTemplateEntryWithExpression && it.getExpression() == null }
|
||||||
.mapIndexed { index, entry ->
|
.mapIndexed { index, entry ->
|
||||||
entry.toSeparateString(quote, convertExplicitly = index == 0, isFinalEntry = index == entries.size() - 1)
|
entry.toSeparateString(quote, convertExplicitly = (index == 0), isFinalEntry = (index == entries.lastIndex))
|
||||||
}
|
}
|
||||||
.join(separator = "+")
|
.join(separator = "+")
|
||||||
.replaceAll("""$quote\+$quote""", "")
|
.replaceAll("""$quote\+$quote""", "")
|
||||||
|
|
||||||
val replacement = JetPsiFactory(element).createExpression(result)
|
val replacement = JetPsiFactory(element).createExpression(text)
|
||||||
|
|
||||||
element.replace(replacement)
|
element.replace(replacement)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isTripleQuoted(str: String) = str.startsWith("\"\"\"") && str.endsWith("\"\"\"")
|
private fun isTripleQuoted(str: String) = str.startsWith("\"\"\"") && str.endsWith("\"\"\"")
|
||||||
|
|
||||||
private fun JetStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String {
|
private fun JetStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String {
|
||||||
if (this !is JetStringTemplateEntryWithExpression) return getText()!!.quote(quote)
|
if (this !is JetStringTemplateEntryWithExpression) {
|
||||||
|
return getText().quote(quote)
|
||||||
val expression = getExpression()!!
|
|
||||||
|
|
||||||
val expressionText = if (needsParenthesis(expression, isFinalEntry)) "(${expression.getText()})" else expression.getText()!!
|
|
||||||
return if (convertExplicitly && !expression.isStringExpression()) {
|
|
||||||
expressionText + ".toString()"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
expressionText
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val expression = getExpression()!! // checked before
|
||||||
|
|
||||||
|
val text = if (needsParenthesis(expression, isFinalEntry))
|
||||||
|
"(" + expression.getText() + ")"
|
||||||
|
else
|
||||||
|
expression.getText()
|
||||||
|
|
||||||
|
return if (convertExplicitly && !expression.isStringExpression())
|
||||||
|
text + ".toString()"
|
||||||
|
else
|
||||||
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun needsParenthesis(expression: JetExpression, isFinalEntry: Boolean) = when (expression) {
|
private fun needsParenthesis(expression: JetExpression, isFinalEntry: Boolean): Boolean {
|
||||||
is JetBinaryExpression -> true
|
return when (expression) {
|
||||||
is JetIfExpression -> expression.getElse() !is JetBlockExpression && !isFinalEntry
|
is JetBinaryExpression -> true
|
||||||
else -> false
|
is JetIfExpression -> expression.getElse() !is JetBlockExpression && !isFinalEntry
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.quote(quote: String) = quote + this + quote
|
private fun String.quote(quote: String) = quote + this + quote
|
||||||
|
|
||||||
private fun JetExpression.isStringExpression(): Boolean {
|
private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.getType())
|
||||||
val context = this.analyze()
|
|
||||||
val elementType = BindingContextUtils.getRecordedTypeInfo(this, context)?.getType()
|
|
||||||
|
|
||||||
return KotlinBuiltIns.isString(elementType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
val v = <caret>"${}saasd"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
val v = "saasd"
|
||||||
@@ -3214,6 +3214,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("emptyBraces.kt")
|
||||||
|
public void testEmptyBraces() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("handlesEscapeString.kt")
|
@TestMetadata("handlesEscapeString.kt")
|
||||||
public void testHandlesEscapeString() throws Exception {
|
public void testHandlesEscapeString() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user