01 package net.sourceforge.pmd.lang.java.rule.basic;
02
03 import java.util.List;
04
05 import net.sourceforge.pmd.lang.ast.Node;
06 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
07 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
08 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
09 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 }
|