diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index c9df30afa8..c6ff938d7c 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -21,6 +21,9 @@ This is a bug fixing release. ### Fixed Issues +* java + * [#793](https://github.com/pmd/pmd/issues/793): \[java] Parser error with private method in nested classes in interfaces + ### API Changes ### External Contributions \ No newline at end of file diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 71548d28e7..46f04e8fb8 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,7 @@ /** + * Fixes #793 [java] Parser error with private method in nested classes in interfaces + * Andreas Dangel 12/2017 + *==================================================================== * Add support for Java 9 changes: * Private interface methods are only allowed with java9. * A single underscore "_" is an invalid identifier in java9. @@ -340,6 +343,7 @@ public class JavaParser { * 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. + * The flag is also reset, if entering a anonymous inner class. */ private boolean inInterface = false; private void checkForBadPrivateInterfaceMethod(ASTMethodDeclaration node) { @@ -2009,7 +2013,7 @@ void AllocationExpression(): ( ArrayDimsAndInits() | - Arguments() [ ClassOrInterfaceBody() ] + Arguments() [ {inInterface = false;} ClassOrInterfaceBody() ] ) ) { checkForBadAnonymousDiamondUsage(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java index ca230e0626..c85e9f24c7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java @@ -75,8 +75,11 @@ public class ASTMethodDeclaration extends AbstractJavaAccessNode implements DFAG public boolean isInterfaceMember() { - ASTClassOrInterfaceDeclaration clz = getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); - return clz != null && clz.isInterface(); + ASTClassOrInterfaceBody body = getFirstParentOfType(ASTClassOrInterfaceBody.class); + if (body != null && body.jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) { + return ((ASTClassOrInterfaceDeclaration) body.jjtGetParent()).isInterface(); + } + return false; } public boolean isVoid() { 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 aef4882b70..71e49f2cd4 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 @@ -10,6 +10,7 @@ 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 static org.junit.Assert.assertFalse; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -267,4 +268,11 @@ public class JDKVersionTest { public final void jdk9TryWithResources() { parseJava9(loadSource("jdk9_try_with_resources.java")); } + + @Test + public final void jdk7PrivateMethodInnerClassInterface() { + ASTCompilationUnit acu = parseJava17(loadSource("private_method_in_inner_class_interface.java")); + ASTMethodDeclaration privateMethod = acu.getFirstDescendantOfType(ASTMethodDeclaration.class); + assertFalse(privateMethod.isInterfaceMember()); + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/private_method_in_inner_class_interface.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/private_method_in_inner_class_interface.java new file mode 100644 index 0000000000..8cc67a7e62 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/private_method_in_inner_class_interface.java @@ -0,0 +1,28 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast.testdata; + +/** + * With Java9, private methods in interfaces are possible. + * But they must not be confused with private methods in inner classes of interfaces + * when using older java version. + * + * @see https://github.com/pmd/pmd/issues/793 + */ +public interface InterfaceWithInnerClass { + + Object FOO = new Object() { + private void privateMethod() { } + }; + + class InnerClass { + private void privateMethod() { } + } + + enum InnerEnum { + VALUE; + private void privateMethod() { } + } +}