[java] ProperCloneImplementation not valid for final class

This commit is contained in:
Mykhailo Palahuta
2020-08-06 12:04:01 +03:00
parent b273774ea7
commit 2d176f73ee
2 changed files with 37 additions and 22 deletions

View File

@ -8,7 +8,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
@ -21,36 +20,40 @@ public class ProperCloneImplementationRule extends AbstractJavaRule {
}
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
if (!"clone".equals(node.getName()) || node.getArity() > 0) {
return data;
public Object visit(ASTMethodDeclaration method, Object data) {
if (isCloneMethod(method) && isNotAbstractMethod(method)) {
ASTClassOrInterfaceDeclaration classDecl = method.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
if (isNotFinal(classDecl) && hasAnyAllocationOfClass(method, classDecl.getSimpleName())) {
addViolation(data, method);
}
}
ASTBlock block = node.getFirstChildOfType(ASTBlock.class);
if (block == null) {
return data;
}
String enclosingClassName = node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class).getSimpleName();
if (blockHasAllocations(block, enclosingClassName)) {
addViolation(data, node);
}
return data;
}
private boolean blockHasAllocations(ASTBlock block, String enclosingClassName) {
List<ASTAllocationExpression> allocations = block.findDescendantsOfType(ASTAllocationExpression.class);
for (ASTAllocationExpression alloc : allocations) {
ASTClassOrInterfaceType type = alloc.getFirstChildOfType(ASTClassOrInterfaceType.class);
if (typeHasImage(type, enclosingClassName)) {
private boolean isCloneMethod(ASTMethodDeclaration method) {
return "clone".equals(method.getName()) && method.getArity() == 0;
}
private boolean isNotAbstractMethod(ASTMethodDeclaration method) {
return !method.isAbstract();
}
private boolean isNotFinal(ASTClassOrInterfaceDeclaration classOrInterfaceDecl) {
return !classOrInterfaceDecl.isFinal();
}
private boolean hasAnyAllocationOfClass(ASTMethodDeclaration method, String className) {
List<ASTAllocationExpression> allocations = method.findDescendantsOfType(ASTAllocationExpression.class);
for (ASTAllocationExpression allocation : allocations) {
ASTClassOrInterfaceType allocatedType = allocation.getFirstChildOfType(ASTClassOrInterfaceType.class);
if (isSimpleNameOfType(className, allocatedType)) {
return true;
}
}
return false;
}
private boolean typeHasImage(ASTClassOrInterfaceType type, String image) {
return type != null && type.hasImageEqualTo(image);
private boolean isSimpleNameOfType(String simpleName, ASTClassOrInterfaceType type) {
return type != null && type.hasImageEqualTo(simpleName);
}
}

View File

@ -63,6 +63,18 @@ public class Foo {
super.clone();
byte[] array = new byte[6];
}
}
]]></code>
</test-code>
<test-code>
<description>ok, final class false-positive</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
final class Foo {
Foo clone() {
return new Foo();
}
}
]]></code>
</test-code>