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