diff --git a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java index 44c6c8b3e..36b015bc2 100644 --- a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java +++ b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaOutput.java @@ -50,9 +50,11 @@ public final class JavaOutput extends Output { private final InputMetadata inputMetadata; private int iLine = 0; // Closest corresponding line number on input. private int lastK = -1; // Last {@link Tok} index output. - private int spacesPending = 0; private int newlinesPending = 0; private StringBuilder lineBuilder = new StringBuilder(); + // Spaces and tabs seen since the last non-blank character. Written out in front of the next one, so that a line + // never ends in whitespace: trailing tabs inside a comment were kept before, and only a second run removed them. + private StringBuilder spacesPending = new StringBuilder(); /** * {@code JavaOutput} constructor. @@ -99,7 +101,7 @@ public void append(State state, String text, Range range) { if (newlinesPending == 0) { ++newlinesPending; } - spacesPending = 0; + spacesPending = new StringBuilder(); } else { boolean rangesSet = false; int textN = text.length(); @@ -107,7 +109,10 @@ public void append(State state, String text, Range range) { char c = text.charAt(i); switch (c) { case ' ': - ++spacesPending; + spacesPending.append(' '); + break; + case '\t': + spacesPending.append('\t'); break; case '\r': if (i + 1 < text.length() && text.charAt(i + 1) == '\n') { @@ -115,7 +120,7 @@ public void append(State state, String text, Range range) { } // falls through case '\n': - spacesPending = 0; + spacesPending = new StringBuilder(); ++newlinesPending; break; default: @@ -128,9 +133,9 @@ public void append(State state, String text, Range range) { rangesSet = false; --newlinesPending; } - while (spacesPending > 0) { - lineBuilder.append(' '); - --spacesPending; + if (spacesPending.length() > 0) { + lineBuilder.append(spacesPending); + spacesPending = new StringBuilder(); } lineBuilder.append(c); if (!range.isEmpty()) { @@ -152,7 +157,7 @@ public void append(State state, String text, Range range) { @Override public void indent(int indent) { - spacesPending = indent; + spacesPending.append(" ".repeat(indent)); } /** Flush any incomplete last line, then add the EOF token into our data structures. */ @@ -354,7 +359,7 @@ public String toString() { return MoreObjects.toStringHelper(this) .add("iLine", iLine) .add("lastK", lastK) - .add("spacesPending", spacesPending) + .add("spacesPending", spacesPending.toString().replace("\t", "\\t")) .add("newlinesPending", newlinesPending) .add("inputMetadata", inputMetadata) .add("super", super.toString()) diff --git a/open-java-format/src/test/java/com/palantir/javaformat/java/FormatterTest.java b/open-java-format/src/test/java/com/palantir/javaformat/java/FormatterTest.java index e5a15e750..ae8796bd9 100644 --- a/open-java-format/src/test/java/com/palantir/javaformat/java/FormatterTest.java +++ b/open-java-format/src/test/java/com/palantir/javaformat/java/FormatterTest.java @@ -508,4 +508,14 @@ void indentsCommentsThatShareALineLinearly() throws FormatterException { assertThat(formatter.formatSource(input.toString()).length()).isLessThan(10_000); } + + @Test + public void removeTrailingTabsInComments() throws FormatterException { + String input = "class Foo {\n void f() {\n int x = 0; // comment\t\t\t\n return;\n }\n}\n"; + String expected = "class Foo {\n void f() {\n int x = 0; // comment\n return;\n }\n}\n"; + Formatter formatter = Formatter.createFormatter( + JavaFormatterOptions.builder().style(Style.OJF).build()); + + assertThat(formatter.formatSource(input)).isEqualTo(expected); + } }