Fixes #793 [java] Parser error with private method in nested classes in interfaces
* Remember old state to allow nesting * Fix ASTMethodDeclaration.isInterfaceMember * Extended tests
This commit is contained in:
@ -343,7 +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.
|
||||
* The flag is also reset, if entering a anonymous inner class or enums.
|
||||
*/
|
||||
private boolean inInterface = false;
|
||||
private void checkForBadPrivateInterfaceMethod(ASTMethodDeclaration node) {
|
||||
@ -1417,6 +1417,7 @@ void ClassOrInterfaceDeclaration(int modifiers):
|
||||
{
|
||||
Token t = null;
|
||||
jjtThis.setModifiers(modifiers);
|
||||
boolean inInterfaceOld = inInterface;
|
||||
inInterface = false;
|
||||
}
|
||||
{
|
||||
@ -1427,7 +1428,7 @@ void ClassOrInterfaceDeclaration(int modifiers):
|
||||
[ ExtendsList() ]
|
||||
[ ImplementsList() ]
|
||||
ClassOrInterfaceBody()
|
||||
{ inInterface = false; } // always reset the flag after leaving the node
|
||||
{ inInterface = inInterfaceOld; } // always restore the flag after leaving the node
|
||||
}
|
||||
|
||||
void ExtendsList():
|
||||
@ -1468,13 +1469,18 @@ jjtThis.setModifiers(modifiers);
|
||||
}
|
||||
|
||||
void EnumBody():
|
||||
{}
|
||||
{
|
||||
boolean inInterfaceOld = inInterface;
|
||||
inInterface = false;
|
||||
}
|
||||
{
|
||||
"{"
|
||||
[( Annotation() )* EnumConstant() ( LOOKAHEAD(2) "," ( Annotation() )* EnumConstant() )* ]
|
||||
[ "," ]
|
||||
[ ";" ( ClassOrInterfaceBodyDeclaration() )* ]
|
||||
"}"
|
||||
|
||||
{ inInterface = inInterfaceOld; } // always restore the flag after leaving the node
|
||||
}
|
||||
|
||||
void EnumConstant():
|
||||
@ -2013,7 +2019,12 @@ void AllocationExpression():
|
||||
(
|
||||
ArrayDimsAndInits()
|
||||
|
|
||||
Arguments() [ {inInterface = false;} ClassOrInterfaceBody() ]
|
||||
Arguments()
|
||||
[
|
||||
{ boolean inInterfaceOld = inInterface; inInterface = false; /* a anonymous class is not a interface */ }
|
||||
ClassOrInterfaceBody()
|
||||
{ inInterface = inInterfaceOld; } // always restore the flag after leaving the node
|
||||
]
|
||||
)
|
||||
)
|
||||
{ checkForBadAnonymousDiamondUsage(); }
|
||||
|
@ -75,9 +75,12 @@ public class ASTMethodDeclaration extends AbstractJavaAccessNode implements DFAG
|
||||
|
||||
|
||||
public boolean isInterfaceMember() {
|
||||
ASTClassOrInterfaceBody body = getFirstParentOfType(ASTClassOrInterfaceBody.class);
|
||||
if (body != null && body.jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) {
|
||||
return ((ASTClassOrInterfaceDeclaration) body.jjtGetParent()).isInterface();
|
||||
// for a real class/interface the 3rd parent is a ClassOrInterfaceDeclaration,
|
||||
// for anonymous classes, the parent is e.g. a AllocationExpression
|
||||
Node potentialTypeDeclaration = getNthParent(3);
|
||||
|
||||
if (potentialTypeDeclaration instanceof ASTClassOrInterfaceDeclaration) {
|
||||
return ((ASTClassOrInterfaceDeclaration) potentialTypeDeclaration).isInterface();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -10,10 +10,14 @@ 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.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Test;
|
||||
@ -270,9 +274,22 @@ public class JDKVersionTest {
|
||||
}
|
||||
|
||||
@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());
|
||||
public final void jdk7PrivateMethodInnerClassInterface1() {
|
||||
ASTCompilationUnit acu = parseJava17(loadSource("private_method_in_inner_class_interface1.java"));
|
||||
List<ASTMethodDeclaration> methods = acu.findDescendantsOfType(ASTMethodDeclaration.class);
|
||||
assertEquals(3, methods.size());
|
||||
for (ASTMethodDeclaration method : methods) {
|
||||
assertFalse(method.isInterfaceMember());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void jdk7PrivateMethodInnerClassInterface2() {
|
||||
try {
|
||||
ASTCompilationUnit acu = parseJava17(loadSource("private_method_in_inner_class_interface2.java"));
|
||||
fail("Expected exception");
|
||||
} catch (ParseException e) {
|
||||
assertTrue(e.getMessage().startsWith("Line 19"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* 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() { }
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 class PrivateMethodsInInterface1 {
|
||||
|
||||
public interface Interface1 {
|
||||
Object FOO = new Object() {
|
||||
private void privateMethod() { }
|
||||
};
|
||||
}
|
||||
|
||||
public interface Interface2 {
|
||||
class InnerClass {
|
||||
private void privateMethod() { }
|
||||
}
|
||||
}
|
||||
|
||||
public interface Interface3 {
|
||||
enum InnerEnum {
|
||||
VALUE;
|
||||
private void privateMethod() { }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast.testdata;
|
||||
|
||||
/**
|
||||
* Prior to Java9, private methods are not possible.
|
||||
* Make sure, they are detected.
|
||||
*
|
||||
* @see https://github.com/pmd/pmd/issues/793
|
||||
*/
|
||||
public class PrivateMethodsInInterface2 {
|
||||
|
||||
public interface Interface1 {
|
||||
Object FOO = new Object() {
|
||||
private void privateMethod() { }
|
||||
};
|
||||
private void privateMethodInInterface1() { } // note: this will be a parser error!
|
||||
}
|
||||
|
||||
public interface Interface2 {
|
||||
class InnerClass {
|
||||
private void privateMethod() { }
|
||||
}
|
||||
}
|
||||
|
||||
public interface Interface3 {
|
||||
enum InnerEnum {
|
||||
VALUE;
|
||||
private void privateMethod() { }
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user