View Javadoc

1   package net.sourceforge.pmd.lang.java.rule.basic;
2   
3   import java.util.List;
4   
5   import net.sourceforge.pmd.lang.ast.Node;
6   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
7   import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
8   import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
9   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  }