From 77222904de33f6eeb0a107022cc03f69a0180147 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Sep 2017 14:31:24 +0200 Subject: [PATCH] Check for diamond operator for anonymous classes --- pmd-java/etc/grammar/Java.jjt | 17 ++++++++++++++--- .../lang/java/ast/ASTAllocationExpression.java | 10 ++++++++++ .../pmd/lang/java/ast/ASTTypeArguments.java | 4 ++++ .../pmd/lang/java/ast/JDKVersionTest.java | 10 ++++++++++ .../jdkversiontests/jdk9_anonymous_diamond.java | 8 ++++++++ 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_anonymous_diamond.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 18ad2d4435..c3910615c0 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,7 +1,8 @@ /** - * Add support for Java 9 changes - * private interface methods are only allowed with java9, - * a single underscore "_" is an invalid identifier in java9. + * Add support for Java 9 changes: + * Private interface methods are only allowed with java9. + * A single underscore "_" is an invalid identifier in java9. + * Diamond operator for anonymous classes is only allowed with java9. * Andreas Dangel 09/2017 *==================================================================== * Add support for new Java 8 annotation locations. @@ -324,6 +325,15 @@ public class JavaParser { throwParseException("Cannot use explicit receiver parameters when running in JDK inferior to 1.8 mode!"); } } + private void checkForBadAnonymousDiamondUsage() { + if (jdkVersion < 9) { + ASTAllocationExpression node = (ASTAllocationExpression)jjtree.peekNode(); + ASTTypeArguments types = node.getFirstDescendantOfType(ASTTypeArguments.class); + if (node.isAnonymousClass() && types != null && types.isDiamond()) { + throwParseException("Cannot use '<>' with anonymous inner classes when running in JDK inferior to 9 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. @@ -1960,6 +1970,7 @@ void AllocationExpression(): Arguments() [ ClassOrInterfaceBody() ] ) ) + { checkForBadAnonymousDiamondUsage(); } } /* diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java index fbf7293a61..3d7bb093e8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.lang.ast.Node; + public class ASTAllocationExpression extends AbstractJavaTypeNode { public ASTAllocationExpression(int id) { super(id); @@ -20,4 +22,12 @@ public class ASTAllocationExpression extends AbstractJavaTypeNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + public boolean isAnonymousClass() { + if (jjtGetNumChildren() > 1) { + Node lastChild = jjtGetChild(jjtGetNumChildren() - 1); + return lastChild instanceof ASTClassOrInterfaceBody; + } + return false; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java index 0367669904..99f2483bd0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java @@ -20,4 +20,8 @@ public class ASTTypeArguments extends AbstractJavaNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + public boolean isDiamond() { + return jjtGetNumChildren() == 0; + } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java index faa604cea0..861b9215b8 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java @@ -237,4 +237,14 @@ public class JDKVersionTest { public final void jdk9InvalidIdentifier() { parseJava9(loadSource("jdk9_invalid_identifier.java")); } + + @Test(expected = ParseException.class) + public final void jdk9AnonymousDiamondInJava8() { + parseJava18(loadSource("jdk9_anonymous_diamond.java")); + } + + @Test + public final void jdk9AnonymousDiamond() { + parseJava9(loadSource("jdk9_anonymous_diamond.java")); + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_anonymous_diamond.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_anonymous_diamond.java new file mode 100644 index 0000000000..722c104592 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_anonymous_diamond.java @@ -0,0 +1,8 @@ +import java.util.HashSet; +import java.util.Set; + +public class Java9AnonymousDiamond { + public static void main(String ... args) { + Set set = new HashSet<>() { }; + } +} \ No newline at end of file