/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.basic;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule {
private boolean implementsComparable = false;
private boolean containsEquals = false;
private boolean containsHashCode = false;
private Node nodeFound = null;
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.isInterface()) {
return data;
}
super.visit(node, data);
if (!implementsComparable && containsEquals ^ containsHashCode) {
if (nodeFound == null) {
nodeFound = node;
}
addViolation(data, nodeFound);
}
implementsComparable = false;
containsEquals = false;
containsHashCode = false;
nodeFound = null;
return data;
}
@Override
public Object visit(ASTImplementsList node, Object data) {
for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) {
if (node.jjtGetChild(ix) instanceof ASTClassOrInterfaceType) {
ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.jjtGetChild(ix);
Class<?> clazz = cit.getType();
if (clazz != null && node.jjtGetChild(ix).hasImageEqualTo("Comparable")) {
implementsComparable = true;
return data;
}
}
}
return super.visit(node, data);
}
@Override
public Object visit(ASTMethodDeclarator node, Object data) {
if (implementsComparable) {
return data;
}
int iFormalParams = 0;
String paramName = null;
for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) {
Node sn = node.jjtGetChild(ix);
if (sn instanceof ASTFormalParameters) {
List<ASTFormalParameter> allParams = ((ASTFormalParameters) sn)
.findChildrenOfType(ASTFormalParameter.class);
for (ASTFormalParameter formalParam : allParams) {
iFormalParams++;
ASTClassOrInterfaceType param = formalParam.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
if (param != null) {
paramName = param.getImage();
}
}
}
}
if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) {
containsHashCode = true;
nodeFound = node;
} else if (iFormalParams == 1 && node.hasImageEqualTo("equals")
&& ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) {
containsEquals = true;
nodeFound = node;
}
return super.visit(node, data);
}
}