[java] Add Java12 support
This commit is contained in:
@ -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() )
|
|
||||||
|
|
|
|
||||||
":" (SwitchLabel() ":")* ( BlockStatement() )*
|
(LOOKAHEAD(3) SwitchLabeledStatementGroup() )* (SwitchLabel() ":")*
|
||||||
)
|
)
|
||||||
)*
|
"}"
|
||||||
/*
|
|
||||||
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():
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
||||||
}
|
}
|
||||||
@ -12,8 +16,7 @@ class ASTSwitchExpression extends AbstractJavaNode {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
||||||
}
|
}
|
||||||
@ -12,8 +16,7 @@ class ASTSwitchLabeledRule extends AbstractJavaNode {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user