From b01d4dc0d7bf6a2fa7b85a265635ad5bddbe70b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 17 Mar 2020 21:36:15 +0100 Subject: [PATCH] Test --- .../pmd/lang/ast/AbstractNode.java | 4 +- .../net/sourceforge/pmd/lang/ast/Node.java | 2 +- pmd-java/etc/grammar/Java.jjt | 23 +-- .../pmd/lang/java/ast/Java14Test.java | 141 +++++++++++++----- .../java14/YieldStatements.java | 35 +++++ 5 files changed, 151 insertions(+), 54 deletions(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index e7f7b0fdef..c14ede1d12 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -357,7 +357,7 @@ public abstract class AbstractNode implements Node { } @Override - public List findDescendantsOfType(final Class targetType) { + public List findDescendantsOfType(final Class targetType) { final List list = new ArrayList<>(); findDescendantsOfType(this, targetType, list, false); return list; @@ -381,7 +381,7 @@ public abstract class AbstractNode implements Node { findDescendantsOfType(this, targetType, results, crossBoundaries); } - private static void findDescendantsOfType(final Node node, final Class targetType, final List results, + private static void findDescendantsOfType(final Node node, final Class targetType, final List results, final boolean crossFindBoundaries) { for (Node child : node.children()) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java index 1b8172ec54..46b9ae08f3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java @@ -284,7 +284,7 @@ public interface Node { * @return List of all children of type targetType. Returns an empty list if * none found. */ - List findDescendantsOfType(Class targetType); + List findDescendantsOfType(Class targetType); /** * Traverses down the tree to find all the descendant instances of type diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 9b881d591f..ed02e26612 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -506,10 +506,10 @@ public class JavaParser { * True if we're in a switch block, one precondition for parsing a yield * statement. */ - private boolean inSwitchBlock = false; + private boolean inSwitchExprBlock = false; private boolean isYieldStart() { - return inSwitchBlock && isJava13PreviewOr14() + return inSwitchExprBlock && isJava13PreviewOr14() && isKeyword("yield") && mayStartExprAfterYield(2); } @@ -541,8 +541,9 @@ public class JavaParser { } // lambda: yield () -> {}; // method call: yield (); - return lookahead != offset + 2 // ie () - || t.kind == ARROW; + return t != null + && (lookahead != offset + 2 // ie () + || t.kind == LAMBDA); default: return false; } @@ -1667,10 +1668,13 @@ void CastExpression() : } void SwitchExpression() : -{} +{boolean prevInSwitchBlock = inSwitchExprBlock;} { {checkForSwitchExpression();} - "switch" "(" Expression() ")" SwitchBlock() + "switch" "(" Expression() ")" + {inSwitchExprBlock = true;} + SwitchBlock() + {inSwitchExprBlock = prevInSwitchBlock;} } void PrimaryExpression() : @@ -1838,6 +1842,7 @@ void Statement() : {} { LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() +| LOOKAHEAD( { isYieldStart() } ) YieldStatement() | LOOKAHEAD(2) LabeledStatement() | Block() | EmptyStatement() @@ -1873,7 +1878,7 @@ void BlockStatement(): {} { LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() -| LOOKAHEAD({ jdkVersion >= 13 && isKeyword("yield") }) YieldStatement() +| LOOKAHEAD( { isYieldStart() } ) YieldStatement() | LOOKAHEAD(( "final" | Annotation() )* Type() ) LocalVariableDeclaration() ";" @@ -1946,9 +1951,8 @@ void SwitchStatement(): } void SwitchBlock() #void : -{boolean prevInSwitchBlock = inSwitchBlock;} +{} { - {inSwitchBlock = true;} "{" ( SwitchLabel() @@ -1963,7 +1967,6 @@ void SwitchBlock() #void : ) )? "}" - {inSwitchBlock = prevInSwitchBlock;} } void SwitchLabeledRule() #void : diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java index 334335db65..86cb5e08c7 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java @@ -5,9 +5,14 @@ package net.sourceforge.pmd.lang.java.ast; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + import java.util.List; -import org.junit.Assert; import org.junit.Test; import net.sourceforge.pmd.lang.ast.ParseException; @@ -47,36 +52,90 @@ public class Java14Test { private void parseAndCheckSwitchExpression(JavaParsingHelper parser) { ASTCompilationUnit compilationUnit = parser.parseResource("SwitchExpressions.java"); List switchStatements = compilationUnit.findDescendantsOfType(ASTSwitchStatement.class); - Assert.assertEquals(2, switchStatements.size()); + assertEquals(2, switchStatements.size()); - Assert.assertTrue(switchStatements.get(0).getChild(0) instanceof ASTExpression); - Assert.assertTrue(switchStatements.get(0).getChild(1) instanceof ASTSwitchLabeledExpression); - Assert.assertTrue(switchStatements.get(0).getChild(1).getChild(0) instanceof ASTSwitchLabel); - Assert.assertEquals(3, switchStatements.get(0).getChild(1).getChild(0).getNumChildren()); - Assert.assertTrue(switchStatements.get(0).getChild(2).getChild(0) instanceof ASTSwitchLabel); - Assert.assertFalse(((ASTSwitchLabel) switchStatements.get(0).getChild(2).getChild(0)).isDefault()); - Assert.assertEquals(1, switchStatements.get(0).getChild(2).getChild(0).getNumChildren()); + assertTrue(switchStatements.get(0).getChild(0) instanceof ASTExpression); + assertTrue(switchStatements.get(0).getChild(1) instanceof ASTSwitchLabeledExpression); + assertTrue(switchStatements.get(0).getChild(1).getChild(0) instanceof ASTSwitchLabel); + assertEquals(3, switchStatements.get(0).getChild(1).getChild(0).getNumChildren()); + assertTrue(switchStatements.get(0).getChild(2).getChild(0) instanceof ASTSwitchLabel); + assertFalse(((ASTSwitchLabel) switchStatements.get(0).getChild(2).getChild(0)).isDefault()); + assertEquals(1, switchStatements.get(0).getChild(2).getChild(0).getNumChildren()); - Assert.assertTrue(switchStatements.get(1).getChild(3) instanceof ASTSwitchLabeledExpression); - Assert.assertTrue(switchStatements.get(1).getChild(3).getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(((ASTSwitchLabel) switchStatements.get(1).getChild(3).getChild(0)).isDefault()); + assertTrue(switchStatements.get(1).getChild(3) instanceof ASTSwitchLabeledExpression); + assertTrue(switchStatements.get(1).getChild(3).getChild(0) instanceof ASTSwitchLabel); + assertTrue(((ASTSwitchLabel) switchStatements.get(1).getChild(3).getChild(0)).isDefault()); List switchExpressions = compilationUnit.findDescendantsOfType(ASTSwitchExpression.class); - Assert.assertEquals(4, switchExpressions.size()); + assertEquals(4, switchExpressions.size()); - Assert.assertEquals(Integer.TYPE, switchExpressions.get(0).getType()); - Assert.assertEquals(4, switchExpressions.get(0).findChildrenOfType(ASTSwitchLabeledExpression.class).size()); - Assert.assertEquals(Integer.TYPE, switchExpressions.get(0).getFirstChildOfType(ASTSwitchLabeledExpression.class) - .getFirstChildOfType(ASTExpression.class).getType()); + assertEquals(Integer.TYPE, switchExpressions.get(0).getType()); + assertEquals(4, switchExpressions.get(0).findChildrenOfType(ASTSwitchLabeledExpression.class).size()); + assertEquals(Integer.TYPE, switchExpressions.get(0).getFirstChildOfType(ASTSwitchLabeledExpression.class) + .getFirstChildOfType(ASTExpression.class).getType()); - Assert.assertTrue(switchExpressions.get(1).getChild(3) instanceof ASTSwitchLabeledBlock); + assertTrue(switchExpressions.get(1).getChild(3) instanceof ASTSwitchLabeledBlock); - Assert.assertEquals(Integer.TYPE, switchExpressions.get(2).getType()); + assertEquals(Integer.TYPE, switchExpressions.get(2).getType()); List yields = switchExpressions.get(2).findDescendantsOfType(ASTYieldStatement.class); - Assert.assertEquals(4, yields.size()); - Assert.assertEquals("SwitchExpressions.BAZ", yields.get(2).getImage()); + assertEquals(4, yields.size()); + assertEquals("SwitchExpressions.BAZ", yields.get(2).getImage()); - Assert.assertEquals(String.class, switchExpressions.get(3).getType()); + assertEquals(String.class, switchExpressions.get(3).getType()); + } + + @Test + public void checkYieldConditionalBehaviour() { + checkYieldStatements(java13p); + } + + @Test + public void checkYieldConditionalBehaviourJ14() { + checkYieldStatements(java14); + } + + private void checkYieldStatements(JavaParsingHelper parser) { + ASTCompilationUnit compilationUnit = parser.parseResource("YieldStatements.java"); + List stmts = compilationUnit.findDescendantsOfType(ASTBlockStatement.class); + // fetch the interesting node, on the java-grammar branch this is not needed + for (int i = 0; i < stmts.size(); i++) { + JavaNode child = stmts.get(i).getChild(0); + + if (child instanceof ASTStatement) { + stmts.set(i, child.getChild(0)); + } else { + stmts.set(i, child); + } + } + + assertEquals(18, stmts.size()); + + int i = 0; + assertThat(stmts.get(i++), instanceOf(ASTLocalVariableDeclaration.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class)); + assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class)); + assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + + assertThat(stmts.get(i++), instanceOf(ASTIfStatement.class)); + + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class)); + + assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class)); + assertThat(stmts.get(i++), instanceOf(ASTStatementExpression.class)); + assertThat(stmts.get(i++), instanceOf(ASTYieldStatement.class)); + + assertEquals(i, stmts.size()); } @Test @@ -89,10 +148,10 @@ public class Java14Test { private void multipleCaseLabels(JavaParsingHelper parser) { ASTCompilationUnit compilationUnit = parser.parseResource("MultipleCaseLabels.java"); ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class); - Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression); - Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabel); + assertTrue(switchStatement.getChild(0) instanceof ASTExpression); + assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabel); ASTSwitchLabel switchLabel = switchStatement.getFirstChildOfType(ASTSwitchLabel.class); - Assert.assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size()); + assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size()); } @Test @@ -105,22 +164,22 @@ public class Java14Test { private void switchRules(JavaParsingHelper parser) { ASTCompilationUnit compilationUnit = parser.parseResource("SwitchRules.java"); ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class); - Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression); - Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabeledExpression); + assertTrue(switchStatement.getChild(0) instanceof ASTExpression); + assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabeledExpression); ASTSwitchLabeledExpression switchLabeledExpression = (ASTSwitchLabeledExpression) switchStatement.getChild(1); - Assert.assertEquals(2, switchLabeledExpression.getNumChildren()); - Assert.assertTrue(switchLabeledExpression.getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(switchLabeledExpression.getChild(1) instanceof ASTExpression); + assertEquals(2, switchLabeledExpression.getNumChildren()); + assertTrue(switchLabeledExpression.getChild(0) instanceof ASTSwitchLabel); + assertTrue(switchLabeledExpression.getChild(1) instanceof ASTExpression); ASTSwitchLabeledBlock switchLabeledBlock = (ASTSwitchLabeledBlock) switchStatement.getChild(4); - Assert.assertEquals(2, switchLabeledBlock.getNumChildren()); - Assert.assertTrue(switchLabeledBlock.getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(switchLabeledBlock.getChild(1) instanceof ASTBlock); + assertEquals(2, switchLabeledBlock.getNumChildren()); + assertTrue(switchLabeledBlock.getChild(0) instanceof ASTSwitchLabel); + assertTrue(switchLabeledBlock.getChild(1) instanceof ASTBlock); ASTSwitchLabeledThrowStatement switchLabeledThrowStatement = (ASTSwitchLabeledThrowStatement) switchStatement.getChild(5); - Assert.assertEquals(2, switchLabeledThrowStatement.getNumChildren()); - Assert.assertTrue(switchLabeledThrowStatement.getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(switchLabeledThrowStatement.getChild(1) instanceof ASTThrowStatement); + assertEquals(2, switchLabeledThrowStatement.getNumChildren()); + assertTrue(switchLabeledThrowStatement.getChild(0) instanceof ASTSwitchLabel); + assertTrue(switchLabeledThrowStatement.getChild(1) instanceof ASTThrowStatement); } @Test @@ -133,13 +192,13 @@ public class Java14Test { private void simpleSwitchExpressions(JavaParsingHelper parser) { ASTCompilationUnit compilationUnit = parser.parseResource("SimpleSwitchExpressions.java"); ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class); - Assert.assertEquals(6, switchExpression.getNumChildren()); - Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression); - Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size()); + assertEquals(6, switchExpression.getNumChildren()); + assertTrue(switchExpression.getChild(0) instanceof ASTExpression); + assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size()); 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()); + assertEquals(Integer.TYPE, localVarDecl.getType()); + assertEquals(Integer.TYPE, switchExpression.getType()); } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.java new file mode 100644 index 0000000000..f56e25646f --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/YieldStatements.java @@ -0,0 +1,35 @@ +/** + * @see JEP 361: Switch Expressions (Standard) + */ +public class YieldStatements { + { + int yield = 0; + yield = 2; // should be an assignment + yield (2); // should be a method call + yield(a,b); // should be a method call + + + yield = switch (e) { // must be a switch expr + case 1 -> { + yield(a,b); // should be a method call + yield = 2; // should be an assignment + yield (2); // should be a yield statement + yield++bar; // should be a yield statement (++bar is an expression) + yield--bar; // should be a yield statement (--bar is an expression) + yield++; // should be an increment (not an error) + yield--; // should be a decrement (not an error) + + if (true) yield(2); + else yield 4; + + yield = switch (foo) { // putting a switch in the middles checks the reset behavior + case 4 -> {yield(5);} // should be a yield statement + }; + + yield () -> {}; // should be a yield statement + yield (); // should be a method call + yield (2); // should be a yield statement + } + }; + } +}