From ceb6c297601049400e9fa976b9d291b40719210d Mon Sep 17 00:00:00 2001 From: Md Tanvir Alam Date: Thu, 1 Oct 2026 00:23:51 -0400 Subject: [PATCH] Make long-string wrapping idempotent after format StringWrapper.applyReplacements chooses '+' continuation indents from the string literal's start column. When the literal is prefixed (e.g. after `return`), that indent disagrees with the pretty-printer, so a second format pass rewrote the file (issue #935). Format once more after applying wrap replacements so the output is stable under subsequent formatSource / CLI runs. --- .../googlejavaformat/java/StringWrapper.java | 8 +++++++ .../java/StringWrapperTest.java | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java index 52d55adba..f530c2c5f 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java @@ -97,6 +97,14 @@ static String wrap(final int columnLimit, String input, Formatter formatter) } } + // applyReplacements chooses continuation indents from the string literal's start column. + // The pretty-printer may break the '+' at a different column (for example relative to + // `return`), so format once more. Without this, a second format pass changes indentation + // and wrapping is not idempotent (https://github.com/google/google-java-format/issues/935). + if (!result.equals(input)) { + result = formatter.formatSource(result); + } + return result; } diff --git a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java index afc1533f4..d8647721c 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java @@ -209,4 +209,28 @@ public class T { String actual = StringWrapper.wrap(100, input, new Formatter()); assertThat(actual).isEqualTo(expected); } + + /** + * Wrapping a long string that does not start at the beginning of its statement (e.g. after + * {@code return}) must produce output that is stable under a subsequent {@link + * Formatter#formatSource} pass. See https://github.com/google/google-java-format/issues/935. + */ + @Test + public void wrapThenFormatIsIdempotentForPrefixedString() throws Exception { + String input = + """ + public class JavaFormatterExample { + + public static String veryLongString() { + return "Very, very, very, very, very, very, very, very, very, very, very long string that will need to be split"; + } + } + """; + Formatter formatter = new Formatter(); + String wrapped = StringWrapper.wrap(100, formatter.formatSource(input), formatter); + String reformatted = formatter.formatSource(wrapped); + assertThat(reformatted).isEqualTo(wrapped); + // And a second wrap+format round trip must not change anything either. + assertThat(StringWrapper.wrap(100, reformatted, formatter)).isEqualTo(wrapped); + } }