This commit is contained in:
Clément Fournier
2020-03-17 21:36:15 +01:00
parent 9e9c370a4a
commit b01d4dc0d7
5 changed files with 151 additions and 54 deletions

View File

@ -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() <IDENTIFIER>)
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 :

View File

@ -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<ASTSwitchStatement> 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<ASTSwitchExpression> 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<ASTYieldStatement> 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<JavaNode> stmts = compilationUnit.<JavaNode>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());
}
}

View File

@ -0,0 +1,35 @@
/**
* @see <a href="https://openjdk.java.net/jeps/361">JEP 361: Switch Expressions (Standard)</a>
*/
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
}
};
}
}