View Javadoc

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                  ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType)node.jjtGetChild(ix);
44                  Class clazz = cit.getType();
45                  if (clazz != null || ((SimpleNode) node.jjtGetChild(ix)).hasImageEqualTo("Comparable")) {
46                      implementsComparable = true;
47                      return data;
48                  }
49              }
50          }
51          return super.visit(node, data);
52      }
53  
54      public Object visit(ASTMethodDeclarator node, Object data) {
55          if (implementsComparable) {
56              return data;
57          }
58  
59          int iFormalParams = 0;
60          String paramName = null;
61          for (int ix = 0; ix < node.jjtGetNumChildren(); ix++) {
62              SimpleNode sn = (SimpleNode) node.jjtGetChild(ix);
63              if (sn.getClass().equals(ASTFormalParameters.class)) {
64                  List<ASTFormalParameter> allParams = ((ASTFormalParameters) sn).findChildrenOfType(ASTFormalParameter.class);
65                  for (ASTFormalParameter formalParam: allParams) {
66                      iFormalParams++;
67                      ASTClassOrInterfaceType param = formalParam.getFirstChildOfType(ASTClassOrInterfaceType.class);
68                      if (param != null) {
69                          paramName = param.getImage();
70                      }
71                  }
72              }
73          }
74  
75          if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) {
76              containsHashCode = true;
77              nodeFound = node;
78          } else if (iFormalParams == 1 && node.hasImageEqualTo("equals") && ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) {
79              containsEquals = true;
80              nodeFound = node;
81          }
82          return super.visit(node, data);
83      }
84  
85  }