Add pretty printing for lambdas

This commit is contained in:
Clément Fournier
2024-04-04 16:29:28 +02:00
parent 916213cc74
commit 6e0aafbf44
2 changed files with 74 additions and 19 deletions

View File

@@ -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);

View File

@@ -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::<String>meth); } }");
@NonNull ASTMethodReference m = root.descendants(ASTMethodReference.class).firstOrThrow();
testPrettyPrint("foo(ASTW::<String>meth)", ASTMethodReference.class,
"ASTW::<String>meth");
}
assertThat(prettyPrint(m), contentEquals("ASTW::<String>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 <T extends ASTExpression> void testPrettyPrint(String expr, Class<T> 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 <T extends ASTExpression> void testPrettyPrintIdentity(String expr, Class<T> nodeTy) {
testPrettyPrint(expr, nodeTy, expr);
}
private static Matcher<CharSequence> contentEquals(String str) {