OverrideBothEqualsAndHashcodeRule.java
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(ixinstanceof ASTClassOrInterfaceType) {
45     ASTClassOrInterfaceType cit = (ASTClassOrInterfaceTypenode.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 = ((ASTFormalParameterssn)
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 == && node.hasImageEqualTo("hashCode")) {
80       containsHashCode = true;
81       nodeFound = node;
82   else if (iFormalParams == && 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 }