Coverage Report - com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
BooleanExpressionComplexityCheck
97%
34/35
63%
12/19
2
BooleanExpressionComplexityCheck$Context
100%
11/11
100%
4/4
2
 
 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.metrics;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.Check;
 22  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 23  
 import com.puppycrawl.tools.checkstyle.api.FastStack;
 24  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 25  
 import com.puppycrawl.tools.checkstyle.checks.CheckUtils;
 26  
 
 27  
 /**
 28  
  * Restricts nested boolean operators (&&, ||, &, | and ^) to
 29  
  * a specified depth (default = 3).
 30  
  *
 31  
  * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 32  
  * @author o_sukhodolsky
 33  
  */
 34  
 public final class BooleanExpressionComplexityCheck extends Check
 35  
 {
 36  
     /** Default allowed complexity. */
 37  
     private static final int DEFAULT_MAX = 3;
 38  
 
 39  
     /** Stack of contexts. */
 40  2
     private final FastStack<Context> mContextStack = FastStack.newInstance();
 41  
     /** Maximum allowed complexity. */
 42  
     private int mMax;
 43  
     /** Current context. */
 44  
     private Context mContext;
 45  
 
 46  
     /** Creates new instance of the check. */
 47  
     public BooleanExpressionComplexityCheck()
 48  2
     {
 49  2
         setMax(DEFAULT_MAX);
 50  2
     }
 51  
 
 52  
     @Override
 53  
     public int[] getDefaultTokens()
 54  
     {
 55  2
         return new int[] {
 56  
             TokenTypes.CTOR_DEF,
 57  
             TokenTypes.METHOD_DEF,
 58  
             TokenTypes.EXPR,
 59  
             TokenTypes.LAND,
 60  
             TokenTypes.BAND,
 61  
             TokenTypes.LOR,
 62  
             TokenTypes.BOR,
 63  
             TokenTypes.BXOR,
 64  
         };
 65  
     }
 66  
 
 67  
     @Override
 68  
     public int[] getRequiredTokens()
 69  
     {
 70  1
         return new int[] {
 71  
             TokenTypes.CTOR_DEF,
 72  
             TokenTypes.METHOD_DEF,
 73  
             TokenTypes.EXPR,
 74  
         };
 75  
     }
 76  
 
 77  
     /**
 78  
      * Getter for maximum allowed complexity.
 79  
      * @return value of maximum allowed complexity.
 80  
      */
 81  
     public int getMax()
 82  
     {
 83  22
         return mMax;
 84  
     }
 85  
 
 86  
     /**
 87  
      * Setter for maximum allowed complexity.
 88  
      * @param aMax new maximum allowed complexity.
 89  
      */
 90  
     public void setMax(int aMax)
 91  
     {
 92  3
         mMax = aMax;
 93  3
     }
 94  
 
 95  
     @Override
 96  
     public void visitToken(DetailAST aAST)
 97  
     {
 98  64
         switch (aAST.getType()) {
 99  
         case TokenTypes.CTOR_DEF:
 100  
         case TokenTypes.METHOD_DEF:
 101  6
             visitMethodDef(aAST);
 102  6
             break;
 103  
         case TokenTypes.EXPR:
 104  22
             visitExpr();
 105  22
             break;
 106  
         case TokenTypes.LAND:
 107  
         case TokenTypes.BAND:
 108  
         case TokenTypes.LOR:
 109  
         case TokenTypes.BOR:
 110  
         case TokenTypes.BXOR:
 111  36
             mContext.visitBooleanOperator();
 112  36
             break;
 113  
         default:
 114  0
             throw new IllegalStateException(aAST.toString());
 115  
         }
 116  64
     }
 117  
 
 118  
     @Override
 119  
     public void leaveToken(DetailAST aAST)
 120  
     {
 121  64
         switch (aAST.getType()) {
 122  
         case TokenTypes.CTOR_DEF:
 123  
         case TokenTypes.METHOD_DEF:
 124  6
             leaveMethodDef();
 125  6
             break;
 126  
         case TokenTypes.EXPR:
 127  22
             leaveExpr(aAST);
 128  22
             break;
 129  
         default:
 130  
             // Do nothing
 131  
         }
 132  64
     }
 133  
 
 134  
     /**
 135  
      * Creates new context for a given method.
 136  
      * @param aAST a method we start to check.
 137  
      */
 138  
     private void visitMethodDef(DetailAST aAST)
 139  
     {
 140  6
         mContextStack.push(mContext);
 141  6
         mContext = new Context(!CheckUtils.isEqualsMethod(aAST));
 142  6
     }
 143  
 
 144  
     /** Removes old context. */
 145  
     private void leaveMethodDef()
 146  
     {
 147  6
         mContext = mContextStack.pop();
 148  6
     }
 149  
 
 150  
     /** Creates and pushes new context. */
 151  
     private void visitExpr()
 152  
     {
 153  22
         mContextStack.push(mContext);
 154  22
         mContext = new Context((mContext == null) || mContext.isChecking());
 155  22
     }
 156  
 
 157  
     /**
 158  
      * Restores previous context.
 159  
      * @param aAST expression we leave.
 160  
      */
 161  
     private void leaveExpr(DetailAST aAST)
 162  
     {
 163  22
         mContext.checkCount(aAST);
 164  22
         mContext = mContextStack.pop();
 165  22
     }
 166  
 
 167  
     /**
 168  
      * Represents context (method/expression) in which we check complexity.
 169  
      *
 170  
      * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
 171  
      * @author o_sukhodolsky
 172  
      */
 173  
     private class Context
 174  
     {
 175  
         /**
 176  
          * Should we perform check in current context or not.
 177  
          * Usually false if we are inside equals() method.
 178  
          */
 179  
         private final boolean mChecking;
 180  
         /** Count of boolean operators. */
 181  
         private int mCount;
 182  
 
 183  
         /**
 184  
          * Creates new instance.
 185  
          * @param aChecking should we check in current context or not.
 186  
          */
 187  
         public Context(boolean aChecking)
 188  28
         {
 189  28
             mChecking = aChecking;
 190  28
             mCount = 0;
 191  28
         }
 192  
 
 193  
         /**
 194  
          * Getter for checking property.
 195  
          * @return should we check in current context or not.
 196  
          */
 197  
         public boolean isChecking()
 198  
         {
 199  14
             return mChecking;
 200  
         }
 201  
 
 202  
         /** Increases operator counter. */
 203  
         public void visitBooleanOperator()
 204  
         {
 205  36
             ++mCount;
 206  36
         }
 207  
 
 208  
         /**
 209  
          * Checks if we violates maximum allowed complexity.
 210  
          * @param aAST a node we check now.
 211  
          */
 212  
         public void checkCount(DetailAST aAST)
 213  
         {
 214  22
             if (mChecking && (mCount > getMax())) {
 215  2
                 final DetailAST parentAST = aAST.getParent();
 216  
 
 217  2
                 log(parentAST.getLineNo(), parentAST.getColumnNo(),
 218  
                     "booleanExpressionComplexity", mCount, getMax());
 219  
             }
 220  22
         }
 221  
     }
 222  
 }