From 1bc61293d972c3650a7b40be5a2d0c1616dbf7b3 Mon Sep 17 00:00:00 2001 From: Alex Abashev Date: Sat, 3 Oct 2026 21:15:33 +0300 Subject: [PATCH] Keep an annotated lambda parameter on its line An annotation with arguments on a lambda parameter, such as `(final var x, @SuppressWarnings("unused") var y) -> x + y`, forced a line break after the annotation, so a statement that fits in 120 columns came out as four lines. visitLambdaExpression declared each parameter with inlineAnnotationDirection, which answers VERTICAL, a forced break, for any annotation that has arguments. That rule is for local variable declarations, where the annotation above the type is the wanted shape. Method parameters are declared with Direction.HORIZONTAL and keep their annotations inline; lambda parameters now do the same. Golden ojf-issue-101-annotated-lambda-parameters covers the broken shape, a one-line input, two annotations, marker annotations, a block body, a lambda too long for one line and one whose parameters do not fit, with a method parameter and a local variable as controls. The JDK 21 and 25 sources format exactly as before: they have no lambda parameter with an annotation that takes arguments. Closes #101. --- .../javaformat/java/JavaInputAstVisitor.java | 8 ++--- ...ssue-101-annotated-lambda-parameters.input | 29 ++++++++++++++++++ ...sue-101-annotated-lambda-parameters.output | 30 +++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.input create mode 100644 open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.output diff --git a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java index a23b7a548..076f8aadf 100644 --- a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java +++ b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java @@ -1247,10 +1247,10 @@ protected void visitLambdaExpression(LambdaExpressionTree node, boolean statemen token(","); builder.breakOp(" "); } - visitVariables( - ImmutableList.of(parameter), - DeclarationKind.NONE, - inlineAnnotationDirection(parameter.getModifiers())); + // A lambda parameter is a parameter: its annotations stay on its line, as a method parameter's do. The + // vertical direction, a forced break after an annotation with arguments, is for local variable + // declarations. + visitVariables(ImmutableList.of(parameter), DeclarationKind.NONE, Direction.HORIZONTAL); first = false; } if (parens) { diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.input b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.input new file mode 100644 index 000000000..e4c539989 --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.input @@ -0,0 +1,29 @@ +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +class AnnotatedLambdaParameters { + BiFunction withArgs = + (final var x, + @SuppressWarnings("unused") + var y) -> x + y; + + Function typed = ( @SuppressWarnings( "unused" ) String s )->s.length(); + + BiFunction two = (@Deprecated @SuppressWarnings("unused") + var x, var y) -> x + y; + + BiFunction marker = (@Deprecated var x, + @Deprecated final var y) -> x + y; + + Consumer block = (@SuppressWarnings({"unused", "rawtypes"}) + String s) -> { System.out.println(s); }; + + BiFunction tooLongForOneLine = (@SuppressWarnings("unused") Integer first, @SuppressWarnings("unused") Integer second) -> first + second; + + BiFunction parametersDoNotFitOnOneLine = (@SuppressWarnings("unused") Integer firstParameterWithAVeryLongName, @SuppressWarnings("unused") Integer secondParameterWithAVeryLongName) -> firstParameterWithAVeryLongName + secondParameterWithAVeryLongName; + + void method(@SuppressWarnings("unused") int y, @Deprecated int z) { + @SuppressWarnings("unchecked") Function local = o -> (String) o; + } +} diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.output b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.output new file mode 100644 index 000000000..41a8338d1 --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-101-annotated-lambda-parameters.output @@ -0,0 +1,30 @@ +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +class AnnotatedLambdaParameters { + BiFunction withArgs = (final var x, @SuppressWarnings("unused") var y) -> x + y; + + Function typed = (@SuppressWarnings("unused") String s) -> s.length(); + + BiFunction two = (@Deprecated @SuppressWarnings("unused") var x, var y) -> x + y; + + BiFunction marker = (@Deprecated var x, @Deprecated final var y) -> x + y; + + Consumer block = (@SuppressWarnings({"unused", "rawtypes"}) String s) -> { + System.out.println(s); + }; + + BiFunction tooLongForOneLine = + (@SuppressWarnings("unused") Integer first, @SuppressWarnings("unused") Integer second) -> first + second; + + BiFunction parametersDoNotFitOnOneLine = + (@SuppressWarnings("unused") Integer firstParameterWithAVeryLongName, + @SuppressWarnings("unused") Integer secondParameterWithAVeryLongName) -> + firstParameterWithAVeryLongName + secondParameterWithAVeryLongName; + + void method(@SuppressWarnings("unused") int y, @Deprecated int z) { + @SuppressWarnings("unchecked") + Function local = o -> (String) o; + } +}