From ac4a0daff98634fa6b5f464ec4ce42e60e556c05 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Tue, 13 Aug 2019 20:29:31 +0200 Subject: [PATCH] [java] Add Java 13 support Fix type resolution of switch with yields --- .../pmd/lang/java/ast/ASTYieldStatement.java | 9 +++++ .../typeresolution/ClassTypeResolver.java | 21 +++++++++-- .../pmd/lang/java/ast/Java13Test.java | 23 ++++++++++++ .../java13/SwitchExpressionsYield.java | 36 +++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/SwitchExpressionsYield.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java index eb6cf98fb6..b3a59c33ee 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTYieldStatement.java @@ -18,4 +18,13 @@ public class ASTYieldStatement extends AbstractJavaTypeNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public String getImage() { + String result = super.getImage(); + if (result == null && hasDescendantOfType(ASTName.class)) { + result = getFirstDescendantOfType(ASTName.class).getImage(); + } + return result; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java index 0e44508070..4d06e0a841 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java @@ -34,7 +34,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement; import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; @@ -1187,7 +1186,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { super.visit(node, data); JavaTypeDefinition type = null; - // first try to determine the type based on the first expression/break of a switch rule + // first try to determine the type based on the first expression/break/yield of a switch rule List rules = node.findChildrenOfType(ASTSwitchLabeledRule.class); for (ASTSwitchLabeledRule rule : rules) { Node body = rule.jjtGetChild(1); // second child is either Expression, Block, ThrowStatement @@ -1203,10 +1202,18 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { break; } } + List yields = body.findDescendantsOfType(ASTYieldStatement.class); + if (!yields.isEmpty()) { + ASTExpression expression = yields.get(0).getFirstChildOfType(ASTExpression.class); + if (expression != null) { + type = expression.getTypeDefinition(); + break; + } + } } } if (type == null) { - // now check the labels and their expressions of break statements + // now check the labels and their expressions of break/yield statements for (int i = 0; i < node.jjtGetNumChildren(); i++) { Node child = node.jjtGetChild(i); if (child instanceof ASTBlockStatement) { @@ -1218,6 +1225,14 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { break; } } + List yields = child.findDescendantsOfType(ASTYieldStatement.class); + if (!yields.isEmpty()) { + ASTExpression expression = yields.get(0).getFirstChildOfType(ASTExpression.class); + if (expression != null && expression.getTypeDefinition() != null) { + type = expression.getTypeDefinition(); + break; + } + } } } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java index febaac9fe7..df00d86777 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java13Test.java @@ -41,6 +41,29 @@ public class Java13Test { Assert.assertEquals(Integer.TYPE, yieldStatement.getType()); } + @Test + public void testSwitchExpressionsYield() { + ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("13", + loadSource("SwitchExpressionsYield.java")); + Assert.assertNotNull(compilationUnit); + + ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class); + Assert.assertEquals(11, switchExpression.jjtGetNumChildren()); + Assert.assertTrue(switchExpression.jjtGetChild(0) instanceof ASTExpression); + Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabel.class).size()); + + ASTYieldStatement yieldStatement = switchExpression.getFirstDescendantOfType(ASTYieldStatement.class); + Assert.assertEquals("SwitchExpressionsBreak.SIX", yieldStatement.getImage()); + Assert.assertTrue(yieldStatement.jjtGetChild(0) instanceof ASTExpression); + + ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class) + .get(1); + ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class); + Assert.assertEquals(Integer.TYPE, localVarDecl.getType()); + Assert.assertEquals(Integer.TYPE, switchExpression.getType()); + } + + @Test(expected = ParseException.class) public void testSwitchExpressionsBeforeJava13() { ParserTstUtil.parseAndTypeResolveJava("12", loadSource("SwitchExpressions.java")); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/SwitchExpressionsYield.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/SwitchExpressionsYield.java new file mode 100644 index 0000000000..fd8ca7bf70 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java13/SwitchExpressionsYield.java @@ -0,0 +1,36 @@ +/** + * + * @see JEP 325: Switch Expressions (Preview) + */ +public class SwitchExpressionsYield { + private static final int MONDAY = 1; + private static final int TUESDAY = 2; + private static final int WEDNESDAY = 3; + private static final int THURSDAY = 4; + private static final int FRIDAY = 5; + private static final int SATURDAY = 6; + private static final int SUNDAY = 7; + + private static final int SIX = 6; + + public static void main(String[] args) { + int day = FRIDAY; + + var numLetters = switch (day) { + case MONDAY, FRIDAY, SUNDAY: yield SwitchExpressionsBreak.SIX; + case TUESDAY : yield 7; + case THURSDAY, SATURDAY : yield 8; + case WEDNESDAY : yield 9; + default : { + int k = day * 2; + int result = f(k); + yield result; + } + }; + System.out.printf("NumLetters: %d%n", numLetters); + } + + private static int f(int k) { + return k*3; + } +}