Coverage Report - com.puppycrawl.tools.checkstyle.checks.coding.ReturnCountCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
ReturnCountCheck
90%
29/32
60%
6/10
1.769
ReturnCountCheck$Context
100%
9/9
100%
4/4
1.769
 
 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  
 package com.puppycrawl.tools.checkstyle.checks.coding;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 22  
 import com.puppycrawl.tools.checkstyle.api.FastStack;
 23  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 24  
 import com.puppycrawl.tools.checkstyle.checks.AbstractFormatCheck;
 25  
 
 26  
 /**
 27  
  * <p>
 28  
  * Restricts return statements to a specified count (default = 2).
 29  
  * Ignores specified methods (<code>equals()</code> by default).
 30  
  * </p>
 31  
  * <p>
 32  
  * Rationale: Too many return points can be indication that code is
 33  
  * attempting to do too much or may be difficult to understand.
 34  
  * </p>
 35  
  *
 36  
  * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 37  
  * TODO: Test for inside a static block
 38  
  */
 39  
 public final class ReturnCountCheck extends AbstractFormatCheck
 40  
 {
 41  
     /** Default allowed number of return statements. */
 42  
     private static final int DEFAULT_MAX = 2;
 43  
 
 44  
     /** Stack of method contexts. */
 45  2
     private final FastStack<Context> mContextStack = FastStack.newInstance();
 46  
     /** Maximum allowed number of return stmts. */
 47  
     private int mMax;
 48  
     /** Current method context. */
 49  
     private Context mContext;
 50  
 
 51  
     /** Creates new instance of the checks. */
 52  
     public ReturnCountCheck()
 53  
     {
 54  2
         super("^equals$");
 55  2
         setMax(DEFAULT_MAX);
 56  2
     }
 57  
 
 58  
     @Override
 59  
     public int[] getDefaultTokens()
 60  
     {
 61  2
         return new int[] {
 62  
             TokenTypes.CTOR_DEF,
 63  
             TokenTypes.METHOD_DEF,
 64  
             TokenTypes.LITERAL_RETURN,
 65  
         };
 66  
     }
 67  
 
 68  
     @Override
 69  
     public int[] getRequiredTokens()
 70  
     {
 71  0
         return new int[]{
 72  
             TokenTypes.CTOR_DEF,
 73  
             TokenTypes.METHOD_DEF,
 74  
         };
 75  
     }
 76  
 
 77  
     /**
 78  
      * Getter for max property.
 79  
      * @return maximum allowed number of return statements.
 80  
      */
 81  
     public int getMax()
 82  
     {
 83  14
         return mMax;
 84  
     }
 85  
 
 86  
     /**
 87  
      * Setter for max property.
 88  
      * @param aMax maximum allowed number of return statements.
 89  
      */
 90  
     public void setMax(int aMax)
 91  
     {
 92  2
         mMax = aMax;
 93  2
     }
 94  
 
 95  
     @Override
 96  
     public void beginTree(DetailAST aRootAST)
 97  
     {
 98  2
         mContext = null;
 99  2
         mContextStack.clear();
 100  2
     }
 101  
 
 102  
     @Override
 103  
     public void visitToken(DetailAST aAST)
 104  
     {
 105  54
         switch (aAST.getType()) {
 106  
         case TokenTypes.CTOR_DEF:
 107  
         case TokenTypes.METHOD_DEF:
 108  10
             visitMethodDef(aAST);
 109  10
             break;
 110  
         case TokenTypes.LITERAL_RETURN:
 111  44
             mContext.visitLiteralReturn();
 112  44
             break;
 113  
         default:
 114  0
             throw new IllegalStateException(aAST.toString());
 115  
         }
 116  54
     }
 117  
 
 118  
     @Override
 119  
     public void leaveToken(DetailAST aAST)
 120  
     {
 121  54
         switch (aAST.getType()) {
 122  
         case TokenTypes.CTOR_DEF:
 123  
         case TokenTypes.METHOD_DEF:
 124  10
             leaveMethodDef(aAST);
 125  10
             break;
 126  
         case TokenTypes.LITERAL_RETURN:
 127  
             // Do nothing
 128  44
             break;
 129  
         default:
 130  0
             throw new IllegalStateException(aAST.toString());
 131  
         }
 132  54
     }
 133  
 
 134  
     /**
 135  
      * Creates new method context and places old one on the stack.
 136  
      * @param aAST method definition for check.
 137  
      */
 138  
     private void visitMethodDef(DetailAST aAST)
 139  
     {
 140  10
         mContextStack.push(mContext);
 141  10
         final DetailAST methodNameAST = aAST.findFirstToken(TokenTypes.IDENT);
 142  10
         mContext =
 143  
             new Context(!getRegexp().matcher(methodNameAST.getText()).find());
 144  10
     }
 145  
 
 146  
     /**
 147  
      * Checks number of return statements and restore
 148  
      * previous method context.
 149  
      * @param aAST method def node.
 150  
      */
 151  
     private void leaveMethodDef(DetailAST aAST)
 152  
     {
 153  10
         mContext.checkCount(aAST);
 154  10
         mContext = mContextStack.pop();
 155  10
     }
 156  
 
 157  
     /**
 158  
      * Class to encapsulate information about one method.
 159  
      * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 160  
      */
 161  
     private class Context
 162  
     {
 163  
         /** Whether we should check this method or not. */
 164  
         private final boolean mChecking;
 165  
         /** Counter for return statements. */
 166  
         private int mCount;
 167  
 
 168  
         /**
 169  
          * Creates new method context.
 170  
          * @param aChecking should we check this method or not.
 171  
          */
 172  
         public Context(boolean aChecking)
 173  10
         {
 174  10
             mChecking = aChecking;
 175  10
             mCount = 0;
 176  10
         }
 177  
 
 178  
         /** Increase number of return statements. */
 179  
         public void visitLiteralReturn()
 180  
         {
 181  44
             ++mCount;
 182  44
         }
 183  
 
 184  
         /**
 185  
          * Checks if number of return statements in method more
 186  
          * than allowed.
 187  
          * @param aAST method def associated with this context.
 188  
          */
 189  
         public void checkCount(DetailAST aAST)
 190  
         {
 191  10
             if (mChecking && (mCount > getMax())) {
 192  5
                 log(aAST.getLineNo(), aAST.getColumnNo(), "return.count",
 193  
                     mCount, getMax());
 194  
             }
 195  10
         }
 196  
     }
 197  
 }