[java] Add Java12 support

This commit is contained in:
Andreas Dangel
2019-03-15 20:51:53 +01:00
parent 8949019da6
commit 65cac51445
6 changed files with 114 additions and 56 deletions

View File

@ -383,6 +383,15 @@ public class JavaParser {
throwParseException("Multiple case labels in switch statements are only supported with Java 12"); throwParseException("Multiple case labels in switch statements are only supported with Java 12");
} }
} }
/**
* Keeps track during tree construction, whether we are currently building a switch label.
* A switch label must not contain a LambdaExpression.
* Unfortunately, we have added LambdaExpression as part of PrimaryPrefix, which is wrong.
* To keep compatibility, this flag is used, whether a LambdaExpression should be parsed
* in PrimaryPrefix.
* See also comment at #Expression().
*/
private boolean inSwitchLabel = false;
private void checkForSwitchRules() { private void checkForSwitchRules() {
if (jdkVersion < 12) { if (jdkVersion < 12) {
throwParseException("Switch rules in switch statements are only supported with Java 12"); throwParseException("Switch rules in switch statements are only supported with Java 12");
@ -424,6 +433,26 @@ public class JavaParser {
return getToken(1).kind == IDENTIFIER && getToken(1).image.equals(keyword); return getToken(1).kind == IDENTIFIER && getToken(1).image.equals(keyword);
} }
/**
* Semantic lookahead needed to distinguish between switch rules
* and switch statement. Using the syntactic lookahead for SwitchLabel()
* does not work, during lookahead the javacode is not executed, so
* that "->" is already consumed as a LambdaExpression, when it is actually
* part of the switch rule. See also #inSwitchLabel.
*/
private boolean switchLabeledRuleLookahead(int maxTokens) {
int pos = 0;
while (pos < maxTokens) {
Token token = getToken(pos);
pos++;
if (token.kind == COLON) return false;
if (token.kind == LAMBDA) return true;
}
return false;
}
public Map<Integer, String> getSuppressMap() { public Map<Integer, String> getSuppressMap() {
return token_source.getSuppressMap(); return token_source.getSuppressMap();
} }
@ -2019,16 +2048,15 @@ void Expression() :
// separated from the AssignmentExpression production. Their use is restricted // separated from the AssignmentExpression production. Their use is restricted
// to method and constructor argument, cast operand, and the RHS of assignments. // to method and constructor argument, cast operand, and the RHS of assignments.
// https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.27 // https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.27
//
// To prevent LambdaExpressions in switch labels, the field #inSwitchLabel is used
// as a workaround.
{} {}
{ {
LOOKAHEAD((<IDENTIFIER>|LambdaParameters()) "->" ) LambdaExpression()
|
(
ConditionalExpression() ConditionalExpression()
[ [
LOOKAHEAD(2) AssignmentOperator() Expression() LOOKAHEAD(2) AssignmentOperator() Expression()
] ]
)
} }
void AssignmentOperator() : void AssignmentOperator() :
@ -2188,7 +2216,7 @@ void SwitchExpression() :
{} {}
{ {
{checkForSwitchExpression();} {checkForSwitchExpression();}
"switch" "(" Expression() ")" "{" SwitchBlock() "}" "switch" "(" Expression() ")" SwitchBlock()
} }
void PrimaryExpression() : void PrimaryExpression() :
@ -2218,9 +2246,9 @@ void PrimaryPrefix() :
Literal() Literal()
| LOOKAHEAD(2) "this" {jjtThis.setUsesThisModifier();} | LOOKAHEAD(2) "this" {jjtThis.setUsesThisModifier();}
| "super" {jjtThis.setUsesSuperModifier();} | "super" {jjtThis.setUsesSuperModifier();}
//| LOOKAHEAD( <IDENTIFIER> "->" ) LambdaExpression() | LOOKAHEAD( <IDENTIFIER> "->", {!inSwitchLabel} ) LambdaExpression()
//| LOOKAHEAD( "(" VariableDeclaratorId() ( "," VariableDeclaratorId() )* ")" "->" ) LambdaExpression() | LOOKAHEAD( "(" VariableDeclaratorId() ( "," VariableDeclaratorId() )* ")" "->", {!inSwitchLabel} ) LambdaExpression()
//| LOOKAHEAD( FormalParameters() "->" ) LambdaExpression() | LOOKAHEAD( FormalParameters() "->", {!inSwitchLabel} ) LambdaExpression()
| LOOKAHEAD(3) "(" Expression() ")" | LOOKAHEAD(3) "(" Expression() ")"
| AllocationExpression() | AllocationExpression()
| LOOKAHEAD( ResultType() "." "class" ) ResultType() "." "class" | LOOKAHEAD( ResultType() "." "class" ) ResultType() "." "class"
@ -2445,41 +2473,37 @@ void StatementExpression() :
void SwitchStatement(): void SwitchStatement():
{} {}
{ {
"switch" "(" Expression() ")" "{" "switch" "(" Expression() ")" SwitchBlock()
SwitchBlock()
"}"
} }
void SwitchBlock() #void : void SwitchBlock() #void :
{} {}
{ {
( "{"
SwitchLabel() (
( LOOKAHEAD( { switchLabeledRuleLookahead(10) } ) ( SwitchLabeledRule() )+
"->" ( Expression() ";" | Block() | ThrowStatement() ) |
| (LOOKAHEAD(3) SwitchLabeledStatementGroup() )* (SwitchLabel() ":")*
":" (SwitchLabel() ":")* ( BlockStatement() )* )
) "}"
)*
/*
LOOKAHEAD(SwitchLabel() "->") SwitchLabeledRule() ( SwitchLabeledRule() )*
|
( SwitchLabeledStatementGroup() )*
*/
} }
void SwitchLabeledStatementGroup() #void: void SwitchLabeledStatementGroup() #void:
{} {}
{ {
SwitchLabel() ":" (SwitchLabel() ":")* ( BlockStatement() )* (SwitchLabel() ":")+ ( BlockStatement() )+
} }
void SwitchLabel() : void SwitchLabel() :
{} {}
{ {
"case" ConditionalExpression() ({checkForMultipleCaseLabels();} "," ConditionalExpression())* { inSwitchLabel = true; }
(
"case" ( ConditionalExpression() #Expression ) ({checkForMultipleCaseLabels();} "," ( ConditionalExpression() #Expression ) )*
| |
"default" {jjtThis.setDefault();} "default" {jjtThis.setDefault();}
)
{ inSwitchLabel = false; }
} }
void SwitchLabeledRule(): void SwitchLabeledRule():

View File

@ -1,21 +1,24 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/* Generated By:JJTree: Do not edit this line. ASTSwitchLabeledRule.java Version 4.3 */ /* Generated By:JJTree: Do not edit this line. ASTSwitchLabeledRule.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package net.sourceforge.pmd.lang.java.ast; package net.sourceforge.pmd.lang.java.ast;
public public class ASTSwitchExpression extends AbstractJavaNode {
class ASTSwitchExpression extends AbstractJavaNode { ASTSwitchExpression(int id) {
ASTSwitchExpression(int id) { super(id);
super(id); }
}
ASTSwitchExpression(JavaParser p, int id) { ASTSwitchExpression(JavaParser p, int id) {
super(p, id); super(p, id);
} }
@Override
/** Accept the visitor. **/ public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data);
return visitor.visit(this, data); }
}
} }
/* JavaCC - OriginalChecksum=8b1747ca53f66203ee212a3699a9a2f3 (do not edit this line) */ /* JavaCC - OriginalChecksum=8b1747ca53f66203ee212a3699a9a2f3 (do not edit this line) */

View File

@ -1,21 +1,24 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
/* Generated By:JJTree: Do not edit this line. ASTSwitchLabeledRule.java Version 4.3 */ /* Generated By:JJTree: Do not edit this line. ASTSwitchLabeledRule.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package net.sourceforge.pmd.lang.java.ast; package net.sourceforge.pmd.lang.java.ast;
public public class ASTSwitchLabeledRule extends AbstractJavaNode {
class ASTSwitchLabeledRule extends AbstractJavaNode { ASTSwitchLabeledRule(int id) {
ASTSwitchLabeledRule(int id) { super(id);
super(id); }
}
ASTSwitchLabeledRule(JavaParser p, int id) { ASTSwitchLabeledRule(JavaParser p, int id) {
super(p, id); super(p, id);
} }
@Override
/** Accept the visitor. **/ public Object jjtAccept(JavaParserVisitor visitor, Object data) {
public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data);
return visitor.visit(this, data); }
}
} }
/* JavaCC - OriginalChecksum=8b1747ca53f66203ee212a3699a9a2f3 (do not edit this line) */ /* JavaCC - OriginalChecksum=8b1747ca53f66203ee212a3699a9a2f3 (do not edit this line) */

View File

@ -26,8 +26,8 @@ public class LanguageVersionDiscovererTest {
File javaFile = new File("/path/to/MyClass.java"); File javaFile = new File("/path/to/MyClass.java");
LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile);
assertEquals("LanguageVersion must be Java 11 !", assertEquals("LanguageVersion must be Java 12 !",
LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("11"), languageVersion); LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("12"), languageVersion);
} }
/** /**
@ -48,7 +48,7 @@ public class LanguageVersionDiscovererTest {
public void testLanguageVersionDiscoverer() { public void testLanguageVersionDiscoverer() {
PMDConfiguration configuration = new PMDConfiguration(); PMDConfiguration configuration = new PMDConfiguration();
LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer(); LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer();
assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("11"), assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("12"),
languageVersionDiscoverer languageVersionDiscoverer
.getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME)));
configuration configuration

View File

@ -34,6 +34,11 @@ public class Java12Test {
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12", ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12",
loadSource("MultipleCaseLabels.java")); loadSource("MultipleCaseLabels.java"));
Assert.assertNotNull(compilationUnit); Assert.assertNotNull(compilationUnit);
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
Assert.assertTrue(switchStatement.jjtGetChild(0) instanceof ASTExpression);
Assert.assertTrue(switchStatement.jjtGetChild(1) instanceof ASTSwitchLabel);
ASTSwitchLabel switchLabel = switchStatement.getFirstChildOfType(ASTSwitchLabel.class);
Assert.assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size());
} }
@Test(expected = ParseException.class) @Test(expected = ParseException.class)
@ -46,6 +51,23 @@ public class Java12Test {
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12", ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12",
loadSource("SwitchRules.java")); loadSource("SwitchRules.java"));
Assert.assertNotNull(compilationUnit); Assert.assertNotNull(compilationUnit);
ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class);
Assert.assertTrue(switchStatement.jjtGetChild(0) instanceof ASTExpression);
Assert.assertTrue(switchStatement.jjtGetChild(1) instanceof ASTSwitchLabeledRule);
ASTSwitchLabeledRule switchLabeledRule = (ASTSwitchLabeledRule) switchStatement.jjtGetChild(1);
Assert.assertEquals(2, switchLabeledRule.jjtGetNumChildren());
Assert.assertTrue(switchLabeledRule.jjtGetChild(0) instanceof ASTSwitchLabel);
Assert.assertTrue(switchLabeledRule.jjtGetChild(1) instanceof ASTExpression);
switchLabeledRule = (ASTSwitchLabeledRule) switchStatement.jjtGetChild(4);
Assert.assertEquals(2, switchLabeledRule.jjtGetNumChildren());
Assert.assertTrue(switchLabeledRule.jjtGetChild(0) instanceof ASTSwitchLabel);
Assert.assertTrue(switchLabeledRule.jjtGetChild(1) instanceof ASTBlock);
switchLabeledRule = (ASTSwitchLabeledRule) switchStatement.jjtGetChild(5);
Assert.assertEquals(2, switchLabeledRule.jjtGetNumChildren());
Assert.assertTrue(switchLabeledRule.jjtGetChild(0) instanceof ASTSwitchLabel);
Assert.assertTrue(switchLabeledRule.jjtGetChild(1) instanceof ASTThrowStatement);
} }
@Test(expected = ParseException.class) @Test(expected = ParseException.class)
@ -58,6 +80,11 @@ public class Java12Test {
ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12", ASTCompilationUnit compilationUnit = ParserTstUtil.parseAndTypeResolveJava("12",
loadSource("SwitchExpressions.java")); loadSource("SwitchExpressions.java"));
Assert.assertNotNull(compilationUnit); Assert.assertNotNull(compilationUnit);
ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class);
Assert.assertEquals(6, switchExpression.jjtGetNumChildren());
Assert.assertTrue(switchExpression.jjtGetChild(0) instanceof ASTExpression);
Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size());
} }
} }

View File

@ -14,7 +14,8 @@ public class SwitchRules {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(" 6"); case MONDAY, FRIDAY, SUNDAY -> System.out.println(" 6");
case TUESDAY -> System.out.println(" 7"); case TUESDAY -> System.out.println(" 7");
case THURSDAY, SATURDAY -> System.out.println(" 8"); case THURSDAY, SATURDAY -> System.out.println(" 8");
case WEDNESDAY -> System.out.println(" 9"); case WEDNESDAY -> { System.out.println(" 9"); }
default -> throw new IllegalArgumentException();
} }
} }
} }