1 package net.sourceforge.pmd.lang.java.rule.basic; 2 3 import java.util.List; 4 5 import net.sourceforge.pmd.lang.ast.Node; 6 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; 7 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; 8 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; 9 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; 10 import net.sourceforge.pmd.lang.java.ast.ASTImplementsList; 11 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; 12 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; 13 14 public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule { 15 16 private boolean implementsComparable = false; 17 18 private boolean containsEquals = false; 19 20 private boolean containsHashCode = false; 21 22 private Node nodeFound = null; 23 24 @Override 25 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { 26 if (node.isInterface()) { 27 return data; 28 } 29 super.visit(node, data); 30 if (!implementsComparable && containsEquals ^ containsHashCode) { 31 if (nodeFound == null) { 32 nodeFound = node; 33 } 34 addViolation(data, nodeFound); 35 } 36 implementsComparable = containsEquals = containsHashCode = false; 37 nodeFound = null; 38 return data; 39 } 40 41 @Override 42 public Object visit(ASTImplementsList node, Object data) { 43 for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) { 44 if (node.jjtGetChild(ix) instanceof ASTClassOrInterfaceType) { 45 ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.jjtGetChild(ix); 46 Class<?> clazz = cit.getType(); 47 if (clazz != null || node.jjtGetChild(ix).hasImageEqualTo("Comparable")) { 48 implementsComparable = true; 49 return data; 50 } 51 } 52 } 53 return super.visit(node, data); 54 } 55 56 @Override 57 public Object visit(ASTMethodDeclarator node, Object data) { 58 if (implementsComparable) { 59 return data; 60 } 61 62 int iFormalParams = 0; 63 String paramName = null; 64 for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) { 65 Node sn = node.jjtGetChild(ix); 66 if (sn instanceof ASTFormalParameters) { 67 List<ASTFormalParameter> allParams = ((ASTFormalParameters) sn) 68 .findChildrenOfType(ASTFormalParameter.class); 69 for (ASTFormalParameter formalParam : allParams) { 70 iFormalParams++; 71 ASTClassOrInterfaceType param = formalParam.getFirstDescendantOfType(ASTClassOrInterfaceType.class); 72 if (param != null) { 73 paramName = param.getImage(); 74 } 75 } 76 } 77 } 78 79 if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) { 80 containsHashCode = true; 81 nodeFound = node; 82 } else if (iFormalParams == 1 && node.hasImageEqualTo("equals") 83 && ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) { 84 containsEquals = true; 85 nodeFound = node; 86 } 87 return super.visit(node, data); 88 } 89 90 }