diff --git a/idea/resources/inspectionDescriptions/ReplaceToStringWithStringTemplate.html b/idea/resources/inspectionDescriptions/ReplaceToStringWithStringTemplate.html
new file mode 100644
index 00000000000..1d1d6dae28a
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/ReplaceToStringWithStringTemplate.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports toString function calls replaceable with string template.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 4211a54f10d..d07033c49ff 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2900,6 +2900,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.172 b/idea/src/META-INF/plugin.xml.172
index ff371b58ad9..0b6483e17f2 100644
--- a/idea/src/META-INF/plugin.xml.172
+++ b/idea/src/META-INF/plugin.xml.172
@@ -2898,6 +2898,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173
index 0134669dc32..37720d79315 100644
--- a/idea/src/META-INF/plugin.xml.173
+++ b/idea/src/META-INF/plugin.xml.173
@@ -2898,6 +2898,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.182 b/idea/src/META-INF/plugin.xml.182
index 89fe893b8a4..329fc96bf59 100644
--- a/idea/src/META-INF/plugin.xml.182
+++ b/idea/src/META-INF/plugin.xml.182
@@ -2899,6 +2899,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31
index bd56da26a6a..3b3cadef1c6 100644
--- a/idea/src/META-INF/plugin.xml.as31
+++ b/idea/src/META-INF/plugin.xml.as31
@@ -2898,6 +2898,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32
index ceace052246..73934004f5c 100644
--- a/idea/src/META-INF/plugin.xml.as32
+++ b/idea/src/META-INF/plugin.xml.as32
@@ -2898,6 +2898,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceToStringWithStringTemplateInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceToStringWithStringTemplateInspection.kt
new file mode 100644
index 00000000000..550b9e5dcc8
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceToStringWithStringTemplateInspection.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.inspections
+
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
+import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
+import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
+import org.jetbrains.kotlin.idea.intentions.toResolvedCall
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+class ReplaceToStringWithStringTemplateInspection : AbstractApplicabilityBasedInspection(
+ KtDotQualifiedExpression::class.java
+) {
+ override fun isApplicable(element: KtDotQualifiedExpression): Boolean {
+ if (element.receiverExpression !is KtReferenceExpression) return false
+ if (element.parent is KtBlockStringTemplateEntry) return false
+ return element.isToString()
+ }
+
+ override fun applyTo(element: PsiElement, project: Project, editor: Editor?) {
+ val expression = element.getParentOfType(strict = false) ?: return
+ val variable = expression.receiverExpression.text
+ element.replace(KtPsiFactory(element).createExpression("\"$$variable\""))
+ }
+
+ override fun inspectionText(element: KtDotQualifiedExpression) = "Should be replaced 'toString' with string template"
+
+ override fun inspectionTarget(element: KtDotQualifiedExpression) = element
+
+ override val defaultFixText = "Replace 'toString' with string template"
+
+ private fun KtDotQualifiedExpression.isToString(): Boolean {
+ val resolvedCall = toResolvedCall(BodyResolveMode.PARTIAL) ?: return false
+ val callableDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return false
+ return callableDescriptor.getDeepestSuperDeclarations().any { it.fqNameUnsafe.asString() == "kotlin.Any.toString" }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/.inspection b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/.inspection
new file mode 100644
index 00000000000..6b03c3c7f04
--- /dev/null
+++ b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.ReplaceToStringWithStringTemplateInspection
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/nonReference.kt b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/nonReference.kt
new file mode 100644
index 00000000000..5fc21684259
--- /dev/null
+++ b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/nonReference.kt
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+// PROBLEM: none
+fun test(): String {
+ return 1.toString()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt
new file mode 100644
index 00000000000..bda00904af8
--- /dev/null
+++ b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+fun test(): String {
+ val x = 1
+ return x.toString()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt.after b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt.after
new file mode 100644
index 00000000000..e15a79eaf50
--- /dev/null
+++ b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt.after
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+fun test(): String {
+ val x = 1
+ return "$x"
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/stringTemplate.kt b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/stringTemplate.kt
new file mode 100644
index 00000000000..aae8802c343
--- /dev/null
+++ b/idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/stringTemplate.kt
@@ -0,0 +1,6 @@
+// WITH_RUNTIME
+// PROBLEM: none
+fun test(): String {
+ val x = 1
+ return "Foo: ${x.toString()}"
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
index 86c06e1af8f..050dbba6df6 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
@@ -4206,6 +4206,34 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
+ @TestMetadata("idea/testData/inspectionsLocal/replaceToStringWithStringTemplate")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ReplaceToStringWithStringTemplate extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInReplaceToStringWithStringTemplate() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceToStringWithStringTemplate"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("nonReference.kt")
+ public void testNonReference() throws Exception {
+ runTest("idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/nonReference.kt");
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/simple.kt");
+ }
+
+ @TestMetadata("stringTemplate.kt")
+ public void testStringTemplate() throws Exception {
+ runTest("idea/testData/inspectionsLocal/replaceToStringWithStringTemplate/stringTemplate.kt");
+ }
+ }
+
@TestMetadata("idea/testData/inspectionsLocal/replaceToWithInfixForm")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)