Coverage Report - com.puppycrawl.tools.checkstyle.checks.sizes.ExecutableStatementCountCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
ExecutableStatementCountCheck
100%
44/44
100%
20/20
2.267
ExecutableStatementCountCheck$Context
100%
8/8
N/A
2.267
 
 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.sizes;
 21  
 
 22  
 import java.util.ArrayDeque;
 23  
 import java.util.Deque;
 24  
 
 25  
 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
 26  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 27  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 28  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 29  
 
 30  
 /**
 31  
  * Restricts the number of executable statements to a specified limit
 32  
  * (default = 30).
 33  
  * @author Simon Harris
 34  
  */
 35  
 @FileStatefulCheck
 36  
 public final class ExecutableStatementCountCheck
 37  
     extends AbstractCheck {
 38  
 
 39  
     /**
 40  
      * A key is pointing to the warning message text in "messages.properties"
 41  
      * file.
 42  
      */
 43  
     public static final String MSG_KEY = "executableStatementCount";
 44  
 
 45  
     /** Default threshold. */
 46  
     private static final int DEFAULT_MAX = 30;
 47  
 
 48  
     /** Stack of method contexts. */
 49  18
     private final Deque<Context> contextStack = new ArrayDeque<>();
 50  
 
 51  
     /** Threshold to report error for. */
 52  
     private int max;
 53  
 
 54  
     /** Current method context. */
 55  
     private Context context;
 56  
 
 57  
     /** Constructs a {@code ExecutableStatementCountCheck}. */
 58  18
     public ExecutableStatementCountCheck() {
 59  18
         max = DEFAULT_MAX;
 60  18
     }
 61  
 
 62  
     @Override
 63  
     public int[] getDefaultTokens() {
 64  20
         return new int[] {
 65  
             TokenTypes.CTOR_DEF,
 66  
             TokenTypes.METHOD_DEF,
 67  
             TokenTypes.INSTANCE_INIT,
 68  
             TokenTypes.STATIC_INIT,
 69  
             TokenTypes.SLIST,
 70  
         };
 71  
     }
 72  
 
 73  
     @Override
 74  
     public int[] getRequiredTokens() {
 75  31
         return new int[] {TokenTypes.SLIST};
 76  
     }
 77  
 
 78  
     @Override
 79  
     public int[] getAcceptableTokens() {
 80  10
         return new int[] {
 81  
             TokenTypes.CTOR_DEF,
 82  
             TokenTypes.METHOD_DEF,
 83  
             TokenTypes.INSTANCE_INIT,
 84  
             TokenTypes.STATIC_INIT,
 85  
             TokenTypes.SLIST,
 86  
         };
 87  
     }
 88  
 
 89  
     /**
 90  
      * Sets the maximum threshold.
 91  
      * @param max the maximum threshold.
 92  
      */
 93  
     public void setMax(int max) {
 94  6
         this.max = max;
 95  6
     }
 96  
 
 97  
     @Override
 98  
     public void beginTree(DetailAST rootAST) {
 99  9
         context = new Context(null);
 100  9
         contextStack.clear();
 101  9
     }
 102  
 
 103  
     @Override
 104  
     public void visitToken(DetailAST ast) {
 105  245
         switch (ast.getType()) {
 106  
             case TokenTypes.CTOR_DEF:
 107  
             case TokenTypes.METHOD_DEF:
 108  
             case TokenTypes.INSTANCE_INIT:
 109  
             case TokenTypes.STATIC_INIT:
 110  34
                 visitMemberDef(ast);
 111  34
                 break;
 112  
             case TokenTypes.SLIST:
 113  210
                 visitSlist(ast);
 114  210
                 break;
 115  
             default:
 116  1
                 throw new IllegalStateException(ast.toString());
 117  
         }
 118  244
     }
 119  
 
 120  
     @Override
 121  
     public void leaveToken(DetailAST ast) {
 122  244
         switch (ast.getType()) {
 123  
             case TokenTypes.CTOR_DEF:
 124  
             case TokenTypes.METHOD_DEF:
 125  
             case TokenTypes.INSTANCE_INIT:
 126  
             case TokenTypes.STATIC_INIT:
 127  33
                 leaveMemberDef(ast);
 128  33
                 break;
 129  
             case TokenTypes.SLIST:
 130  
                 // Do nothing
 131  210
                 break;
 132  
             default:
 133  1
                 throw new IllegalStateException(ast.toString());
 134  
         }
 135  243
     }
 136  
 
 137  
     /**
 138  
      * Process the start of the member definition.
 139  
      * @param ast the token representing the member definition.
 140  
      */
 141  
     private void visitMemberDef(DetailAST ast) {
 142  34
         contextStack.push(context);
 143  34
         context = new Context(ast);
 144  34
     }
 145  
 
 146  
     /**
 147  
      * Process the end of a member definition.
 148  
      *
 149  
      * @param ast the token representing the member definition.
 150  
      */
 151  
     private void leaveMemberDef(DetailAST ast) {
 152  33
         final int count = context.getCount();
 153  33
         if (count > max) {
 154  40
             log(ast.getLineNo(), ast.getColumnNo(),
 155  20
                     MSG_KEY, count, max);
 156  
         }
 157  33
         context = contextStack.pop();
 158  33
     }
 159  
 
 160  
     /**
 161  
      * Process the end of a statement list.
 162  
      *
 163  
      * @param ast the token representing the statement list.
 164  
      */
 165  
     private void visitSlist(DetailAST ast) {
 166  210
         if (context.getAST() != null) {
 167  
             // find member AST for the statement list
 168  107
             final DetailAST contextAST = context.getAST();
 169  107
             DetailAST parent = ast.getParent();
 170  107
             int type = parent.getType();
 171  376
             while (type != TokenTypes.CTOR_DEF
 172  
                 && type != TokenTypes.METHOD_DEF
 173  
                 && type != TokenTypes.INSTANCE_INIT
 174  
                 && type != TokenTypes.STATIC_INIT) {
 175  
 
 176  269
                 parent = parent.getParent();
 177  269
                 type = parent.getType();
 178  
             }
 179  107
             if (parent == contextAST) {
 180  105
                 context.addCount(ast.getChildCount() / 2);
 181  
             }
 182  
         }
 183  210
     }
 184  
 
 185  
     /**
 186  
      * Class to encapsulate counting information about one member.
 187  
      * @author Simon Harris
 188  
      */
 189  
     private static class Context {
 190  
         /** Member AST node. */
 191  
         private final DetailAST ast;
 192  
 
 193  
         /** Counter for context elements. */
 194  
         private int count;
 195  
 
 196  
         /**
 197  
          * Creates new member context.
 198  
          * @param ast member AST node.
 199  
          */
 200  43
         Context(DetailAST ast) {
 201  43
             this.ast = ast;
 202  43
             count = 0;
 203  43
         }
 204  
 
 205  
         /**
 206  
          * Increase count.
 207  
          * @param addition the count increment.
 208  
          */
 209  
         public void addCount(int addition) {
 210  105
             count += addition;
 211  105
         }
 212  
 
 213  
         /**
 214  
          * Gets the member AST node.
 215  
          * @return the member AST node.
 216  
          */
 217  
         public DetailAST getAST() {
 218  317
             return ast;
 219  
         }
 220  
 
 221  
         /**
 222  
          * Gets the count.
 223  
          * @return the count.
 224  
          */
 225  
         public int getCount() {
 226  33
             return count;
 227  
         }
 228  
     }
 229  
 }