View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.rules;
5   
6   import net.sourceforge.pmd.AbstractRule;
7   import net.sourceforge.pmd.ast.ASTBlock;
8   import net.sourceforge.pmd.ast.ASTBlockStatement;
9   import net.sourceforge.pmd.ast.ASTBooleanLiteral;
10  import net.sourceforge.pmd.ast.ASTIfStatement;
11  import net.sourceforge.pmd.ast.ASTReturnStatement;
12  import net.sourceforge.pmd.ast.ASTStatement;
13  import net.sourceforge.pmd.ast.SimpleNode;
14  
15  public class SimplifyBooleanReturns extends AbstractRule {
16  
17      public Object visit(ASTIfStatement node, Object data) {
18          // only deal with if..then..else stmts
19          if (node.jjtGetNumChildren() != 3) {
20              return super.visit(node, data);
21          }
22  
23          // don't bother if either the if or the else block is empty
24          if (node.jjtGetChild(1).jjtGetNumChildren() == 0 || node.jjtGetChild(2).jjtGetNumChildren() == 0) {
25              return super.visit(node, data);
26          }
27  
28          // first case:
29          // If
30          //  Expr
31          //  Statement
32          //   ReturnStatement
33          //  Statement
34          //   ReturnStatement
35          // i.e.,
36          // if (foo)
37          //  return true;
38          // else
39          //  return false;
40  
41          // second case
42          // If
43          // Expr
44          // Statement
45          //  Block
46          //   BlockStatement
47          //    Statement
48          //     ReturnStatement
49          // Statement
50          //  Block
51          //   BlockStatement
52          //    Statement
53          //     ReturnStatement
54          // i.e.,
55          // if (foo) {
56          //  return true;
57          // } else {
58          //  return false;
59          // }
60          if (node.jjtGetChild(1).jjtGetChild(0) instanceof ASTReturnStatement && node.jjtGetChild(2).jjtGetChild(0) instanceof ASTReturnStatement && terminatesInBooleanLiteral((SimpleNode) node.jjtGetChild(1).jjtGetChild(0)) && terminatesInBooleanLiteral((SimpleNode) node.jjtGetChild(2).jjtGetChild(0))) {
61              addViolation(data, node);
62          } else if (hasOneBlockStmt((SimpleNode) node.jjtGetChild(1)) && hasOneBlockStmt((SimpleNode) node.jjtGetChild(2)) && terminatesInBooleanLiteral((SimpleNode) node.jjtGetChild(1).jjtGetChild(0)) && terminatesInBooleanLiteral((SimpleNode) node.jjtGetChild(2).jjtGetChild(0))) {
63              addViolation(data, node);
64          }
65  
66          return super.visit(node, data);
67      }
68  
69      private boolean hasOneBlockStmt(SimpleNode node) {
70          return node.jjtGetChild(0) instanceof ASTBlock && node.jjtGetChild(0).jjtGetNumChildren() == 1 && node.jjtGetChild(0).jjtGetChild(0) instanceof ASTBlockStatement && node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTStatement && node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTReturnStatement;
71      }
72  
73      private boolean terminatesInBooleanLiteral(SimpleNode node) {
74          return eachNodeHasOneChild(node) && (getLastChild(node) instanceof ASTBooleanLiteral);
75      }
76  
77      private boolean eachNodeHasOneChild(SimpleNode node) {
78          if (node.jjtGetNumChildren() > 1) {
79              return false;
80          }
81          if (node.jjtGetNumChildren() == 0) {
82              return true;
83          }
84          return eachNodeHasOneChild((SimpleNode) node.jjtGetChild(0));
85      }
86  
87      private SimpleNode getLastChild(SimpleNode node) {
88          if (node.jjtGetNumChildren() == 0) {
89              return node;
90          }
91          return getLastChild((SimpleNode) node.jjtGetChild(0));
92      }
93  }