diff --git a/idea/resources/inspectionDescriptions/ReplaceStringFormatWithLiteral.html b/idea/resources/inspectionDescriptions/ReplaceStringFormatWithLiteral.html new file mode 100644 index 00000000000..b4f58789dfe --- /dev/null +++ b/idea/resources/inspectionDescriptions/ReplaceStringFormatWithLiteral.html @@ -0,0 +1,5 @@ + + +This inspection reports String.format call can be replaced with string templates. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 430258c85a9..4211a54f10d 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2882,6 +2882,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + + + + + + + + + + + String.format("foo is %s, bar is %s.", foo, bar) +} + +class Foo(private val value: Int) : Formattable { + override fun formatTo(formatter: Formatter?, flags: Int, width: Int, precision: Int) { + formatter?.out()?.append("[$value]") + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/invalidArgs.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/invalidArgs.kt new file mode 100644 index 00000000000..6306240bdff --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/invalidArgs.kt @@ -0,0 +1,8 @@ +// PROBLEM: none +// WITH_RUNTIME + +fun test() { + val foo = 1 + + String.format("foo is %s, bar is %s.", foo) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt new file mode 100644 index 00000000000..8d0ace6c703 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt @@ -0,0 +1,8 @@ +// RUNTIME_WITH_FULL_JDK + +fun test() { + val foo = 1 + val bar = 2 + + java.lang.String.format("foo is %s, bar is %s.", foo, bar) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt.after b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt.after new file mode 100644 index 00000000000..46a31942d27 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt.after @@ -0,0 +1,8 @@ +// RUNTIME_WITH_FULL_JDK + +fun test() { + val foo = 1 + val bar = 2 + + "foo is $foo, bar is $bar." +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt new file mode 100644 index 00000000000..88464b30207 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt @@ -0,0 +1,10 @@ +// RUNTIME_WITH_FULL_JDK + +import java.lang.String.format + +fun test() { + val foo = 1 + val bar = 2 + + format("foo is %s, bar is %s.", foo, bar) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt.after b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt.after new file mode 100644 index 00000000000..78aa96796d9 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt.after @@ -0,0 +1,10 @@ +// RUNTIME_WITH_FULL_JDK + +import java.lang.String.format + +fun test() { + val foo = 1 + val bar = 2 + + "foo is $foo, bar is $bar." +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/noArgs.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/noArgs.kt new file mode 100644 index 00000000000..a28c1adb160 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/noArgs.kt @@ -0,0 +1,6 @@ +// PROBLEM: none +// WITH_RUNTIME + +fun test() { + String.format("%%") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder.kt new file mode 100644 index 00000000000..1d48d77fb56 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder.kt @@ -0,0 +1,9 @@ +// PROBLEM: none +// WITH_RUNTIME + +fun test() { + val foo = 1 + val bar = 2 + + String.format("foo is %s, bar is %d.", foo, bar) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder2.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder2.kt new file mode 100644 index 00000000000..096d3b7680b --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder2.kt @@ -0,0 +1,9 @@ +// PROBLEM: none +// WITH_RUNTIME + +fun test() { + val foo = 1 + val bar = 2 + + String.format("foo is %s, bar is %s.%n", foo, bar) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/rawStringFormat.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/rawStringFormat.kt new file mode 100644 index 00000000000..b2ca510d5c5 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/rawStringFormat.kt @@ -0,0 +1,9 @@ +// PROBLEM: none +// WITH_RUNTIME + +fun test() { + val foo = 1 + val bar = 2 + + String.format("""foo is %s, bar is %s.%n""", foo, bar) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt new file mode 100644 index 00000000000..ffff1ad8ece --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// HIGHLIGHT: INFORMATION + +fun test() { + val foo = 1 + + String.format("foo is %s, bar is %s.", foo, Bar().value) +} + +class Bar { + val value = 2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt.after b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt.after new file mode 100644 index 00000000000..82e6bf73e6a --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt.after @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// HIGHLIGHT: INFORMATION + +fun test() { + val foo = 1 + + "foo is $foo, bar is ${Bar().value}." +} + +class Bar { + val value = 2 +} \ 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 b5fd01b1f66..86c06e1af8f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -4148,6 +4148,64 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceStringFormatWithLiteral extends AbstractLocalInspectionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInReplaceStringFormatWithLiteral() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("formattableArgs.kt") + public void testFormattableArgs() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/formattableArgs.kt"); + } + + @TestMetadata("invalidArgs.kt") + public void testInvalidArgs() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/invalidArgs.kt"); + } + + @TestMetadata("javaStringFormat.kt") + public void testJavaStringFormat() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt"); + } + + @TestMetadata("javaStringFormat2.kt") + public void testJavaStringFormat2() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt"); + } + + @TestMetadata("noArgs.kt") + public void testNoArgs() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/noArgs.kt"); + } + + @TestMetadata("notStringPlaceFolder.kt") + public void testNotStringPlaceFolder() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder.kt"); + } + + @TestMetadata("notStringPlaceFolder2.kt") + public void testNotStringPlaceFolder2() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder2.kt"); + } + + @TestMetadata("rawStringFormat.kt") + public void testRawStringFormat() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/rawStringFormat.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt"); + } + } + @TestMetadata("idea/testData/inspectionsLocal/replaceToWithInfixForm") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)