Skip to content

Fix print idempotency for Javadoc <pre><code> blocks on Java 25#7464

Merged
knutwannheden merged 1 commit intomainfrom
crisp-bison
Apr 23, 2026
Merged

Fix print idempotency for Javadoc <pre><code> blocks on Java 25#7464
knutwannheden merged 1 commit intomainfrom
crisp-bison

Conversation

@knutwannheden
Copy link
Copy Markdown
Contributor

Motivation

Parsing Javadoc comments containing <pre><code> blocks with a newline after the opening tag failed the parser's print idempotency check on Java 25 (but not on Java 8/11/17/21). This surfaced against Google Dagger in a Moderne CLI run — 18 Java files in google/dagger failed to parse with IllegalStateException: ... is not print idempotent, all of them Javadoc comments in the common style:

/**
 * <pre><code>
 *   class Outer {
 *     static class Inner {}
 *   }
 * </code></pre>
 */

Root cause: Java 25's DocCommentTree strips leading whitespace (including newlines) from text nodes, so the raw source has \n characters that the DCText / DCRawText body does not. In ReloadableJava25JavadocVisitor.visitText, the else branch blindly advanced the cursor past these \n characters without emitting a corresponding LineBreak. The unconsumed LineBreak then got dumped at the end of the comment by the trailing-lineBreaks flush, producing a stray * line before the closing */.

Summary

  • ReloadableJava25JavadocVisitor.visitText: before processing each character from the text node, consume any \n in the source that is missing from the node and emit the corresponding LineBreak.
  • Add four parser idempotency tests in JavadocTest covering variants of <pre><code> blocks (newline after opening tag, two consecutive blocks, blocks containing {@literal} inline tags, block starting on the same line as preceding text).

Test plan

  • ./gradlew :rewrite-java-25:test :rewrite-java-25:compatibilityTest — all green, including the four new preCodeBlock* tests
  • CI across all Java versions

Java 25's `DocCommentTree` strips leading whitespace (including newlines)
from text nodes, so the source string had a `\n` that the `DCText` body
didn't. `visitText` silently advanced past it without emitting a
`LineBreak`, and the orphaned line break was flushed at the end of the
comment as a stray ` *` line.

Consume any source newline that's missing from the text node before
processing each character, emitting the corresponding `LineBreak`.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Apr 23, 2026
@knutwannheden knutwannheden merged commit 585edc3 into main Apr 23, 2026
1 check passed
@knutwannheden knutwannheden deleted the crisp-bison branch April 23, 2026 16:46
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant