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