Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanReturnCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
SimplifyBooleanReturnCheck
100%
25/25
83%
20/24
3.6
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2014  Oliver Burn
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle.checks.coding;
 21  
 
 22  
 import antlr.collections.AST;
 23  
 import com.puppycrawl.tools.checkstyle.api.Check;
 24  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 25  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 26  
 
 27  
 
 28  
 /**
 29  
  * <p>
 30  
  * Checks for overly complicated boolean return statements.
 31  
  * Idea shamelessly stolen from the equivalent PMD rule (pmd.sourceforge.net).
 32  
  * </p>
 33  
  * <p>
 34  
  * An example of how to configure the check is:
 35  
  * </p>
 36  
  * <pre>
 37  
  * &lt;module name="SimplifyBooleanReturn"/&gt;
 38  
  * </pre>
 39  
  * @author Lars Kühne
 40  
  */
 41  1
 public class SimplifyBooleanReturnCheck
 42  
     extends Check
 43  
 {
 44  
     @Override
 45  
     public int[] getDefaultTokens()
 46  
     {
 47  1
         return new int[] {TokenTypes.LITERAL_IF};
 48  
     }
 49  
 
 50  
     @Override
 51  
     public void visitToken(DetailAST aAST)
 52  
     {
 53  
         // LITERAL_IF has the following four or five children:
 54  
         // '('
 55  
         // condition
 56  
         // ')'
 57  
         // thenStatement
 58  
         // [ LITERAL_ELSE (with the elseStatement as a child) ]
 59  
 
 60  
         // don't bother if this is not if then else
 61  5
         final AST elseLiteral =
 62  
             aAST.findFirstToken(TokenTypes.LITERAL_ELSE);
 63  5
         if (elseLiteral == null) {
 64  1
             return;
 65  
         }
 66  4
         final AST elseStatement = elseLiteral.getFirstChild();
 67  
 
 68  
         // skip '(' and ')'
 69  
         // TODO: Introduce helpers in DetailAST
 70  4
         final AST condition = aAST.getFirstChild().getNextSibling();
 71  4
         final AST thenStatement = condition.getNextSibling().getNextSibling();
 72  
 
 73  4
         if (returnsOnlyBooleanLiteral(thenStatement)
 74  
             && returnsOnlyBooleanLiteral(elseStatement))
 75  
         {
 76  2
             log(aAST.getLineNo(), aAST.getColumnNo(), "simplify.boolreturn");
 77  
         }
 78  4
     }
 79  
 
 80  
     /**
 81  
      * Returns if an AST is a return statment with a boolean literal
 82  
      * or a compound statement that contains only such a return statement.
 83  
      *
 84  
      * Returns <code>true</code> iff aAST represents
 85  
      * <br>
 86  
      * <pre>
 87  
      * return true/false;
 88  
      * <pre>
 89  
      * or
 90  
      * <br>
 91  
      * <pre>
 92  
      * {
 93  
      *   return true/false;
 94  
      * }
 95  
      * <pre>
 96  
      *
 97  
      * @param aAST the sytax tree to check
 98  
      * @return if aAST is a return statment with a boolean literal.
 99  
      */
 100  
     private static boolean returnsOnlyBooleanLiteral(AST aAST)
 101  
     {
 102  6
         if (isBooleanLiteralReturnStatement(aAST)) {
 103  2
             return true;
 104  
         }
 105  
 
 106  4
         final AST firstStmnt = aAST.getFirstChild();
 107  4
         return isBooleanLiteralReturnStatement(firstStmnt);
 108  
     }
 109  
 
 110  
     /**
 111  
      * Returns if an AST is a return statment with a boolean literal.
 112  
      *
 113  
      * Returns <code>true</code> iff aAST represents
 114  
      * <br>
 115  
      * <pre>
 116  
      * return true/false;
 117  
      * <pre>
 118  
      *
 119  
      * @param aAST the sytax tree to check
 120  
      * @return if aAST is a return statment with a boolean literal.
 121  
      */
 122  
     private static boolean isBooleanLiteralReturnStatement(AST aAST)
 123  
     {
 124  10
         if ((aAST == null) || (aAST.getType() != TokenTypes.LITERAL_RETURN)) {
 125  5
             return false;
 126  
         }
 127  
 
 128  5
         final AST expr = aAST.getFirstChild();
 129  
 
 130  5
         if ((expr == null) || (expr.getType() == TokenTypes.SEMI)) {
 131  1
             return false;
 132  
         }
 133  
 
 134  4
         final AST value = expr.getFirstChild();
 135  4
         return isBooleanLiteralType(value.getType());
 136  
     }
 137  
 
 138  
     /**
 139  
      * Checks if a token type is a literal true or false.
 140  
      * @param aTokenType the TokenType
 141  
      * @return true iff aTokenType is LITERAL_TRUE or LITERAL_FALSE
 142  
      */
 143  
     private static boolean isBooleanLiteralType(final int aTokenType)
 144  
     {
 145  4
         final boolean isTrue = (aTokenType == TokenTypes.LITERAL_TRUE);
 146  4
         final boolean isFalse = (aTokenType == TokenTypes.LITERAL_FALSE);
 147  4
         return isTrue || isFalse;
 148  
     }
 149  
 }