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  }