/** * 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); } }