diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/StringRules.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/StringRules.java index af81c81b..fcd21767 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/StringRules.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/StringRules.java @@ -9,10 +9,12 @@ import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.base.Utf8; import com.google.common.collect.Streams; +import com.google.errorprone.annotations.FormatMethod; import com.google.errorprone.refaster.Refaster; import com.google.errorprone.refaster.annotation.AfterTemplate; import com.google.errorprone.refaster.annotation.AlsoNegation; import com.google.errorprone.refaster.annotation.BeforeTemplate; +import com.google.errorprone.refaster.annotation.Repeated; import com.google.errorprone.refaster.annotation.UseImportPolicy; import java.util.Arrays; import java.util.Collection; @@ -348,4 +350,23 @@ final class StringRules { return string.startsWith(prefix, fromIndex); } } + + /** + * Prefer {@link String#formatted(Object...)} over {@link String#format(String, Object...)}, as + * the former works more nicely with text blocks, while the latter does not appear advantageous in + * any circumstance (assuming one targets JDK 15+). + */ + static final class StringFormatted { + @BeforeTemplate + @FormatMethod + String before(String format, @Repeated Object args) { + return String.format(format, args); + } + + @AfterTemplate + @FormatMethod + String after(String format, @Repeated Object args) { + return format.formatted(args); + } + } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestInput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestInput.java index d189a5df..5e1c2c17 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestInput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestInput.java @@ -124,4 +124,8 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase { boolean testStringStartsWith() { return "foo".substring(1).startsWith("bar"); } + + String testStringFormatted() { + return String.format("%s%s", "foo", "bar"); + } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestOutput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestOutput.java index 3717a85f..09f58506 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestOutput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/StringRulesTestOutput.java @@ -124,4 +124,8 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase { boolean testStringStartsWith() { return "foo".startsWith("bar", 1); } + + String testStringFormatted() { + return "%s%s".formatted("foo", "bar"); + } }