Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.SimplifyBooleanReturnCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
SimplifyBooleanReturnCheck
100%
29/29
100%
22/22
2.143
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 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.StatelessCheck;
 24  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 25  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 26  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 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  
 @StatelessCheck
 42  9
 public class SimplifyBooleanReturnCheck
 43  
     extends AbstractCheck {
 44  
 
 45  
     /**
 46  
      * A key is pointing to the warning message text in "messages.properties"
 47  
      * file.
 48  
      */
 49  
     public static final String MSG_KEY = "simplify.boolReturn";
 50  
 
 51  
     @Override
 52  
     public int[] getAcceptableTokens() {
 53  5
         return getRequiredTokens();
 54  
     }
 55  
 
 56  
     @Override
 57  
     public int[] getDefaultTokens() {
 58  11
         return getRequiredTokens();
 59  
     }
 60  
 
 61  
     @Override
 62  
     public int[] getRequiredTokens() {
 63  27
         return new int[] {TokenTypes.LITERAL_IF};
 64  
     }
 65  
 
 66  
     @Override
 67  
     public void visitToken(DetailAST ast) {
 68  
         // LITERAL_IF has the following four or five children:
 69  
         // '('
 70  
         // condition
 71  
         // ')'
 72  
         // thenStatement
 73  
         // [ LITERAL_ELSE (with the elseStatement as a child) ]
 74  
 
 75  
         // don't bother if this is not if then else
 76  7
         final AST elseLiteral =
 77  7
             ast.findFirstToken(TokenTypes.LITERAL_ELSE);
 78  7
         if (elseLiteral != null) {
 79  6
             final AST elseStatement = elseLiteral.getFirstChild();
 80  
 
 81  
             // skip '(' and ')'
 82  6
             final AST condition = ast.getFirstChild().getNextSibling();
 83  6
             final AST thenStatement = condition.getNextSibling().getNextSibling();
 84  
 
 85  6
             if (canReturnOnlyBooleanLiteral(thenStatement)
 86  3
                 && canReturnOnlyBooleanLiteral(elseStatement)) {
 87  2
                 log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY);
 88  
             }
 89  
         }
 90  7
     }
 91  
 
 92  
     /**
 93  
      * Returns if an AST is a return statement with a boolean literal
 94  
      * or a compound statement that contains only such a return statement.
 95  
      *
 96  
      * <p>Returns {@code true} iff ast represents
 97  
      * <br/>
 98  
      * <pre>
 99  
      * return true/false;
 100  
      * </pre>
 101  
      * or
 102  
      * <br/>
 103  
      * <pre>
 104  
      * {
 105  
      *   return true/false;
 106  
      * }
 107  
      * </pre>
 108  
      *
 109  
      * @param ast the syntax tree to check
 110  
      * @return if ast is a return statement with a boolean literal.
 111  
      */
 112  
     private static boolean canReturnOnlyBooleanLiteral(AST ast) {
 113  9
         boolean result = true;
 114  9
         if (!isBooleanLiteralReturnStatement(ast)) {
 115  7
             final AST firstStatement = ast.getFirstChild();
 116  7
             result = isBooleanLiteralReturnStatement(firstStatement);
 117  
         }
 118  9
         return result;
 119  
     }
 120  
 
 121  
     /**
 122  
      * Returns if an AST is a return statement with a boolean literal.
 123  
      *
 124  
      * <p>Returns {@code true} iff ast represents
 125  
      * <br/>
 126  
      * <pre>
 127  
      * return true/false;
 128  
      * </pre>
 129  
      *
 130  
      * @param ast the syntax tree to check
 131  
      * @return if ast is a return statement with a boolean literal.
 132  
      */
 133  
     private static boolean isBooleanLiteralReturnStatement(AST ast) {
 134  16
         boolean booleanReturnStatement = false;
 135  
 
 136  16
         if (ast != null && ast.getType() == TokenTypes.LITERAL_RETURN) {
 137  7
             final AST expr = ast.getFirstChild();
 138  
 
 139  7
             if (expr.getType() != TokenTypes.SEMI) {
 140  6
                 final AST value = expr.getFirstChild();
 141  6
                 booleanReturnStatement = isBooleanLiteralType(value.getType());
 142  
             }
 143  
         }
 144  16
         return booleanReturnStatement;
 145  
     }
 146  
 
 147  
     /**
 148  
      * Checks if a token type is a literal true or false.
 149  
      * @param tokenType the TokenType
 150  
      * @return true iff tokenType is LITERAL_TRUE or LITERAL_FALSE
 151  
      */
 152  
     private static boolean isBooleanLiteralType(final int tokenType) {
 153  6
         final boolean isTrue = tokenType == TokenTypes.LITERAL_TRUE;
 154  6
         final boolean isFalse = tokenType == TokenTypes.LITERAL_FALSE;
 155  6
         return isTrue || isFalse;
 156  
     }
 157  
 }