diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java index 06338e5a1b..d3a4541ee0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java @@ -9,11 +9,13 @@ import static net.sourceforge.pmd.util.AssertionUtil.shouldNotReachHere; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import net.sourceforge.pmd.lang.ast.NodeStream; import net.sourceforge.pmd.lang.java.ast.ASTAmbiguousName; import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTArrayAccess; import net.sourceforge.pmd.lang.java.ast.ASTArrayType; +import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; import net.sourceforge.pmd.lang.java.ast.ASTClassDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassLiteral; @@ -28,8 +30,12 @@ import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTForInit; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; +import net.sourceforge.pmd.lang.java.ast.ASTGuard; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTIntersectionType; +import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; +import net.sourceforge.pmd.lang.java.ast.ASTLambdaParameter; +import net.sourceforge.pmd.lang.java.ast.ASTLambdaParameterList; import net.sourceforge.pmd.lang.java.ast.ASTList; import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTMethodCall; @@ -338,6 +344,41 @@ public final class PrettyPrintingUtil { return null; } + + @Override + public Void visit(ASTLambdaExpression node, StringBuilder sb) { + node.getParameters().acceptVisitor(this, sb); + sb.append(" -> "); + ASTExpression exprBody = node.getExpression(); + if (exprBody != null) { + exprBody.acceptVisitor(this, sb); + } else { + sb.append("{ ... }"); + } + return null; + } + + @Override + public Void visit(ASTLambdaParameterList node, StringBuilder sb) { + if (node.size() == 1) { + sb.append(node.get(0).getVarId().getName()); + return null; + } else if (node.isEmpty()) { + sb.append("()"); + return null; + } + + sb.append('('); + sb.append(node.get(0).getVarId().getName()); + node.toStream().drop(1).forEach(it -> { + sb.append(", "); + sb.append(it.getVarId().getName()); + }); + sb.append(')'); + + return null; + } + @Override public Void visit(ASTMethodCall node, StringBuilder sb) { addQualifier(node, sb); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtilTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtilTest.java index 58b14a8b46..3a491ddb38 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtilTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtilTest.java @@ -20,9 +20,12 @@ import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.java.BaseParserTest; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; +import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; import net.sourceforge.pmd.lang.java.ast.ASTMethodCall; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodReference; +import net.sourceforge.pmd.lang.java.ast.ExpressionParsingCtx; import net.sourceforge.pmd.util.StringUtil; class PrettyPrintingUtilTest extends BaseParserTest { @@ -47,42 +50,53 @@ class PrettyPrintingUtilTest extends BaseParserTest { @Test void ppMethodCallArgsTooBig() { - ASTCompilationUnit root = java.parse("class A { { this.foo(\"a long string\", 12, 12, 12, 12, 12); } }"); - @NonNull ASTMethodCall m = root.descendants(ASTMethodCall.class).firstOrThrow(); - - assertThat(prettyPrint(m), contentEquals("this.foo(\"a long string\", 12...)")); + testPrettyPrint("this.foo(\"a long string\", 12, 12, 12, 12, 12)", + ASTMethodCall.class, "this.foo(\"a long string\", 12...)"); } @Test void ppMethodCallOnCast() { - ASTCompilationUnit root = java.parse("class A { { ((Object) this).foo(12); } }"); - @NonNull ASTMethodCall m = root.descendants(ASTMethodCall.class).firstOrThrow(); - - assertThat(prettyPrint(m), contentEquals("((Object) this).foo(12)")); + testPrettyPrintIdentity("((Object) this).foo(12)", ASTMethodCall.class); } @Test void ppMethodRef() { - ASTCompilationUnit root = java.parse("class A { { foo(ASTW::meth); } }"); - @NonNull ASTMethodReference m = root.descendants(ASTMethodReference.class).firstOrThrow(); - - assertThat(prettyPrint(m), contentEquals("ASTW::meth")); + testPrettyPrintIdentity("ASTW::meth", ASTMethodReference.class); } @Test void ppCtorCall() { - ASTCompilationUnit root = java.parse("class A { { new Foo(1); } }"); - @NonNull ASTConstructorCall m = root.descendants(ASTConstructorCall.class).firstOrThrow(); - - assertThat(prettyPrint(m), contentEquals("new Foo(1)")); + testPrettyPrintIdentity("new Foo(1)", ASTConstructorCall.class); } @Test void ppMethodRefWithTyArgs() { - ASTCompilationUnit root = java.parse("class A { { foo(ASTW::meth); } }"); - @NonNull ASTMethodReference m = root.descendants(ASTMethodReference.class).firstOrThrow(); + testPrettyPrint("foo(ASTW::meth)", ASTMethodReference.class, + "ASTW::meth"); + } - assertThat(prettyPrint(m), contentEquals("ASTW::meth")); + @Test + void ppLambdaExpr() { + testPrettyPrintIdentity("(a, b) -> new Foo()", ASTLambdaExpression.class); + testPrettyPrintIdentity("() -> new Foo()", ASTLambdaExpression.class); + testPrettyPrintIdentity("x -> new Foo()", ASTLambdaExpression.class); + testPrettyPrint("(x) -> new Foo()", ASTLambdaExpression.class, "x -> new Foo()"); + } + + @Test + void ppLambdaBlock() { + testPrettyPrint("(a, b) -> {return new Foo(); }", ASTLambdaExpression.class, + "(a, b) -> { ... }"); + } + + private void testPrettyPrint(String expr, Class nodeTy, String expected) { + ASTCompilationUnit root = java.parse("class A { { Object x = " + expr + "; } }"); + @NonNull T node = root.descendants(nodeTy).firstOrThrow(); + assertThat(prettyPrint(node), contentEquals(expected)); + } + + private void testPrettyPrintIdentity(String expr, Class nodeTy) { + testPrettyPrint(expr, nodeTy, expr); } private static Matcher contentEquals(String str) {