Repository navigation
Keep //$NON-NLS-n$ markers valid: no inserted space, each marker on the line of its string - #150
Merged
Merged
Conversation
…t that fits on one line A trailing line comment lands in the level of the statement's last break, while its forced line break lands in the enclosing level. When that level fits on one line it is written from its flat text, and Comment.computeFlat added the space after the slashes itself, bypassing the exemption that JavaCommentsHelper.rewrite has for the IDE markers: `String a = "x"; //$NON-NLS-1$` came out as `// $NON-NLS-1$`, which Eclipse no longer recognises. The missing-space rule is now one method, JavaCommentsHelper.addMissingSpace, applied by both paths, and the comment's width follows its flat text instead of a hand-maintained + 1. A trailing `///` comment that already had its space is no longer turned into `// /` either: 4 of the 15,747 JDK 21 sources change, all that way. The tests were written first: trailingLineCommentGetsItsMissingSpaceExceptIdeMarkers and the ojf-issue-23-non-nls-trailing-marker fixture failed before the change. The first of the three cases of #23. Same defect upstream: google/google-java-format#221, google/google-java-format#361.
… statement is wrapped or reflowed Eclipse numbers a marker by the position of its literal on the line and reads it only there. The formatter left every marker of a wrapped call on the call's last line, and gave a reflowed literal one marker, on its last piece. OpsBuilder.build now pairs each marker of a markers-only trailing comment with the n-th string literal of the comment's input line, within the same partial-format region, and puts a zero-text ReservedWidth after that literal, so the layout counts the marker on the literal's line and a second run changes nothing. JavaOutput.appendNonNlsMarkers writes each paired marker at the end of its literal's output line, numbered by the literal's position among the string literals written there; a marker whose number has no literal stays where it was. JavaCommentsHelper never wraps a comment of markers. StringWrapper recomputes the markers of a reflowed chain's line from the new line structure, one marker after every piece and the markers of the literals before and after the chain renumbered for their lines, and reserves their room per line; a mixed comment, a second changing chain on the line, or a chain that ends in a text block leaves the markers alone. The tests were written first: the fixtures ojf-issue-23-wrapped-arguments, ojf-issue-23-reflowed-literal and ojf-issue-23-marked-literals, with nonNlsMarkersStayOnTheLineOfTheirLiteral and aRunOfNonNlsMarkersIsNeverWrapped, failed before the change. None of the 15,747 JDK 21 sources changes: the JDK carries no Eclipse markers. Fixes #23. Same defect upstream: google/google-java-format#221, google/google-java-format#361.
The marker code used Guava's ImmutableList for its lists of marker numbers and literal indices. List.of, List.copyOf and Stream.toList give unmodifiable lists without it, so the signatures take and return List. The field in Comment carries the Immutable suppression the other doc nodes use for their effectively immutable state.
The fixtures exercise the marker code end to end only. NonNlsMarkersTest pins which comments count as markers only, the order and the places in which the numbers are read, and the spelling of a marker; ReservedWidthTest pins that a reservation takes its width on the line and nothing else; the two JavaCommentsHelperTest cases pin the missing-space rule and its exemptions.
google/MOE, the tool whose markers the line-comment wrapper kept on one line, has been dead for years. Its special case goes, with the test that pinned it; only the NON-NLS marker runs stay unwrapped.
This was referenced Oct 25, 2026
The fork's own files carry the Apache 2.0 header without a copyright line. The four files this change adds were created with a Palantir one; CLAUDE.md records the rule, and #154 covers the rest of the tree.
Comment carried the annotation and needed a suppression for its List field, and ReservedWidth had taken the annotation from its sibling nodes. Doc itself is not annotated, so the check adds nothing here: the nodes are immutable by construction.
The locals this change added declare their type with var where the initializer gives it unchanged. The loop variables over a List<Integer> keep int, so that they are not boxed, and the lambda keeps its target type.
CLAUDE.md: plain java.util collections instead of Guava's immutable ones, javax.annotation.Nullable as the one nullability annotation, var for locals, no Error Prone @immutable, and the Apache header without a copyright line on a new file.
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.
Eclipse marks a string literal that is deliberately not externalised with a trailing
//$NON-NLS-n$comment, wherenis the position of the literal on its line. Eclipse recognises a marker only with that exact spelling and only on the line of its literal. The formatter broke this in three ways (#23); this fixes all three, in two commits.Case 1: a space was inserted into a trailing marker
String a = "x"; //$NON-NLS-1$came out asString a = "x"; // $NON-NLS-1$. A trailing line comment lands in the level of the statement's last break, and that level is written from its flat text when it fits on one line, soComment.computeFlat()added the space itself, without the exemption thatJavaCommentsHelper.rewrite()has for//noinspectionand//$NON-NLS-n$. The missing-space rule is now one method,JavaCommentsHelper.addMissingSpace, applied by both paths, and the comment's width follows its flat text. A trailing///comment that already had its space is no longer turned into// /either.Cases 2 and 3: markers left behind when a statement is wrapped or reflowed
Before:
After:
OpsBuilder.buildpairs each marker of a markers-only trailing comment with the n-th string literal of the comment's input line (within the same partial-format region) and puts a zero-textReservedWidthafter that literal, so the layout already counts the marker on the literal's line and a second run changes nothing.JavaOutput.appendNonNlsMarkerswrites each paired marker at the end of its literal's output line, numbered by the literal's position among the string literals written there; a marker whose number has no literal stays where it was. A comment of markers is never wrapped.StringWrapperrecomputes the markers of a reflowed chain's line from the new line structure: one marker after every piece, the markers of literals before and after the chain renumbered for their lines, with their room reserved per line.Left alone by design: a mixed comment such as
// note //$NON-NLS-1$, a line on which two reflowed chains change (only reachable with a wrap limit below the formatter's), and a chain that ends in a text block.Also in this PR
List(List.of,List.copyOf,Stream.toList), not Guava'sImmutableList.// MOE:comments on one line: google/MOE has been dead for years, so such a comment wraps like any other.CLAUDE.md:varfor locals, no Error Prone@Immutableon the marker nodes, and the Apache header without a copyright line on the four new files (Audit the license headers of all source files #154 covers the rest of the tree).Tests
Written first, and failing before each change:
trailingLineCommentGetsItsMissingSpaceExceptIdeMarkerswith the fixtureojf-issue-23-non-nls-trailing-marker(case 1);nonNlsMarkersStayOnTheLineOfTheirLiteral,aRunOfNonNlsMarkersIsNeverWrappedand the fixturesojf-issue-23-wrapped-arguments,ojf-issue-23-reflowed-literalandojf-issue-23-marked-literals(cases 2 and 3). The fixtures also run the idempotency checks. Unit tests cover the utility classes:NonNlsMarkersTest,ReservedWidthTest, and twoJavaCommentsHelperTestcases foraddMissingSpace.Verification
./gradlew testover all modules is green on the rebased branch;./gradlew formatDiffchanges nothing./// ...comment that the flat path used to turn into// / ...; cases 2 and 3 change none, as the JDK carries no Eclipse markers.Fixes #23. The same defect upstream: google/google-java-format#221, google/google-java-format#361.