forked from phoedos/pmd
Add Java9 Language Module, Update grammar
* Java8 mode now rejects private methods in interfaces * Java9 mode now rejects "_" as identifier
This commit is contained in:
@ -1,4 +1,9 @@
|
||||
/**
|
||||
* Add support for Java 9 changes
|
||||
* private interface methods are only allowed with java9,
|
||||
* a single underscore "_" is an invalid identifier in java9.
|
||||
* Andreas Dangel 09/2017
|
||||
*====================================================================
|
||||
* Add support for new Java 8 annotation locations.
|
||||
* Bugs #414, #415, #417
|
||||
* @Snap252 06/2017
|
||||
@ -319,6 +324,22 @@ public class JavaParser {
|
||||
throwParseException("Cannot use explicit receiver parameters when running in JDK inferior to 1.8 mode!");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Keeps track whether we are dealing with an interface or not. Needed since the tree is
|
||||
* is not fully constructed yet, when we check for private interface methods.
|
||||
* The flag is updated, if entering ClassOrInterfaceDeclaration and reset when leaving.
|
||||
*/
|
||||
private boolean inInterface = false;
|
||||
private void checkForBadPrivateInterfaceMethod(ASTMethodDeclaration node) {
|
||||
if (jdkVersion < 9 && inInterface && node.isPrivate()) {
|
||||
throwParseException("Cannot use private interface methods when running in JDK inferior to 9 mode!");
|
||||
}
|
||||
}
|
||||
private void checkForBadIdentifier(String image) {
|
||||
if (jdkVersion >= 9 && "_".equals(image)) {
|
||||
throwParseException("With JDK 9, '_' is a keyword, and may not be used as an identifier!");
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -1343,12 +1364,14 @@ jjtThis.setModifiers(modifiers);
|
||||
}
|
||||
{
|
||||
|
||||
( /* See note about this optional final modifier in BlockStatement */ ["final"|"abstract"] "class" | "interface" { jjtThis.setInterface(); } )
|
||||
( /* See note about this optional final modifier in BlockStatement */
|
||||
["final"|"abstract"] "class" | "interface" { jjtThis.setInterface(); inInterface = true; } )
|
||||
t=<IDENTIFIER> { jjtThis.setImage(t.image); }
|
||||
[ TypeParameters() ]
|
||||
[ ExtendsList() ]
|
||||
[ ImplementsList() ]
|
||||
ClassOrInterfaceBody()
|
||||
{ inInterface = false; } // always reset the flag after leaving the node
|
||||
}
|
||||
|
||||
void ExtendsList():
|
||||
@ -1446,6 +1469,7 @@ void ClassOrInterfaceBodyDeclaration():
|
||||
";"
|
||||
}
|
||||
|
||||
|
||||
void FieldDeclaration(int modifiers) :
|
||||
{jjtThis.setModifiers(modifiers);}
|
||||
{
|
||||
@ -1471,6 +1495,7 @@ void VariableDeclaratorId() :
|
||||
{
|
||||
checkForBadAssertUsage(image, "a variable name");
|
||||
checkForBadEnumUsage(image, "a variable name");
|
||||
checkForBadIdentifier(image);
|
||||
jjtThis.setImage( image );
|
||||
}
|
||||
}
|
||||
@ -1489,7 +1514,10 @@ void ArrayInitializer() :
|
||||
}
|
||||
|
||||
void MethodDeclaration(int modifiers) :
|
||||
{jjtThis.setModifiers(modifiers);}
|
||||
{
|
||||
jjtThis.setModifiers(modifiers);
|
||||
{ checkForBadPrivateInterfaceMethod(jjtThis); }
|
||||
}
|
||||
{
|
||||
[ TypeParameters() ]
|
||||
(Annotation() {checkForBadTypeAnnotations();})* ResultType() MethodDeclarator() [ "throws" NameList() ]
|
||||
|
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java;
|
||||
|
||||
import net.sourceforge.pmd.lang.Parser;
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
|
||||
public class Java19Handler extends AbstractJavaHandler {
|
||||
|
||||
public Parser getParser(ParserOptions parserOptions) {
|
||||
return new Java19Parser(parserOptions);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java;
|
||||
|
||||
import java.io.Reader;
|
||||
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaParser;
|
||||
import net.sourceforge.pmd.lang.java.ast.ParseException;
|
||||
|
||||
/**
|
||||
* Adapter for the JavaParser, using Java 1.9 grammar.
|
||||
*/
|
||||
public class Java19Parser extends AbstractJavaParser {
|
||||
|
||||
public Java19Parser(ParserOptions parserOptions) {
|
||||
super(parserOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JavaParser createJavaParser(Reader source) throws ParseException {
|
||||
JavaParser javaParser = super.createJavaParser(source);
|
||||
javaParser.setJdkVersion(9);
|
||||
return javaParser;
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ public class JavaLanguageModule extends BaseLanguageModule {
|
||||
addVersion("1.6", new Java16Handler(), false);
|
||||
addVersion("1.7", new Java17Handler(), false);
|
||||
addVersion("1.8", new Java18Handler(), true);
|
||||
addVersion("9", new Java19Handler(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -145,6 +145,11 @@ public class ParserTstUtil {
|
||||
return parseJava(getLanguageVersionHandler("1.8"), code);
|
||||
}
|
||||
|
||||
/** @see #parseJava(LanguageVersionHandler, String) */
|
||||
public static ASTCompilationUnit parseJava9(String code) {
|
||||
return parseJava(getLanguageVersionHandler("9"), code);
|
||||
}
|
||||
|
||||
/** @see #parseJava(LanguageVersionHandler, String) */
|
||||
public static ASTCompilationUnit parseJava13(Class<?> source) {
|
||||
return parseJava13(getSourceFromClass(source));
|
||||
@ -170,6 +175,11 @@ public class ParserTstUtil {
|
||||
return parseJava18(getSourceFromClass(source));
|
||||
}
|
||||
|
||||
/** @see #parseJava(LanguageVersionHandler, String) */
|
||||
public static ASTCompilationUnit parseJava9(Class<?> source) {
|
||||
return parseJava9(getSourceFromClass(source));
|
||||
}
|
||||
|
||||
/** @see #parseJava(LanguageVersionHandler, String) */
|
||||
public static ASTCompilationUnit parseJavaDefaultVersion(String source) {
|
||||
return parseJava(getDefaultLanguageVersionHandler(), source);
|
||||
|
@ -8,6 +8,8 @@ import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava13;
|
||||
import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava14;
|
||||
import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava15;
|
||||
import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava17;
|
||||
import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava18;
|
||||
import static net.sourceforge.pmd.lang.java.ParserTstUtil.parseJava9;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -205,4 +207,29 @@ public class JDKVersionTest {
|
||||
public final void testMulticatchWithAnnotations() {
|
||||
parseJava17(loadSource("jdk17_multicatch_with_annotations.java"));
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public final void jdk9PrivateInterfaceMethodsInJava18() {
|
||||
parseJava18(loadSource("jdk9_private_interface_methods.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testPrivateMethods() {
|
||||
parseJava18("public class Foo { private void bar() { } }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void jdk9PrivateInterfaceMethods() {
|
||||
parseJava9(loadSource("jdk9_private_interface_methods.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void jdk9InvalidIdentifierInJava18() {
|
||||
parseJava18(loadSource("jdk9_invalid_identifier.java"));
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public final void jdk9InvalidIdentifier() {
|
||||
parseJava9(loadSource("jdk9_invalid_identifier.java"));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Using "_" as an identifier is not allowed anymore with java9.
|
||||
*/
|
||||
public class Java9Identifier {
|
||||
|
||||
/*
|
||||
* see https://bugs.openjdk.java.net/browse/JDK-8061549
|
||||
*/
|
||||
public interface Lambda {
|
||||
public int a(int _);
|
||||
public default void t(Lambda l) {
|
||||
t(_ -> 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* With java9, private methods are allowed in interface.
|
||||
*/
|
||||
public class Java9Interface {
|
||||
|
||||
public interface Tool {
|
||||
void use();
|
||||
|
||||
default String getName() {
|
||||
return determineName();
|
||||
}
|
||||
|
||||
default String getStaticName() {
|
||||
return determineNameStatic();
|
||||
}
|
||||
|
||||
private String determineName() {
|
||||
return "unknown:" + this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private static String determineNameStatic() {
|
||||
return "unknown:" + Tool.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SampleTool implements Tool {
|
||||
|
||||
public void use() {
|
||||
if (true) { // force a PMD violation: java-basic/UnconditionalIfStatement
|
||||
System.out.println("Instance: " + getName());
|
||||
System.out.println(" Static: " + getStaticName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
Tool tool = new SampleTool();
|
||||
tool.use();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user