diff --git a/open-java-format/src/main/java/com/palantir/javaformat/doc/Comment.java b/open-java-format/src/main/java/com/palantir/javaformat/doc/Comment.java index 38bd5ea49..124551df6 100644 --- a/open-java-format/src/main/java/com/palantir/javaformat/doc/Comment.java +++ b/open-java-format/src/main/java/com/palantir/javaformat/doc/Comment.java @@ -88,8 +88,13 @@ public State computeBreaks( CommentsHelper commentsHelper, int maxWidth, State state, Obs.ExplorationNode observationNode) { String text = commentsHelper.rewrite(tok, maxWidth, state.column()); @SuppressWarnings("for-rollout:NullAway") - int firstLineLength = text.length() - Iterators.getLast(Newlines.lineOffsetIterator(text)); - return state.withColumn(state.column() + firstLineLength) + int lastLineStart = Iterators.getLast(Newlines.lineOffsetIterator(text)); + int lastLineLength = text.length() - lastLineStart; + // rewrite() indents every line after the first to state.column(), so after a comment that spans lines the + // column is the length of its last line. Adding state.column() to it as well doubled the column for each + // further comment on that line. + int column = lastLineStart == 0 ? state.column() + lastLineLength : lastLineLength; + return state.withColumn(column) .addNewLines(Iterators.size(Newlines.lineOffsetIterator(text))) .withTokState(this, ImmutableTokState.of(text)); } 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 7e8bf6282..e5a15e750 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 @@ -491,4 +491,21 @@ void formatsDeeplyNestedCallsQuickly() { assertTimeoutPreemptively(Duration.ofSeconds(10), () -> formatter.formatSource(input)); } + + @Test + void indentsCommentsThatShareALineLinearly() throws FormatterException { + // Commented-out code that had javadoc in it puts many multi-line comments on one line: "*//** javadoc *//*". + // Each comment's continuation lines are indented to the column where the comment starts, and the column after + // a comment used to be counted from where it started plus its last line, which already holds that indent. So + // every comment started twice as far right as the one before, and these sixteen came out as 4.3 MB. + StringBuilder input = new StringBuilder("/*\nclass X {\n"); + for (int i = 0; i < 16; i++) { + input.append("\t*//** javadoc *//*\n\tpublic void foo(Bar bar) {}\n\n"); + } + input.append("}*/\n"); + Formatter formatter = Formatter.createFormatter( + JavaFormatterOptions.builder().style(Style.OJF).build()); + + assertThat(formatter.formatSource(input.toString()).length()).isLessThan(10_000); + } } diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-36-multiline-comments-on-one-line.input b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-36-multiline-comments-on-one-line.input new file mode 100644 index 000000000..d10f4fd61 --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-36-multiline-comments-on-one-line.input @@ -0,0 +1,14 @@ +/* +class X { + *//** javadoc *//* + public void foo(Bar bar) {} + + *//** javadoc *//* + public void foo(Bar bar) {} + + *//** javadoc *//* + public void foo(Bar bar) {} + + *//** javadoc *//* + public void foo(Bar bar) {} +}*/ diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-36-multiline-comments-on-one-line.output b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-36-multiline-comments-on-one-line.output new file mode 100644 index 000000000..84d857ff0 --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-36-multiline-comments-on-one-line.output @@ -0,0 +1,14 @@ +/* +class X { + *//** javadoc *//* + public void foo(Bar bar) {} + + *//** javadoc *//* + public void foo(Bar bar) {} + + *//** javadoc *//* + public void foo(Bar bar) {} + + *//** javadoc *//* + public void foo(Bar bar) {} + }*/