From 969310f134b3cda6d177b6e0b8ff22c9788f4b66 Mon Sep 17 00:00:00 2001 From: Jordan Kiesel Date: Sat, 30 May 2026 22:47:31 -0600 Subject: [PATCH] fix: proper handling of comments on lambda and parenthesized expressions --- src/comments.ts | 41 ++++++++++++++++- src/printer.ts | 3 +- src/printers/expressions.ts | 8 ++-- .../unit-test/comments/expression/_input.java | 4 ++ .../comments/expression/_output.java | 4 ++ .../lambda/arrow-parens-always/_input.java | 41 +++++++++++++++++ .../lambda/arrow-parens-always/_output.java | 46 +++++++++++++++++++ .../lambda/arrow-parens-avoid/_input.java | 41 +++++++++++++++++ .../lambda/arrow-parens-avoid/_output.java | 46 +++++++++++++++++++ 9 files changed, 228 insertions(+), 6 deletions(-) diff --git a/src/comments.ts b/src/comments.ts index 612dd340e..9fab3228f 100644 --- a/src/comments.ts +++ b/src/comments.ts @@ -71,7 +71,7 @@ export function willPrintOwnComments(path: AstPath): boolean { return isMember(path.node) && !printer.hasPrettierIgnore(path); } -export function canAttachComment(node: SyntaxNode) { +export function canAttachComment(node: SyntaxNode, ancestors: SyntaxNode[]) { if (!node.isNamed) { return isBinaryOperator(node); } @@ -81,11 +81,25 @@ export function canAttachComment(node: SyntaxNode) { case SyntaxType.FormalParameters: case SyntaxType.Modifier: case SyntaxType.MultilineStringFragment: - case SyntaxType.ParenthesizedExpression: case SyntaxType.Program: case SyntaxType.StringFragment: case SyntaxType.Visibility: return false; + case SyntaxType.ParenthesizedExpression: { + const [parent] = ancestors; + return !( + parent.isNamed && + [ + SyntaxType.DoStatement, + SyntaxType.IfStatement, + SyntaxType.SwitchExpression, + SyntaxType.SynchronizedStatement, + SyntaxType.TryStatement, + SyntaxType.TryWithResourcesStatement, + SyntaxType.WhileStatement + ].includes(parent.type) + ); + } default: return true; } @@ -102,6 +116,7 @@ export function handleLineComment( handleIfStatementComments, handleJumpStatementComments, handleLabeledStatementComments, + handleLambdaExpressionComments, handleMemberChainComments, handleModifiersComments, handleNameComments, @@ -194,6 +209,28 @@ function handleLabeledStatementComments(commentNode: CommentNode) { return false; } +function handleLambdaExpressionComments(commentNode: CommentNode) { + const { enclosingNode, precedingNode, followingNode } = commentNode; + if ( + enclosingNode?.type === SyntaxType.LambdaExpression && + precedingNode && + followingNode && + enclosingNode.children.find(({ type }) => type === "->")!.end.index < + commentNode.start.index + ) { + if (followingNode.type === SyntaxType.Block) { + if (followingNode.namedChildren.length) { + util.addLeadingComment(followingNode.namedChildren[0], commentNode); + } else { + util.addDanglingComment(followingNode, commentNode, undefined); + } + } else { + util.addLeadingComment(followingNode, commentNode); + } + return true; + } +} + function handleMemberChainComments(commentNode: CommentNode) { const { enclosingNode, precedingNode, followingNode } = commentNode; if ( diff --git a/src/printer.ts b/src/printer.ts index 8a8725f31..1029bdfa8 100644 --- a/src/printer.ts +++ b/src/printer.ts @@ -31,7 +31,8 @@ export default { hasPrettierIgnore(path) { return ( path.node.comments?.some(isPrettierIgnore) === true || - (canAttachComment(path.node) && isFullyBetweenPrettierIgnore(path)) + (canAttachComment(path.node, path.parent ? [path.parent] : []) && + isFullyBetweenPrettierIgnore(path)) ); }, canAttachComment, diff --git a/src/printers/expressions.ts b/src/printers/expressions.ts index 0905d3733..bffc49ab1 100644 --- a/src/printers/expressions.ts +++ b/src/printers/expressions.ts @@ -25,6 +25,7 @@ const { indentIfBreak, join, line, + lineSuffixBoundary, softline } = builders; const { getNextNonSpaceNonCommentCharacterIndex, hasNewline, isNextLineEmpty } = @@ -147,7 +148,7 @@ export default { } const parameters = join([",", line], identifiers); - if (identifiers.length > 1) { + if (identifiers.length > 1 || willBreak(identifiers)) { return group(indentInParentheses(parameters)); } return options.arrowParens === "avoid" @@ -684,8 +685,9 @@ function printLambdaExpressionSignature( } if (path.node.parametersNode.type === SyntaxType.Identifier) { - parts.unshift("("); - parts.push(")"); + return path.node.parametersNode.comments + ? group(["(", indent([softline, ...parts]), lineSuffixBoundary, ")"]) + : ["(", ...parts, ")"]; } } diff --git a/test/unit-test/comments/expression/_input.java b/test/unit-test/comments/expression/_input.java index 75d5180f3..e69b535d5 100644 --- a/test/unit-test/comments/expression/_input.java +++ b/test/unit-test/comments/expression/_input.java @@ -3,5 +3,9 @@ class Example { void example() { 0 // + 1; + + a + + // comment + (b); } } diff --git a/test/unit-test/comments/expression/_output.java b/test/unit-test/comments/expression/_output.java index 5ec638bcb..f4f758c7d 100644 --- a/test/unit-test/comments/expression/_output.java +++ b/test/unit-test/comments/expression/_output.java @@ -3,5 +3,9 @@ class Example { void example() { 0 + // 1; + + a + + // comment + (b); } } diff --git a/test/unit-test/lambda/arrow-parens-always/_input.java b/test/unit-test/lambda/arrow-parens-always/_input.java index e00ad9a06..b9ce8237b 100644 --- a/test/unit-test/lambda/arrow-parens-always/_input.java +++ b/test/unit-test/lambda/arrow-parens-always/_input.java @@ -415,3 +415,44 @@ enum Enum { return n * 2; }, other) } + +// comment +a -> b; + +a // comment + -> b; + +a -> // comment + b; + +a -> b; // comment + +// comment +a -> {}; + +a // comment + -> {}; + +a -> // comment + {}; + +a -> {}; // comment + +// comment +a -> { + b; +}; + +a // comment + -> { + b; +}; + +a -> // comment +{ + b; +}; + +a -> { + b; +}; // comment diff --git a/test/unit-test/lambda/arrow-parens-always/_output.java b/test/unit-test/lambda/arrow-parens-always/_output.java index f04a93c14..81500b35b 100644 --- a/test/unit-test/lambda/arrow-parens-always/_output.java +++ b/test/unit-test/lambda/arrow-parens-always/_output.java @@ -654,3 +654,49 @@ enum Enum { return n * 2; }, other), } + +// comment +(a) -> b; + +( + a // comment +) -> b; + +(a) -> + // comment + b; + +(a) -> b; // comment + +// comment +(a) -> {}; + +( + a // comment +) -> {}; + +(a) -> { + // comment +}; + +(a) -> {}; // comment + +// comment +(a) -> { + b; +}; + +( + a // comment +) -> { + b; +}; + +(a) -> { + // comment + b; +}; + +(a) -> { + b; +}; // comment diff --git a/test/unit-test/lambda/arrow-parens-avoid/_input.java b/test/unit-test/lambda/arrow-parens-avoid/_input.java index e00ad9a06..b9ce8237b 100644 --- a/test/unit-test/lambda/arrow-parens-avoid/_input.java +++ b/test/unit-test/lambda/arrow-parens-avoid/_input.java @@ -415,3 +415,44 @@ enum Enum { return n * 2; }, other) } + +// comment +a -> b; + +a // comment + -> b; + +a -> // comment + b; + +a -> b; // comment + +// comment +a -> {}; + +a // comment + -> {}; + +a -> // comment + {}; + +a -> {}; // comment + +// comment +a -> { + b; +}; + +a // comment + -> { + b; +}; + +a -> // comment +{ + b; +}; + +a -> { + b; +}; // comment diff --git a/test/unit-test/lambda/arrow-parens-avoid/_output.java b/test/unit-test/lambda/arrow-parens-avoid/_output.java index 35bcd7af7..40da78425 100644 --- a/test/unit-test/lambda/arrow-parens-avoid/_output.java +++ b/test/unit-test/lambda/arrow-parens-avoid/_output.java @@ -654,3 +654,49 @@ enum Enum { return n * 2; }, other), } + +// comment +a -> b; + +( + a // comment +) -> b; + +a -> + // comment + b; + +a -> b; // comment + +// comment +a -> {}; + +( + a // comment +) -> {}; + +a -> { + // comment +}; + +a -> {}; // comment + +// comment +a -> { + b; +}; + +( + a // comment +) -> { + b; +}; + +a -> { + // comment + b; +}; + +a -> { + b; +}; // comment