diff --git a/idea/resources/inspectionDescriptions/RemoveSingleExpressionStringTemplate.html b/idea/resources/inspectionDescriptions/RemoveSingleExpressionStringTemplate.html
new file mode 100644
index 00000000000..25a5f780a57
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/RemoveSingleExpressionStringTemplate.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports single-expression String template that can be safely removed
+
+
diff --git a/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/after.kt.template b/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/after.kt.template
new file mode 100644
index 00000000000..465df185e8a
--- /dev/null
+++ b/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/after.kt.template
@@ -0,0 +1,4 @@
+fun foo(x: Int, y: String) {
+ val z = y
+ val w = x.toString()
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/before.kt.template b/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/before.kt.template
new file mode 100644
index 00000000000..b2246682813
--- /dev/null
+++ b/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/before.kt.template
@@ -0,0 +1,4 @@
+fun foo(x: Int, y: String) {
+ val z = "$y"
+ val w = "$x"
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/description.html b/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/description.html
new file mode 100644
index 00000000000..b53507c1360
--- /dev/null
+++ b/idea/resources/intentionDescriptions/RemoveSingleExpressionStringTemplateIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention replaces single-expression string templates with expression itself, with toString() if necessary
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 81070fed4e0..5b3cb0709ce 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1273,6 +1273,11 @@
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.RemoveSingleExpressionStringTemplateIntention
+ Kotlin
+
+
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveSingleExpressionStringTemplateIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveSingleExpressionStringTemplateIntention.kt
new file mode 100644
index 00000000000..36c19296684
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveSingleExpressionStringTemplateIntention.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.intentions
+
+import com.intellij.openapi.editor.Editor
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.psi.KtStringTemplateExpression
+import org.jetbrains.kotlin.psi.createExpressionByPattern
+import org.jetbrains.kotlin.resolve.calls.callUtil.getType
+
+private fun KtStringTemplateExpression.singleExpressionOrNull() =
+ children.singleOrNull()?.children?.firstOrNull() as? KtExpression
+
+class RemoveSingleExpressionStringTemplateInspection : IntentionBasedInspection(
+ RemoveSingleExpressionStringTemplateIntention()
+) {
+ override val problemText = "Single-expression string template"
+}
+
+class RemoveSingleExpressionStringTemplateIntention : SelfTargetingOffsetIndependentIntention(
+ KtStringTemplateExpression::class.java,
+ "Remove single-expression string template"
+) {
+ override fun isApplicableTo(element: KtStringTemplateExpression) =
+ element.singleExpressionOrNull() != null
+
+ override fun applyTo(element: KtStringTemplateExpression, editor: Editor?) {
+ val expression = element.singleExpressionOrNull() ?: return
+ val type = expression.getType(expression.analyze())
+ val newElement =
+ if (KotlinBuiltIns.isString(type)) expression
+ else KtPsiFactory(element).createExpressionByPattern("$0.$1()", expression, "toString")
+ element.replace(newElement)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/.intention b/idea/testData/intentions/removeSingleExpressionStringTemplate/.intention
new file mode 100644
index 00000000000..9520a89c788
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.RemoveSingleExpressionStringTemplateIntention
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/emptyString.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/emptyString.kt
new file mode 100644
index 00000000000..8e9da61b35c
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/emptyString.kt
@@ -0,0 +1,3 @@
+// IS_APPLICABLE: FALSE
+
+val bar = ""
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/justString.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/justString.kt
new file mode 100644
index 00000000000..048cd6d7db2
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/justString.kt
@@ -0,0 +1,3 @@
+// IS_APPLICABLE: FALSE
+
+val bar = "Hello"
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/multipleStringTemplate.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/multipleStringTemplate.kt
new file mode 100644
index 00000000000..92ed7d7a091
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/multipleStringTemplate.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: FALSE
+
+val foo = "foo"
+val bar = "$foo$foo"
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt
new file mode 100644
index 00000000000..48c6500b724
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt
@@ -0,0 +1,4 @@
+// INTENTION_TEXT: Remove single-expression string template
+
+val foo = "foo"
+val bar = "$foo"
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt.after b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt.after
new file mode 100644
index 00000000000..bfa18b703b2
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt.after
@@ -0,0 +1,4 @@
+// INTENTION_TEXT: Remove single-expression string template
+
+val foo = "foo"
+val bar = foo
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt
new file mode 100644
index 00000000000..1e85a3420f5
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt
@@ -0,0 +1,3 @@
+// INTENTION_TEXT: Remove single-expression string template
+
+val bar = "${1.hashCode().toString()}"
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt.after b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt.after
new file mode 100644
index 00000000000..25143a708fe
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt.after
@@ -0,0 +1,3 @@
+// INTENTION_TEXT: Remove single-expression string template
+
+val bar = 1.hashCode().toString()
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt
new file mode 100644
index 00000000000..366d5f4fd95
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt
@@ -0,0 +1,3 @@
+// INTENTION_TEXT: Remove single-expression string template
+
+val bar = "${1.hashCode()}"
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt.after b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt.after
new file mode 100644
index 00000000000..25143a708fe
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt.after
@@ -0,0 +1,3 @@
+// INTENTION_TEXT: Remove single-expression string template
+
+val bar = 1.hashCode().toString()
\ No newline at end of file
diff --git a/idea/testData/intentions/removeSingleExpressionStringTemplate/stringTemplateWithText.kt b/idea/testData/intentions/removeSingleExpressionStringTemplate/stringTemplateWithText.kt
new file mode 100644
index 00000000000..d3ddbf1a3de
--- /dev/null
+++ b/idea/testData/intentions/removeSingleExpressionStringTemplate/stringTemplateWithText.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: FALSE
+
+val foo = "foo"
+val bar = "text$foo"
\ 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 ce8a636d04f..df90a370410 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -8480,6 +8480,57 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
+ @TestMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class RemoveSingleExpressionStringTemplate extends AbstractIntentionTest {
+ public void testAllFilesPresentInRemoveSingleExpressionStringTemplate() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeSingleExpressionStringTemplate"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
+ }
+
+ @TestMetadata("emptyString.kt")
+ public void testEmptyString() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/emptyString.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("justString.kt")
+ public void testJustString() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/justString.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("multipleStringTemplate.kt")
+ public void testMultipleStringTemplate() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/multipleStringTemplate.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("singleExpressionStringTemplate.kt")
+ public void testSingleExpressionStringTemplate() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplate.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("singleExpressionStringTemplateWithMethodCall.kt")
+ public void testSingleExpressionStringTemplateWithMethodCall() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithMethodCall.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("singleExpressionStringTemplateWithNonStringType.kt")
+ public void testSingleExpressionStringTemplateWithNonStringType() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/singleExpressionStringTemplateWithNonStringType.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("stringTemplateWithText.kt")
+ public void testStringTemplateWithText() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeSingleExpressionStringTemplate/stringTemplateWithText.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/intentions/removeUnnecessaryParentheses")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)