From 6675d7814c8f04d40ccbfaa9c1d8bb3c476435af Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Wed, 20 Jun 2018 22:23:04 +0900 Subject: [PATCH] KT-14779 Inspection to replace String.format with string templates (#1645) * Add inspection to replace String.format with string templates #KT-14779 Fixed * KT-14779 Fixed --- .../ReplaceStringFormatWithLiteral.html | 5 ++ idea/src/META-INF/plugin.xml | 9 ++ idea/src/META-INF/plugin.xml.172 | 9 ++ idea/src/META-INF/plugin.xml.173 | 9 ++ idea/src/META-INF/plugin.xml.182 | 9 ++ idea/src/META-INF/plugin.xml.as31 | 9 ++ idea/src/META-INF/plugin.xml.as32 | 9 ++ ...eplaceStringFormatWithLiteralInspection.kt | 90 +++++++++++++++++++ .../.inspection | 1 + .../formattableArgs.kt | 17 ++++ .../invalidArgs.kt | 8 ++ .../javaStringFormat.kt | 8 ++ .../javaStringFormat.kt.after | 8 ++ .../javaStringFormat2.kt | 10 +++ .../javaStringFormat2.kt.after | 10 +++ .../replaceStringFormatWithLiteral/noArgs.kt | 6 ++ .../notStringPlaceFolder.kt | 9 ++ .../notStringPlaceFolder2.kt | 9 ++ .../rawStringFormat.kt | 9 ++ .../replaceStringFormatWithLiteral/simple.kt | 12 +++ .../simple.kt.after | 12 +++ .../LocalInspectionTestGenerated.java | 58 ++++++++++++ 22 files changed, 326 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/ReplaceStringFormatWithLiteral.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceStringFormatWithLiteralInspection.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/.inspection create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/formattableArgs.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/invalidArgs.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat.kt.after create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/javaStringFormat2.kt.after create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/noArgs.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/notStringPlaceFolder2.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/rawStringFormat.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt create mode 100644 idea/testData/inspectionsLocal/replaceStringFormatWithLiteral/simple.kt.after 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)