Repository navigation
Partial formatting should reflow only long strings inside the requested ranges #177
Description
Upstream: google/google-java-format#1514
Kind: bug | Priority: medium
google-java-format#1514 (merged 2026-10-30, copybara export) fixes google-java-format#1114: with --lines, --offset/--length or the library range APIs, only the requested ranges were reformatted, yet every long string literal in the file was still reflowed. Tools that format only changed lines (the git-diff wrapper script, editor integrations) therefore produced unrelated edits elsewhere in the file. Upstream maps the requested ranges onto the formatted output and hands them to StringWrapper, which now reflows only literals that intersect them; the offset mapping was extracted from Cleanups into a shared Edit class.
Why it matters: our code has the same flaw. In FormatFileCallable.formatFile the CLI formats the requested ranges and then calls StringWrapper.wrap on the whole file, so a long string on a line outside the range is wrapped anyway. The replacements path (IDE plugins) is only half guarded: StringWrapper.linesNeedWrapping checks whether a long line overlaps the range, but once it does, wrap is run on the entire text and the result replaces the whole file, again touching strings outside the range. Running with --lines on a changed line is the normal workflow in IDEs and pre-commit hooks, so this produces noisy diffs.
Before (how it is formatted today; derived from our code path, not run):
class Test {
void foo() {
int a = 1;
System.err.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
}
}Formatting only line 3 (--lines 3:3) also rewrites line 4:
System.err.println(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");After (with the change):
class Test {
void foo() {
int a = 1;
System.err.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
}
}Line 4 is left as it was because it is outside the requested range; formatting --lines 4:4 would still wrap it.
Affected files in our repo:
- open-java-format/src/main/java/com/palantir/javaformat/java/StringWrapper.java (
wrap,wrapOnce,getReflowReplacements,linesNeedWrapping) - open-java-format/src/main/java/com/palantir/javaformat/java/FormatFileCallable.java (
call,formatFile) - open-java-format/src/main/java/com/palantir/javaformat/java/Formatter.java (
formatSourceAndFixImports, which wraps the whole file)
The upstream diff will not apply cleanly: we have no Cleanups or Edit classes (see the existing ticket on the unified cleanups pipeline), and our StringWrapper works from a TreeRangeMap of replacements rather than upstream's structure. The idea ports directly, though: our getReflowReplacements already produces per-literal ranges, so they can be filtered by overlap with the formatted-output ranges before applying.
Suggested action: port the idea. Add a range filter to StringWrapper.wrap and pass the mapped requested ranges from FormatFileCallable; keep whole-file behaviour when no range is given. Upstream's StringWrapperTest and MainTest cases from the PR are a good source of tests.
Filed from an upstream-watch ticket after manual review.
Activity