diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties index 81b1e44571b..713466a61a7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/JetBundle.properties @@ -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.string.template=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.overridden.too.many=Is overridden in subclasses diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt index d92bb03f04c..73c9c54cee0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContextUtils -public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndependentIntention("convert.to.concatenated.string.intention", javaClass()) { +public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndependentIntention(javaClass(), "Convert template to concatenated string") { override fun isApplicableTo(element: JetStringTemplateExpression): Boolean { if (element.getLastChild().getNode().getElementType() != JetTokens.CLOSING_QUOTE) return false // not available for unclosed literal return element.getEntries().any { it is JetStringTemplateEntryWithExpression } @@ -34,46 +34,47 @@ public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndepe val quote = if (tripleQuoted) "\"\"\"" else "\"" val entries = element.getEntries() - val result = entries.sequence() + val text = entries + .filterNot { it is JetStringTemplateEntryWithExpression && it.getExpression() == null } .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 = "+") .replaceAll("""$quote\+$quote""", "") - val replacement = JetPsiFactory(element).createExpression(result) - + val replacement = JetPsiFactory(element).createExpression(text) element.replace(replacement) } private fun isTripleQuoted(str: String) = str.startsWith("\"\"\"") && str.endsWith("\"\"\"") private fun JetStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String { - 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 + if (this !is JetStringTemplateEntryWithExpression) { + return getText().quote(quote) } + + 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) { - is JetBinaryExpression -> true - is JetIfExpression -> expression.getElse() !is JetBlockExpression && !isFinalEntry - else -> false + private fun needsParenthesis(expression: JetExpression, isFinalEntry: Boolean): Boolean { + return when (expression) { + is JetBinaryExpression -> true + is JetIfExpression -> expression.getElse() !is JetBlockExpression && !isFinalEntry + else -> false + } } private fun String.quote(quote: String) = quote + this + quote - private fun JetExpression.isStringExpression(): Boolean { - val context = this.analyze() - val elementType = BindingContextUtils.getRecordedTypeInfo(this, context)?.getType() - - return KotlinBuiltIns.isString(elementType) - } + private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.getType()) } diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt new file mode 100644 index 00000000000..f30df71a615 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt @@ -0,0 +1 @@ +val v = "${}saasd" \ No newline at end of file diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt.after new file mode 100644 index 00000000000..a6b1780673c --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/emptyBraces.kt.after @@ -0,0 +1 @@ +val v = "saasd" \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 9432617e373..01477f6a962 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -3214,6 +3214,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { 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") public void testHandlesEscapeString() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt");