Coverage Report - com.puppycrawl.tools.checkstyle.checks.sizes.MethodCountCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
MethodCountCheck
100%
41/41
95%
21/22
1.8
MethodCountCheck$MethodCounter
100%
12/12
100%
4/4
1.8
 
 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.sizes;
 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.Scope;
 25  
 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
 26  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 27  
 import java.util.EnumMap;
 28  
 
 29  
 /**
 30  
  * Counts the methods of the type-definition and checks whether this
 31  
  * count is higher than the configured limit.
 32  
  * @author Alexander Jesse
 33  
  * @author Oliver Burn
 34  
  */
 35  3
 public final class MethodCountCheck extends Check
 36  
 {
 37  
     /**
 38  
      * Marker class used to collect data about the number of methods per
 39  
      * class. Objects of this class are used on the Stack to count the
 40  
      * methods for each class and layer.
 41  
      */
 42  
     private static class MethodCounter
 43  
     {
 44  
         /** Maintains the counts. */
 45  9
         private final EnumMap<Scope, Integer> mCounts =
 46  
             new EnumMap<Scope, Integer>(Scope.class);
 47  
         /** indicated is an interface, in which case all methods are public */
 48  
         private final boolean mInInterface;
 49  
         /** tracks the total. */
 50  
         private int mTotal;
 51  
 
 52  
         /**
 53  
          * Creates an interface.
 54  
          * @param aInInterface indicated if counter for an interface. In which
 55  
          *        case, add all counts as public methods.
 56  
          */
 57  
         MethodCounter(boolean aInInterface)
 58  9
         {
 59  9
             mInInterface = aInInterface;
 60  9
         }
 61  
 
 62  
         /**
 63  
          * Increments to counter by one for the supplied scope.
 64  
          * @param aScope the scope counter to increment.
 65  
          */
 66  
         void increment(Scope aScope)
 67  
         {
 68  66
             mTotal++;
 69  66
             if (mInInterface) {
 70  10
                 mCounts.put(Scope.PUBLIC, 1 + value(Scope.PUBLIC));
 71  
             }
 72  
             else {
 73  56
                 mCounts.put(aScope, 1 + value(aScope));
 74  
             }
 75  66
         }
 76  
 
 77  
         /**
 78  
          * @return the value of a scope counter
 79  
          * @param aScope the scope counter to get the value of
 80  
          */
 81  
         int value(Scope aScope)
 82  
         {
 83  102
             final Integer value = mCounts.get(aScope);
 84  102
             return (null == value) ? 0 : value;
 85  
         }
 86  
 
 87  
         /** @return the total number of methods. */
 88  
         int getTotal()
 89  
         {
 90  9
             return mTotal;
 91  
         }
 92  
     };
 93  
 
 94  
     /** default maximum number of methods */
 95  
     private static final int DEFAULT_MAX_METHODS = 100;
 96  
     /** Maximum private methods. */
 97  3
     private int mMaxPrivate = DEFAULT_MAX_METHODS;
 98  
     /** Maximum package methods. */
 99  3
     private int mMaxPackage = DEFAULT_MAX_METHODS;
 100  
     /** Maximum protected methods. */
 101  3
     private int mMaxProtected = DEFAULT_MAX_METHODS;
 102  
     /** Maximum public methods. */
 103  3
     private int mMaxPublic = DEFAULT_MAX_METHODS;
 104  
     /** Maximum total number of methods. */
 105  3
     private int mMaxTotal = DEFAULT_MAX_METHODS;
 106  
     /** Maintains stack of counters, to support inner types. */
 107  3
     private final FastStack<MethodCounter> mCounters =
 108  
         new FastStack<MethodCounter>();
 109  
 
 110  
     @Override
 111  
     public int[] getDefaultTokens()
 112  
     {
 113  3
         return new int[] {
 114  
             TokenTypes.CLASS_DEF,
 115  
             TokenTypes.ENUM_CONSTANT_DEF,
 116  
             TokenTypes.ENUM_DEF,
 117  
             TokenTypes.INTERFACE_DEF,
 118  
             TokenTypes.METHOD_DEF,
 119  
         };
 120  
     }
 121  
 
 122  
     @Override
 123  
     public void visitToken(DetailAST aAST)
 124  
     {
 125  75
         if ((TokenTypes.CLASS_DEF == aAST.getType())
 126  
             || (TokenTypes.INTERFACE_DEF == aAST.getType())
 127  
             || (TokenTypes.ENUM_CONSTANT_DEF == aAST.getType())
 128  
             || (TokenTypes.ENUM_DEF == aAST.getType()))
 129  
         {
 130  9
             mCounters.push(new MethodCounter(
 131  
                 TokenTypes.INTERFACE_DEF == aAST.getType()));
 132  
         }
 133  66
         else if (TokenTypes.METHOD_DEF == aAST.getType()) {
 134  66
             raiseCounter(aAST);
 135  
         }
 136  75
     }
 137  
 
 138  
     @Override
 139  
     public void leaveToken(DetailAST aAST)
 140  
     {
 141  75
         if ((TokenTypes.CLASS_DEF == aAST.getType())
 142  
             || (TokenTypes.INTERFACE_DEF == aAST.getType())
 143  
             || (TokenTypes.ENUM_CONSTANT_DEF == aAST.getType())
 144  
             || (TokenTypes.ENUM_DEF == aAST.getType()))
 145  
         {
 146  9
             final MethodCounter counter = mCounters.pop();
 147  9
             checkCounters(counter, aAST);
 148  
         }
 149  75
     }
 150  
 
 151  
     /**
 152  
      * Determine the visibility modifier and raise the corresponding counter.
 153  
      * @param aMethod
 154  
      *            The method-subtree from the AbstractSyntaxTree.
 155  
      */
 156  
     private void raiseCounter(DetailAST aMethod)
 157  
     {
 158  66
         final MethodCounter actualCounter = mCounters.peek();
 159  66
         final DetailAST temp = aMethod.findFirstToken(TokenTypes.MODIFIERS);
 160  66
         final Scope scope = ScopeUtils.getScopeFromMods(temp);
 161  66
         actualCounter.increment(scope);
 162  66
     }
 163  
 
 164  
     /**
 165  
      * Check the counters and report violations.
 166  
      * @param aCounter the method counters to check
 167  
      * @param aAst to report errors against.
 168  
      */
 169  
     private void checkCounters(MethodCounter aCounter, DetailAST aAst)
 170  
     {
 171  9
         checkMax(mMaxPrivate, aCounter.value(Scope.PRIVATE),
 172  
                  "too.many.privateMethods", aAst);
 173  9
         checkMax(mMaxPackage, aCounter.value(Scope.PACKAGE),
 174  
                  "too.many.packageMethods", aAst);
 175  9
         checkMax(mMaxProtected, aCounter.value(Scope.PROTECTED),
 176  
                  "too.many.protectedMethods", aAst);
 177  9
         checkMax(mMaxPublic, aCounter.value(Scope.PUBLIC),
 178  
                  "too.many.publicMethods", aAst);
 179  9
         checkMax(mMaxTotal, aCounter.getTotal(), "too.many.methods", aAst);
 180  9
     }
 181  
 
 182  
     /**
 183  
      * Utility for reporting if a maximum has been exceeded.
 184  
      * @param aMax the maximum allowed value
 185  
      * @param aValue the actual value
 186  
      * @param aMsg the message to log. Takes two arguments of value and maximum.
 187  
      * @param aAst the AST to associate with the message.
 188  
      */
 189  
     private void checkMax(int aMax, int aValue, String aMsg, DetailAST aAst)
 190  
     {
 191  45
         if (aMax < aValue) {
 192  11
             log(aAst.getLineNo(), aMsg, aValue, aMax);
 193  
         }
 194  45
     }
 195  
 
 196  
     /**
 197  
      * Sets the maximum allowed <code>private</code> methods per type.
 198  
      * @param aValue the maximum allowed.
 199  
      */
 200  
     public void setMaxPrivate(int aValue)
 201  
     {
 202  2
         mMaxPrivate = aValue;
 203  2
     }
 204  
 
 205  
     /**
 206  
      * Sets the maximum allowed <code>package</code> methods per type.
 207  
      * @param aValue the maximum allowed.
 208  
      */
 209  
     public void setMaxPackage(int aValue)
 210  
     {
 211  1
         mMaxPackage = aValue;
 212  1
     }
 213  
 
 214  
     /**
 215  
      * Sets the maximum allowed <code>protected</code> methods per type.
 216  
      * @param aValue the maximum allowed.
 217  
      */
 218  
     public void setMaxProtected(int aValue)
 219  
     {
 220  1
         mMaxProtected = aValue;
 221  1
     }
 222  
 
 223  
     /**
 224  
      * Sets the maximum allowed <code>public</code> methods per type.
 225  
      * @param aValue the maximum allowed.
 226  
      */
 227  
     public void setMaxPublic(int aValue)
 228  
     {
 229  1
         mMaxPublic = aValue;
 230  1
     }
 231  
 
 232  
     /**
 233  
      * Sets the maximum total methods per type.
 234  
      * @param aValue the maximum allowed.
 235  
      */
 236  
     public void setMaxTotal(int aValue)
 237  
     {
 238  2
         mMaxTotal = aValue;
 239  2
     }
 240  
 }