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