Do not inline a lambda body whose closing paren carries a comment - #77
Merged
Merged
Conversation
A "//" comment on its own line before the "))" that close a lambda's parenthesized body and the call around it was joined onto the code line before it, and the "))" ended up inside the comment, so the output no longer parsed (#62, palantir#1792). The command line noticed only because its import pass parses the result again and reported a position in the output; a caller of formatSource got the text as it was. An expression lambda's body is laid out by handle_breakOnlyIfInnerLevelsThenFitOnOneLine: when the body does not fit after "->" but its first line does, tryInlinePrefixOntoCurrentLine lays the body's level out "on one line" through tryToLayOutLevelOnOneLine, which marks every break of that level as not taken and only lets the inner levels break. The comments before the closing ")" belong to that same level, with forced breaks around them, and a forced break laid out flat is what put the comment on the code line. The width of the docs before the last inner level was checked, and a forced break there fails that check; the docs after it were not checked at all. The check is now made for the trailing docs too, the way tryBreakInnerLevel already refuses a suffix of infinite width: a body with a comment before its closing token is not inlined and breaks normally, so the body starts on the line after "->" and the comments keep their own lines at the body's indent, as they already did when the body's first line did not fit. A block comment in the same place was written without a space in front of it and moved on a second run; it now gets its own line as well. The golden holds the reporter's input, the same shape as a plain call, and the block comment. The 15,747 files of the JDK 21 sources format exactly as before: none of them has a comment before "))".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #62, which mirrors palantir#1792 (the reporter also points at palantir#1152).
The bug
A
//comment on its own line before the))that close a lambda's parenthesized body and the call around it was joined onto the code line before it, and the))ended up inside the comment:The output no longer parsed. The command line noticed only because its import pass parses the result again, and reported
error: ')' expectedat a position in the output; a caller offormatSourcegot the text as it was.Why
An expression lambda's body is laid out by
handle_breakOnlyIfInnerLevelsThenFitOnOneLine. When the body does not fit after->but its first line does,tryInlinePrefixOntoCurrentLinelays the body's level out "on one line" throughtryToLayOutLevelOnOneLine, which marks every break of that level as not taken and only lets the inner levels break. The comments before the closing)belong to that same level, with forced breaks around them, and a forced break laid out flat is exactly what put the comment on the code line. The docs before the last inner level were checked for that (a forced break makes their width infinite); the docs after it were not checked at all. google-java-format has no such inlining, which is why it lays the input out correctly.The fix
tryInlinePrefixOntoCurrentLinenow refuses a level whose trailing docs have infinite width, the same checktryBreakInnerLevelalready makes for its suffix. Such a body is not inlined and breaks normally: it starts on the line after->, and the comments keep their own lines at the body's indent, which is what the formatter already did when the body's first line did not fit either:A block comment in the same place went through the same path: it came out glued to the code without a space,
bbb(i)/* block */));, and moved on a second run. It gets its own line now as well.Checked
ojf-issue-62-comment-before-lambda-close-parensholds the reporter's input, the same shape as a plain call, and the block comment. It fails on main (--skip-*flags show the raw output) and passes with the change, and its output is stable on a second run.//comment inside the body, a comment before the single)of a call, a parenthesized argument that is not a lambda, a short body that already moved after->, and a statement lambda with a comment before}../gradlew :open-java-format:teston JDK 21: 1541 tests, all green.)), and the five with a comment before a single)do not change.Version
Only input that failed today, or came out glued and unstable, formats differently, so this is a bug fix in the 2.x sense.