View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule.design;
5   
6   import java.util.List;
7   
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
10  import net.sourceforge.pmd.lang.java.ast.ASTExpression;
11  import net.sourceforge.pmd.lang.java.ast.ASTName;
12  import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
13  import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
14  import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
15  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16  
17  public class IdempotentOperationsRule extends AbstractJavaRule {
18  
19      @Override
20      public Object visit(ASTStatementExpression node, Object data) {
21          if (node.jjtGetNumChildren() != 3
22                  || !(node.jjtGetChild(0) instanceof ASTPrimaryExpression)
23                  || !(node.jjtGetChild(1) instanceof ASTAssignmentOperator)
24                  || ((ASTAssignmentOperator) node.jjtGetChild(1)).isCompound()
25                  || !(node.jjtGetChild(2) instanceof ASTExpression)
26                  || node.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0
27                  || node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() == 0
28          ) {
29              return super.visit(node, data);
30          }
31  
32          Node lhs = node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
33          if (!(lhs instanceof ASTName)) {
34              return super.visit(node, data);
35          }
36  
37          Node rhs = node.jjtGetChild(2).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
38          if (!(rhs instanceof ASTName)) {
39              return super.visit(node, data);
40          }
41  
42          if (!lhs.hasImageEqualTo(rhs.getImage())) {
43              return super.visit(node, data);
44          }
45  
46          if (lhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) {
47              Node n = lhs.jjtGetParent().jjtGetParent().jjtGetChild(1);
48              if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArrayDereference()) {
49                  return super.visit(node, data);
50              }
51          }
52  
53          if (rhs.jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) {
54              Node n = rhs.jjtGetParent().jjtGetParent().jjtGetChild(1);
55              if (n instanceof ASTPrimarySuffix && ((ASTPrimarySuffix) n).isArguments() || ((ASTPrimarySuffix) n).isArrayDereference()) {
56                  return super.visit(node, data);
57              }
58          }
59  
60          if (lhs.findDescendantsOfType(ASTPrimarySuffix.class).size() != rhs.findDescendantsOfType(ASTPrimarySuffix.class).size()) {
61              return super.visit(node, data);
62          }
63  
64          List<ASTPrimarySuffix> lhsSuffixes = lhs.jjtGetParent().jjtGetParent().findDescendantsOfType(ASTPrimarySuffix.class);
65          List<ASTPrimarySuffix> rhsSuffixes = rhs.jjtGetParent().jjtGetParent().findDescendantsOfType(ASTPrimarySuffix.class);
66          if (lhsSuffixes.size() != rhsSuffixes.size()) {
67              return super.visit(node, data);
68          }
69  
70          for (int i = 0; i < lhsSuffixes.size(); i++) {
71              ASTPrimarySuffix l = lhsSuffixes.get(i);
72              ASTPrimarySuffix r = rhsSuffixes.get(i);
73  
74              if (!l.hasImageEqualTo(r.getImage())) {
75                  return super.visit(node, data);
76              }
77          }
78  
79          addViolation(data, node);
80          return super.visit(node, data);
81      }
82  }