View Javadoc

1   package net.sourceforge.pmd.rules.design;
2   
3   import net.sourceforge.pmd.AbstractRule;
4   import net.sourceforge.pmd.ast.ASTAllocationExpression;
5   import net.sourceforge.pmd.ast.ASTEqualityExpression;
6   import net.sourceforge.pmd.ast.ASTInitializer;
7   import net.sourceforge.pmd.ast.ASTName;
8   import net.sourceforge.pmd.ast.Node;
9   import net.sourceforge.pmd.ast.SimpleNode;
10  import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
11  
12  public class CompareObjectsWithEquals extends AbstractRule {
13  
14      private boolean hasName(Node n) {
15          return n.jjtGetNumChildren() > 0 && n.jjtGetChild(0) instanceof ASTName;
16      }
17      
18      /**
19  	 * Indicate whether this node is allocating a new object.
20  	 * 
21  	 * @param n
22  	 *            node that might be allocating a new object
23  	 * @return true if child 0 is an AllocationExpression
24  	 */
25  	private boolean isAllocation(Node n) {
26          return n.jjtGetNumChildren() > 0 && n.jjtGetChild(0) instanceof ASTAllocationExpression && n.jjtGetParent().jjtGetNumChildren() == 1;
27  	}
28          
29      public Object visit(ASTEqualityExpression node, Object data) {
30          Node c0 = node.jjtGetChild(0).jjtGetChild(0);
31          Node c1 = node.jjtGetChild(1).jjtGetChild(0);
32  
33          // If either side is allocating a new object, there's no way an
34          // equals expression is correct
35          if ((isAllocation(c0)) || (isAllocation(c1))) {
36              addViolation(data, node);
37              return data;
38          }
39          
40          // skip if either child is not a simple name
41          if (!hasName(c0) || !hasName(c1)) {
42              return data;
43          }
44  
45          // skip if either is a qualified name
46          if (isQualifiedName((SimpleNode) c0.jjtGetChild(0)) || isQualifiedName((SimpleNode) c1.jjtGetChild(0))) {
47              return data;
48          }
49  
50          // skip static initializers... missing some cases here
51          if (!node.getParentsOfType(ASTInitializer.class).isEmpty()) {
52              return data;
53          }
54                
55          ASTName n0 = (ASTName) c0.jjtGetChild(0);
56          ASTName n1 = (ASTName) c1.jjtGetChild(0);
57  
58          if (n0.getNameDeclaration() instanceof VariableNameDeclaration && n1.getNameDeclaration() instanceof VariableNameDeclaration) {
59              VariableNameDeclaration nd0 = (VariableNameDeclaration) n0.getNameDeclaration();
60              VariableNameDeclaration nd1 = (VariableNameDeclaration) n1.getNameDeclaration();
61  
62              // skip array dereferences... this misses some cases
63              // FIXME catch comparisons btwn array elements of reference types
64              if (nd0.isArray() || nd1.isArray()) {
65                  return data;
66              }
67  
68              if (nd0.isReferenceType() && nd1.isReferenceType()) {
69                  addViolation(data, node);
70              }
71          }
72  
73          return data;
74      }
75  }