Fix ClassCastException on CloneMethodMustImplementCloneable
- Java 8 code allows for things such as `class UnmodifiableList<T> implements @Readonly List<@Readonly T> {}` where not all token in the ASTImplementsList are ASTClassOrInterfaceType
This commit is contained in:

committed by
Andreas Dangel

parent
f4f2402661
commit
238f6b721b
@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.typeresolution.rules;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.sourceforge.pmd.lang.ast.Node;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
|
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||||
@ -30,75 +31,81 @@ public class CloneMethodMustImplementCloneable extends AbstractJavaRule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
|
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
|
||||||
ASTImplementsList impl = node.getFirstChildOfType(ASTImplementsList.class);
|
ASTImplementsList impl = node.getFirstChildOfType(ASTImplementsList.class);
|
||||||
if (impl != null && impl.jjtGetParent().equals(node)) {
|
if (impl != null && impl.jjtGetParent().equals(node)) {
|
||||||
for (int ix = 0; ix < impl.jjtGetNumChildren(); ix++) {
|
for (int ix = 0; ix < impl.jjtGetNumChildren(); ix++) {
|
||||||
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) impl.jjtGetChild(ix);
|
Node child = impl.jjtGetChild(ix);
|
||||||
if (type.getType() == null) {
|
|
||||||
if ("Cloneable".equals(type.getImage())) {
|
if (child.getClass() != ASTClassOrInterfaceType.class) {
|
||||||
return data;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (type.getType().equals(Cloneable.class)) {
|
|
||||||
return data;
|
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) child;
|
||||||
} else {
|
if (type.getType() == null) {
|
||||||
List<Class<?>> implementors = Arrays.asList(type.getType().getInterfaces());
|
if ("Cloneable".equals(type.getImage())) {
|
||||||
if (implementors.contains(Cloneable.class)) {
|
return data;
|
||||||
return data;
|
}
|
||||||
}
|
} else if (type.getType().equals(Cloneable.class)) {
|
||||||
}
|
return data;
|
||||||
}
|
} else {
|
||||||
}
|
List<Class<?>> implementors = Arrays.asList(type.getType().getInterfaces());
|
||||||
if (node.jjtGetNumChildren() != 0 && node.jjtGetChild(0) instanceof ASTExtendsList) {
|
if (implementors.contains(Cloneable.class)) {
|
||||||
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) node.jjtGetChild(0).jjtGetChild(0);
|
return data;
|
||||||
Class<?> clazz = type.getType();
|
}
|
||||||
if (clazz != null && clazz.equals(Cloneable.class)) {
|
}
|
||||||
return data;
|
}
|
||||||
}
|
}
|
||||||
while (clazz != null && !Object.class.equals(clazz)) {
|
if (node.jjtGetNumChildren() != 0 && node.jjtGetChild(0) instanceof ASTExtendsList) {
|
||||||
if (Arrays.asList(clazz.getInterfaces()).contains(Cloneable.class)) {
|
ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) node.jjtGetChild(0).jjtGetChild(0);
|
||||||
return data;
|
Class<?> clazz = type.getType();
|
||||||
}
|
if (clazz != null && clazz.equals(Cloneable.class)) {
|
||||||
clazz = clazz.getSuperclass();
|
return data;
|
||||||
}
|
}
|
||||||
}
|
while (clazz != null && !Object.class.equals(clazz)) {
|
||||||
|
if (Arrays.asList(clazz.getInterfaces()).contains(Cloneable.class)) {
|
||||||
return super.visit(node, data);
|
return data;
|
||||||
|
}
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visit(node, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visit(ASTMethodDeclaration node, Object data) {
|
public Object visit(ASTMethodDeclaration node, Object data) {
|
||||||
ASTClassOrInterfaceDeclaration classOrInterface = node
|
ASTClassOrInterfaceDeclaration classOrInterface = node
|
||||||
.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
|
.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
|
||||||
if (classOrInterface != null && //Don't analyze enums, which cannot subclass clone()
|
if (classOrInterface != null && //Don't analyze enums, which cannot subclass clone()
|
||||||
(node.isFinal() || classOrInterface.isFinal())) {
|
(node.isFinal() || classOrInterface.isFinal())) {
|
||||||
if (node.findDescendantsOfType(ASTBlock.class).size() == 1) {
|
if (node.findDescendantsOfType(ASTBlock.class).size() == 1) {
|
||||||
List<ASTBlockStatement> blocks = node.findDescendantsOfType(ASTBlockStatement.class);
|
List<ASTBlockStatement> blocks = node.findDescendantsOfType(ASTBlockStatement.class);
|
||||||
if (blocks.size() == 1) {
|
if (blocks.size() == 1) {
|
||||||
ASTBlockStatement block = blocks.get(0);
|
ASTBlockStatement block = blocks.get(0);
|
||||||
ASTClassOrInterfaceType type = block.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
ASTClassOrInterfaceType type = block.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||||
if (type != null && type.getType() != null && type.getNthParent(9).equals(node)
|
if (type != null && type.getType() != null && type.getNthParent(9).equals(node)
|
||||||
&& type.getType().equals(CloneNotSupportedException.class)) {
|
&& type.getType().equals(CloneNotSupportedException.class)) {
|
||||||
return data;
|
return data;
|
||||||
} else if (type != null && type.getType() == null
|
} else if (type != null && type.getType() == null
|
||||||
&& "CloneNotSupportedException".equals(type.getImage())) {
|
&& "CloneNotSupportedException".equals(type.getImage())) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.visit(node, data);
|
return super.visit(node, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visit(ASTMethodDeclarator node, Object data) {
|
public Object visit(ASTMethodDeclarator node, Object data) {
|
||||||
if (!"clone".equals(node.getImage())) {
|
if (!"clone".equals(node.getImage())) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
int countParams = ((ASTFormalParameters) node.jjtGetChild(0)).jjtGetNumChildren();
|
int countParams = ((ASTFormalParameters) node.jjtGetChild(0)).jjtGetNumChildren();
|
||||||
if (countParams != 0) {
|
if (countParams != 0) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
addViolation(data, node);
|
addViolation(data, node);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user