From d7aa1b17421e0927cdafa0da17389eca09925d88 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 16 Mar 2019 10:47:12 +0100 Subject: [PATCH] Support Expression in break statements --- pmd-java/etc/grammar/Java.jjt | 8 ++++- .../typeresolution/ClassTypeResolver.java | 22 ++++++++----- .../pmd/lang/java/ast/Java12Test.java | 17 ++++++++++ .../java12/SwitchExpressionsBreak.java | 31 +++++++++++++++++++ 4 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 8b1eaa979d..82bd933701 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -405,6 +405,12 @@ public class JavaParser { private boolean inFallthroughSwitchCase = false; + private void checkForBreakExpression() { + if (jdkVersion < 12) { + throwParseException("Expressions in break statements are only supported with Java 12"); + } + } + // This is a semantic LOOKAHEAD to determine if we're dealing with an assert // Note that this can't be replaced with a syntactic lookahead // since "assert" isn't a string literal token @@ -2560,7 +2566,7 @@ void ForUpdate() : void BreakStatement() : {Token t;} { - "break" [ t= {jjtThis.setImage(t.image);} ] ";" + "break" [ LOOKAHEAD(1) t= {jjtThis.setImage(t.image);} | Expression() {checkForBreakExpression();} ] ";" } void ContinueStatement() : 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 16dab79549..4883668d0a 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 @@ -1194,21 +1194,27 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { } else if (body instanceof ASTBlock) { List breaks = body.findDescendantsOfType(ASTBreakStatement.class); if (!breaks.isEmpty()) { - //TODO: check for break statements - //type = breaks.get(0).getExpression().getType(); - //break; + ASTExpression expression = breaks.get(0).getFirstChildOfType(ASTExpression.class); + if (expression != null) { + type = expression.getTypeDefinition(); + break; + } } } } if (type == null) { - // now check the labels and their expressions, breaks + // now check the labels and their expressions of break statements for (int i = 0; i < node.jjtGetNumChildren(); i++) { Node child = node.jjtGetChild(i); if (child instanceof ASTBlockStatement) { - List breakStatement = child.findDescendantsOfType(ASTBreakStatement.class); - //TODO: check for break statements - //type = breakStatement.getExpression().getType(); - //break; + List breaks = child.findDescendantsOfType(ASTBreakStatement.class); + if (!breaks.isEmpty()) { + ASTExpression expression = breaks.get(0).getFirstChildOfType(ASTExpression.class); + if (expression != null) { + type = expression.getTypeDefinition(); + break; + } + } } } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java index 601692e3f8..d75aff5737 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java @@ -92,4 +92,21 @@ public class Java12Test { Assert.assertEquals(Integer.TYPE, switchExpression.getType()); } + @Test + public void testSwitchExpressionsBreak() { + ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12", + loadSource("SwitchExpressionsBreak.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()); + + 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()); + } + } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java new file mode 100644 index 0000000000..b25b54ed05 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java @@ -0,0 +1,31 @@ +public class SwitchExpressionsBreak { + 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; + + + public static void main(String[] args) { + int day = FRIDAY; + + var numLetters = switch (day) { + case MONDAY, FRIDAY, SUNDAY: break 6; + case TUESDAY : break 7; + case THURSDAY, SATURDAY : break 8; + case WEDNESDAY : break 9; + default : { + int k = day * 2; + int result = f(k); + break result; + } + }; + System.out.printf("NumLetters: %d%n", numLetters); + } + + private static int f(int k) { + return k*3; + } +}