diff --git a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt index 19db2ae90c8..f330de41433 100644 --- a/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/jet/generators/tests/GenerateTests.kt @@ -393,6 +393,7 @@ fun main(args: Array) { model("intentions/replaceWithInfixFunctionCall", testMethod = "doTestReplaceWithInfixFunctionCall") model("intentions/removeCurlyBracesFromTemplate", testMethod = "doTestRemoveCurlyFromTemplate") model("intentions/convertToStringTemplateIntention", testMethod = "doTestConvertToStringTemplate") + model("intentions/convertToConcatenatedStringIntention", testMethod = "doTestConvertToConcatenatedStringIntention") model("intentions/insertCurlyBracestsToTemplate", testMethod = "doTestInsertCurlyToTemplate") model("intentions/moveLambdaInsideParentheses", testMethod = "doTestMoveLambdaInsideParentheses") model("intentions/moveLambdaOutsideParentheses", testMethod = "doTestMoveLambdaOutsideParentheses") diff --git a/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/after.kt.template new file mode 100644 index 00000000000..aa02c31e6cd --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/after.kt.template @@ -0,0 +1,2 @@ +val x = "World" +val y = "Hello " + x diff --git a/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/before.kt.template new file mode 100644 index 00000000000..025ec57dab4 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/before.kt.template @@ -0,0 +1,2 @@ +val x = "World" +val y = "Hello $x" diff --git a/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/description.html b/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/description.html new file mode 100644 index 00000000000..ebac90f912d --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertToConcatenatedStringIntention/description.html @@ -0,0 +1,5 @@ + + +Converts a statement that builds a String using a String Template to one that builds a String using '+' + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index c28f9d8ef54..d1d03ba323a 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -719,6 +719,11 @@ Kotlin + + org.jetbrains.jet.plugin.intentions.ConvertToConcatenatedStringIntention + Kotlin + + ("convert.to.concatenated.string.intention", javaClass()) { + override fun isApplicableTo(element: JetStringTemplateExpression): Boolean { + return element.getEntries().any { it is JetStringTemplateEntryWithExpression } + } + + override fun applyTo(element: JetStringTemplateExpression, editor: Editor) { + val tripleQuoted = isTripleQuoted(element.getText()!!) + val quote = if (tripleQuoted) "\"\"\"" else "\"" + val entries = element.getEntries() + + val result = entries.stream() + .withIndices() + .map { indexToEntry -> + val (index, entry) = indexToEntry + entry.toSeparateString(quote, convertExplicitly = index == 0, isFinalEntry = index == entries.size - 1) + } + .makeString(separator = "+") + .replaceAll("""$quote\+$quote""", "") + + val replacement = JetPsiFactory.createExpression(element.getProject(), result) + + 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 + } + } + + private fun needsParenthesis(expression: JetExpression, isFinalEntry: Boolean) = 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 = AnalyzerFacadeWithCache.getContextForElement(this) + val elementType = BindingContextUtils.getRecordedTypeInfo(this, context)?.getType() + + return KotlinBuiltIns.getInstance().isString(elementType) + } +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt new file mode 100644 index 00000000000..f932f57cd72 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt @@ -0,0 +1,3 @@ +fun main(args: Array) { + val x = "${if (true) 42 else 12}abc${if (true) 12 else 42}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt.after new file mode 100644 index 00000000000..168f8114ff4 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt.after @@ -0,0 +1,3 @@ +fun main(args: Array) { + val x = (if (true) 42 else 12).toString() + "abc" + if (true) 12 else 42 +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt new file mode 100644 index 00000000000..e682437bed9 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt @@ -0,0 +1,5 @@ +fun main(args: Array) { + val x = "${if (true) 42 else { + 12 + } }abc${if (true) 12 else 42}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt.after new file mode 100644 index 00000000000..5a8def0b002 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt.after @@ -0,0 +1,5 @@ +fun main(args: Array) { + val x = if (true) 42 else { + 12 + }.toString() + "abc" + if (true) 12 else 42 +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt new file mode 100644 index 00000000000..439b4f13771 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt @@ -0,0 +1,4 @@ +fun main(args: Array){ + var t = "t" + val x = "abc\n${t}bar\tfoo" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt.after new file mode 100644 index 00000000000..ef631514194 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt.after @@ -0,0 +1,4 @@ +fun main(args: Array){ + var t = "t" + val x = "abc\n" + t + "bar\tfoo" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt new file mode 100644 index 00000000000..61eae6d9c41 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "${"abc"}${"def"}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt.after new file mode 100644 index 00000000000..faa1c6e93e1 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt.after @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abcdef" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt new file mode 100644 index 00000000000..e2dcf2e6089 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt @@ -0,0 +1,5 @@ +fun main(args: Array){ + val a = "abc" + val c = "bcd" + val x = "${a}b$c" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt.after new file mode 100644 index 00000000000..a6d9f536d28 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt.after @@ -0,0 +1,5 @@ +fun main(args: Array){ + val a = "abc" + val c = "bcd" + val x = a + "b" + c +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt new file mode 100644 index 00000000000..d608e77312d --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc${'d'}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt.after new file mode 100644 index 00000000000..006bb0dafd2 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt.after @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc" + 'd' +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt new file mode 100644 index 00000000000..7ed794b0e61 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc${1}${2}${'a'}${3.2}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt.after new file mode 100644 index 00000000000..e0ac49e7176 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt.after @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc" + 1 + 2 + 'a' + 3.2 +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt new file mode 100644 index 00000000000..ba7af079c4e --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun main(args: Array){ + val x = mapOf("a" to "b") + val y = "abcd${x["a"]}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt.after new file mode 100644 index 00000000000..1de21710b73 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun main(args: Array){ + val x = mapOf("a" to "b") + val y = "abcd" + x["a"] +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt new file mode 100644 index 00000000000..46905379698 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun main(args: Array){ + val x = "abcd" + val y = "$x${x.reverse()}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt.after new file mode 100644 index 00000000000..69b98f37395 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun main(args: Array){ + val x = "abcd" + val y = x + x.reverse() +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt new file mode 100644 index 00000000000..2fd7c212ce9 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt @@ -0,0 +1,4 @@ +fun main(args: Array){ + val x = "abc" + val y = "${x}d" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt.after new file mode 100644 index 00000000000..12cb3e6f01a --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt.after @@ -0,0 +1,4 @@ +fun main(args: Array){ + val x = "abc" + val y = x + "d" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt new file mode 100644 index 00000000000..e9f0d037dc4 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc${0.32}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt.after new file mode 100644 index 00000000000..ae6139f771a --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt.after @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc" + 0.32 +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt new file mode 100644 index 00000000000..d2fbc7b269c --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc${32}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt.after new file mode 100644 index 00000000000..41211b6bee6 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt.after @@ -0,0 +1,3 @@ +fun main(args: Array){ + val x = "abc" + 32 +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt new file mode 100644 index 00000000000..a101342d535 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt @@ -0,0 +1,4 @@ +fun main(args: Array){ + val x = "abc" + val y = "d$x" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt.after new file mode 100644 index 00000000000..822a130f099 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt.after @@ -0,0 +1,4 @@ +fun main(args: Array){ + val x = "abc" + val y = "d" + x +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt new file mode 100644 index 00000000000..ddf74ef5c0e --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt @@ -0,0 +1,5 @@ +fun main(args: Array){ + var r = "a" + val x = """foobar + $r""" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt.after new file mode 100644 index 00000000000..6c5930757a8 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt.after @@ -0,0 +1,5 @@ +fun main(args: Array){ + var r = "a" + val x = """foobar + """ + r +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt new file mode 100644 index 00000000000..cd5f25f881b --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt @@ -0,0 +1,9 @@ +fun main(args: Array){ + val a = "${when (1) { + 1 -> 42 + else -> 3 + }}asdfas${when (1) { + 1 -> 42 + else -> 3 + }}" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt.after new file mode 100644 index 00000000000..2e8e5ffe115 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt.after @@ -0,0 +1,9 @@ +fun main(args: Array){ + val a = when (1) { + 1 -> 42 + else -> 3 + }.toString() + "asdfas" + when (1) { + 1 -> 42 + else -> 3 + } +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt new file mode 100644 index 00000000000..d0bffc8b3fc --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt @@ -0,0 +1,4 @@ +fun main(args: Array){ + val x = "abc" + val y = "$x.bar" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt.after new file mode 100644 index 00000000000..2d7059e7ae8 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt.after @@ -0,0 +1,4 @@ +fun main(args: Array){ + val x = "abc" + val y = x + ".bar" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForErrorElement.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForErrorElement.kt new file mode 100644 index 00000000000..8556f36be21 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForErrorElement.kt @@ -0,0 +1,5 @@ +// IS_APPLICABLE: false +fun main(args: Array){ + var a = 'a' + val x = "x$a{} +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForSimple.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForSimple.kt new file mode 100644 index 00000000000..4501713ca59 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForSimple.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +fun main(args: Array){ + val x = "xyz\n\n" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/notAvailableForDollarSignLiteral.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/notAvailableForDollarSignLiteral.kt new file mode 100644 index 00000000000..525cd09fd82 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/notAvailableForDollarSignLiteral.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +fun main(args: Array){ + val x = "\$d" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt new file mode 100644 index 00000000000..b24eb632e3c --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt @@ -0,0 +1,4 @@ +fun main(args: Array){ + val a = "a" + val x = "$a" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt.after new file mode 100644 index 00000000000..c3504843040 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt.after @@ -0,0 +1,4 @@ +fun main(args: Array){ + val a = "a" + val x = a +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt new file mode 100644 index 00000000000..5e414b168be --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt @@ -0,0 +1,4 @@ +fun main(args: Array){ + val a = 1 + val x = "$a!!!!" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt.after new file mode 100644 index 00000000000..a6abd7944bd --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt.after @@ -0,0 +1,4 @@ +fun main(args: Array){ + val a = 1 + val x = a.toString() + "!!!!" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt new file mode 100644 index 00000000000..1c402ebada4 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt @@ -0,0 +1,5 @@ +fun main(args: Array){ + val a = "abc" + val b = "bcd" + val x = "$a$b" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt.after new file mode 100644 index 00000000000..c4ddbc0d6ce --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt.after @@ -0,0 +1,5 @@ +fun main(args: Array){ + val a = "abc" + val b = "bcd" + val x = a + b +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt new file mode 100644 index 00000000000..49e97b2d7d2 --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt @@ -0,0 +1,5 @@ +fun compute1(): Int = 777 +fun main(args: Array){ + val a = "a" + "a = $a, b = ${compute1() + 222} :)" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt.after new file mode 100644 index 00000000000..93694baeaff --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt.after @@ -0,0 +1,5 @@ +fun compute1(): Int = 777 +fun main(args: Array){ + val a = "a" + "a = " + a + ", b = " + (compute1() + 222) + " :)" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt b/idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt new file mode 100644 index 00000000000..b0c7fe9acca --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun main(args: Array){ + val y = "cde" + val z = "${listOf(1, 2)}$y.bar" +} diff --git a/idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt.after b/idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt.after new file mode 100644 index 00000000000..c583a0585cc --- /dev/null +++ b/idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME +fun main(args: Array){ + val y = "cde" + val z = listOf(1, 2).toString() + y + ".bar" +} diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java index 9a277aa97f7..f53e249c20c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java @@ -67,6 +67,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes doTestIntention(path, new ConvertToStringTemplateIntention()); } + public void doTestConvertToConcatenatedStringIntention(@NotNull String path) throws Exception { + doTestIntention(path, new ConvertToConcatenatedStringIntention()); + } + public void doTestFoldIfToAssignment(@NotNull String path) throws Exception { doTestIntention(path, new FoldIfToAssignmentIntention()); } diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationTestGenerated.java index 6917c21c7bf..318b3cbc91f 100644 --- a/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationTestGenerated.java @@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.intentions.AbstractCodeTransformationTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@InnerTestClasses({CodeTransformationTestGenerated.DoubleBangToIfThen.class, CodeTransformationTestGenerated.IfThenToDoubleBang.class, CodeTransformationTestGenerated.ElvisToIfThen.class, CodeTransformationTestGenerated.IfThenToElvis.class, CodeTransformationTestGenerated.SafeAccessToIfThen.class, CodeTransformationTestGenerated.IfThenToSafeAccess.class, CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.ConvertToStringTemplateIntention.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, CodeTransformationTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, CodeTransformationTestGenerated.RemoveBraces.class, CodeTransformationTestGenerated.AddBraces.class, CodeTransformationTestGenerated.ReplaceGetIntention.class, CodeTransformationTestGenerated.ReplaceContainsIntention.class, CodeTransformationTestGenerated.ReplaceBinaryInfixIntention.class, CodeTransformationTestGenerated.ReplaceUnaryPrefixIntention.class, CodeTransformationTestGenerated.ReplaceInvokeIntention.class, CodeTransformationTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, CodeTransformationTestGenerated.ConvertNegatedBooleanSequence.class, CodeTransformationTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, CodeTransformationTestGenerated.SwapBinaryExpression.class, CodeTransformationTestGenerated.SplitIf.class, CodeTransformationTestGenerated.ReplaceWithOperatorAssign.class, CodeTransformationTestGenerated.ReplaceWithTraditionalAssignment.class, CodeTransformationTestGenerated.SimplifyBooleanWithConstants.class, CodeTransformationTestGenerated.InsertExplicitTypeArguments.class, CodeTransformationTestGenerated.RemoveExplicitTypeArguments.class, CodeTransformationTestGenerated.ConvertAssertToIf.class, CodeTransformationTestGenerated.ConvertIfToAssert.class, CodeTransformationTestGenerated.MakeTypeExplicitInLambda.class, CodeTransformationTestGenerated.MakeTypeImplicitInLambda.class, CodeTransformationTestGenerated.InvertIfCondition.class, CodeTransformationTestGenerated.OperatorToFunction.class, CodeTransformationTestGenerated.ConvertToForEachLoop.class, CodeTransformationTestGenerated.ConvertToForEachFunctionCall.class}) +@InnerTestClasses({CodeTransformationTestGenerated.DoubleBangToIfThen.class, CodeTransformationTestGenerated.IfThenToDoubleBang.class, CodeTransformationTestGenerated.ElvisToIfThen.class, CodeTransformationTestGenerated.IfThenToElvis.class, CodeTransformationTestGenerated.SafeAccessToIfThen.class, CodeTransformationTestGenerated.IfThenToSafeAccess.class, CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.ConvertToStringTemplateIntention.class, CodeTransformationTestGenerated.ConvertToConcatenatedStringIntention.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, CodeTransformationTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, CodeTransformationTestGenerated.RemoveBraces.class, CodeTransformationTestGenerated.AddBraces.class, CodeTransformationTestGenerated.ReplaceGetIntention.class, CodeTransformationTestGenerated.ReplaceContainsIntention.class, CodeTransformationTestGenerated.ReplaceBinaryInfixIntention.class, CodeTransformationTestGenerated.ReplaceUnaryPrefixIntention.class, CodeTransformationTestGenerated.ReplaceInvokeIntention.class, CodeTransformationTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, CodeTransformationTestGenerated.ConvertNegatedBooleanSequence.class, CodeTransformationTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, CodeTransformationTestGenerated.SwapBinaryExpression.class, CodeTransformationTestGenerated.SplitIf.class, CodeTransformationTestGenerated.ReplaceWithOperatorAssign.class, CodeTransformationTestGenerated.ReplaceWithTraditionalAssignment.class, CodeTransformationTestGenerated.SimplifyBooleanWithConstants.class, CodeTransformationTestGenerated.InsertExplicitTypeArguments.class, CodeTransformationTestGenerated.RemoveExplicitTypeArguments.class, CodeTransformationTestGenerated.ConvertAssertToIf.class, CodeTransformationTestGenerated.ConvertIfToAssert.class, CodeTransformationTestGenerated.MakeTypeExplicitInLambda.class, CodeTransformationTestGenerated.MakeTypeImplicitInLambda.class, CodeTransformationTestGenerated.InvertIfCondition.class, CodeTransformationTestGenerated.OperatorToFunction.class, CodeTransformationTestGenerated.ConvertToForEachLoop.class, CodeTransformationTestGenerated.ConvertToForEachFunctionCall.class}) public class CodeTransformationTestGenerated extends AbstractCodeTransformationTest { @TestMetadata("idea/testData/intentions/branched/doubleBangToIfThen") public static class DoubleBangToIfThen extends AbstractCodeTransformationTest { @@ -2310,6 +2310,134 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT } + @TestMetadata("idea/testData/intentions/convertToConcatenatedStringIntention") + public static class ConvertToConcatenatedStringIntention extends AbstractCodeTransformationTest { + public void testAllFilesPresentInConvertToConcatenatedStringIntention() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/intentions/convertToConcatenatedStringIntention"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("embeddedIf.kt") + public void testEmbeddedIf() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIf.kt"); + } + + @TestMetadata("embeddedIfBraces.kt") + public void testEmbeddedIfBraces() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/embeddedIfBraces.kt"); + } + + @TestMetadata("handlesEscapeString.kt") + public void testHandlesEscapeString() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/handlesEscapeString.kt"); + } + + @TestMetadata("interpolate2StringConstants.kt") + public void testInterpolate2StringConstants() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolate2StringConstants.kt"); + } + + @TestMetadata("interpolate3.kt") + public void testInterpolate3() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolate3.kt"); + } + + @TestMetadata("interpolateChar.kt") + public void testInterpolateChar() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateChar.kt"); + } + + @TestMetadata("interpolateConstants.kt") + public void testInterpolateConstants() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateConstants.kt"); + } + + @TestMetadata("interpolateMapAccess.kt") + public void testInterpolateMapAccess() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMapAccess.kt"); + } + + @TestMetadata("interpolateMethodInvoke.kt") + public void testInterpolateMethodInvoke() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateMethodInvoke.kt"); + } + + @TestMetadata("interpolateSimpleWithBraces.kt") + public void testInterpolateSimpleWithBraces() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateSimpleWithBraces.kt"); + } + + @TestMetadata("interpolateStringWithFloat.kt") + public void testInterpolateStringWithFloat() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithFloat.kt"); + } + + @TestMetadata("interpolateStringWithInt.kt") + public void testInterpolateStringWithInt() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/interpolateStringWithInt.kt"); + } + + @TestMetadata("lastExprIsNamedExpression.kt") + public void testLastExprIsNamedExpression() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/lastExprIsNamedExpression.kt"); + } + + @TestMetadata("multilineString.kt") + public void testMultilineString() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/multilineString.kt"); + } + + @TestMetadata("multilineWhenExpr.kt") + public void testMultilineWhenExpr() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/multilineWhenExpr.kt"); + } + + @TestMetadata("namedExprBetweenConstants.kt") + public void testNamedExprBetweenConstants() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/namedExprBetweenConstants.kt"); + } + + @TestMetadata("notApplicableForErrorElement.kt") + public void testNotApplicableForErrorElement() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForErrorElement.kt"); + } + + @TestMetadata("notApplicableForSimple.kt") + public void testNotApplicableForSimple() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/notApplicableForSimple.kt"); + } + + @TestMetadata("notAvailableForDollarSignLiteral.kt") + public void testNotAvailableForDollarSignLiteral() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/notAvailableForDollarSignLiteral.kt"); + } + + @TestMetadata("singleVar.kt") + public void testSingleVar() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/singleVar.kt"); + } + + @TestMetadata("startsWithInt.kt") + public void testStartsWithInt() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/startsWithInt.kt"); + } + + @TestMetadata("startsWithStringExpression.kt") + public void testStartsWithStringExpression() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/startsWithStringExpression.kt"); + } + + @TestMetadata("tricky.kt") + public void testTricky() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/tricky.kt"); + } + + @TestMetadata("withAndWithoutBraces.kt") + public void testWithAndWithoutBraces() throws Exception { + doTestConvertToConcatenatedStringIntention("idea/testData/intentions/convertToConcatenatedStringIntention/withAndWithoutBraces.kt"); + } + + } + @TestMetadata("idea/testData/intentions/moveLambdaInsideParentheses") public static class MoveLambdaInsideParentheses extends AbstractCodeTransformationTest { public void testAllFilesPresentInMoveLambdaInsideParentheses() throws Exception { @@ -4654,6 +4782,7 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT suite.addTestSuite(ReplaceWithInfixFunctionCall.class); suite.addTestSuite(RemoveCurlyBracesFromTemplate.class); suite.addTestSuite(ConvertToStringTemplateIntention.class); + suite.addTestSuite(ConvertToConcatenatedStringIntention.class); suite.addTestSuite(MoveLambdaInsideParentheses.class); suite.addTestSuite(MoveLambdaOutsideParentheses.class); suite.addTestSuite(ReplaceExplicitFunctionLiteralParamWithIt.class);