/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.rules; import net.sourceforge.pmd.AbstractRule; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.ast.ASTBlock; import net.sourceforge.pmd.ast.ASTBlockStatement; import net.sourceforge.pmd.ast.ASTBooleanLiteral; import net.sourceforge.pmd.ast.ASTIfStatement; import net.sourceforge.pmd.ast.ASTReturnStatement; import net.sourceforge.pmd.ast.ASTStatement; import net.sourceforge.pmd.ast.SimpleNode; public class SimplifyBooleanReturnsRule extends AbstractRule { public Object visit(ASTIfStatement node, Object data) { // only deal with if..then..else stmts if (node.jjtGetNumChildren() != 3) { return super.visit(node, data); } // don't bother if either the if or the else block is empty if (node.jjtGetChild(1).jjtGetNumChildren() == 0 || node.jjtGetChild(2).jjtGetNumChildren() == 0) { return super.visit(node, data); } // first case: // If // Expr // Statement // ReturnStatement // Statement // ReturnStatement // i.e., // if (foo) // return true; // else // return false; // second case // If // Expr // Statement // Block // BlockStatement // Statement // ReturnStatement // Statement // Block // BlockStatement // Statement // ReturnStatement // i.e., // if (foo) { // return true; // } else { // return false; // } 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))) { RuleContext ctx = (RuleContext) data; ctx.getReport().addRuleViolation(createRuleViolation(ctx, node.getBeginLine())); } 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))) { RuleContext ctx = (RuleContext) data; ctx.getReport().addRuleViolation(createRuleViolation(ctx, node.getBeginLine())); } return super.visit(node, data); } private boolean hasOneBlockStmt(SimpleNode node) { 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; } private boolean terminatesInBooleanLiteral(SimpleNode node) { return eachNodeHasOneChild(node) && (getLastChild(node) instanceof ASTBooleanLiteral); } private boolean eachNodeHasOneChild(SimpleNode node) { if (node.jjtGetNumChildren() > 1) { return false; } if (node.jjtGetNumChildren() == 0) { return true; } return eachNodeHasOneChild((SimpleNode) node.jjtGetChild(0)); } private SimpleNode getLastChild(SimpleNode node) { if (node.jjtGetNumChildren() == 0) { return node; } return getLastChild((SimpleNode) node.jjtGetChild(0)); } }