001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.checks.metrics; 020 021import com.puppycrawl.tools.checkstyle.api.Check; 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.FastStack; 024import com.puppycrawl.tools.checkstyle.api.TokenTypes; 025import java.math.BigInteger; 026 027/** 028 * Base class for checks the calculate complexity based around methods. 029 * 030 * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a> 031 * @author Oliver Burn 032 */ 033public abstract class AbstractComplexityCheck 034 extends Check 035{ 036 /** the initial current value */ 037 private static final BigInteger INITIAL_VALUE = BigInteger.ONE; 038 039 /** stack of values - all but the current value */ 040 private final FastStack<BigInteger> valueStack = FastStack.newInstance(); 041 042 /** the current value */ 043 private BigInteger currentValue = BigInteger.ZERO; 044 045 /** threshold to report error for */ 046 private int max; 047 048 /** 049 * Creates an instance. 050 * @param max the threshold of when to report an error 051 */ 052 public AbstractComplexityCheck(int max) 053 { 054 this.max = max; 055 } 056 057 /** 058 * @return the message ID to log violations with 059 */ 060 protected abstract String getMessageID(); 061 062 /** 063 * Hook called when visiting a token. Will not be called the method 064 * definition tokens. 065 * 066 * @param ast the token being visited 067 */ 068 protected void visitTokenHook(DetailAST ast) 069 { 070 } 071 072 /** 073 * Hook called when leaving a token. Will not be called the method 074 * definition tokens. 075 * 076 * @param ast the token being left 077 */ 078 protected void leaveTokenHook(DetailAST ast) 079 { 080 } 081 082 @Override 083 public final int[] getRequiredTokens() 084 { 085 return new int[] { 086 TokenTypes.CTOR_DEF, 087 TokenTypes.METHOD_DEF, 088 TokenTypes.INSTANCE_INIT, 089 TokenTypes.STATIC_INIT, 090 }; 091 } 092 093 /** @return the maximum threshold allowed */ 094 public final int getMax() 095 { 096 return max; 097 } 098 099 /** 100 * Set the maximum threshold allowed. 101 * 102 * @param max the maximum threshold 103 */ 104 public final void setMax(int max) 105 { 106 this.max = max; 107 } 108 109 @Override 110 public void visitToken(DetailAST ast) 111 { 112 switch (ast.getType()) { 113 case TokenTypes.CTOR_DEF: 114 case TokenTypes.METHOD_DEF: 115 case TokenTypes.INSTANCE_INIT: 116 case TokenTypes.STATIC_INIT: 117 visitMethodDef(); 118 break; 119 default: 120 visitTokenHook(ast); 121 } 122 } 123 124 @Override 125 public void leaveToken(DetailAST ast) 126 { 127 switch (ast.getType()) { 128 case TokenTypes.CTOR_DEF: 129 case TokenTypes.METHOD_DEF: 130 case TokenTypes.INSTANCE_INIT: 131 case TokenTypes.STATIC_INIT: 132 leaveMethodDef(ast); 133 break; 134 default: 135 leaveTokenHook(ast); 136 } 137 } 138 139 /** 140 * @return the current value 141 */ 142 protected final BigInteger getCurrentValue() 143 { 144 return currentValue; 145 } 146 147 /** 148 * Set the current value 149 * @param value the new value 150 */ 151 protected final void setCurrentValue(BigInteger value) 152 { 153 currentValue = value; 154 } 155 156 /** 157 * Increments the current value by a specified amount. 158 * 159 * @param by the amount to increment by 160 */ 161 protected final void incrementCurrentValue(BigInteger by) 162 { 163 setCurrentValue(getCurrentValue().add(by)); 164 } 165 166 /** Push the current value on the stack */ 167 protected final void pushValue() 168 { 169 valueStack.push(currentValue); 170 currentValue = INITIAL_VALUE; 171 } 172 173 /** 174 * @return pop a value off the stack and make it the current value 175 */ 176 protected final BigInteger popValue() 177 { 178 currentValue = valueStack.pop(); 179 return currentValue; 180 } 181 182 /** Process the start of the method definition */ 183 private void visitMethodDef() 184 { 185 pushValue(); 186 } 187 188 /** 189 * Process the end of a method definition. 190 * 191 * @param ast the token representing the method definition 192 */ 193 private void leaveMethodDef(DetailAST ast) 194 { 195 final BigInteger bigIntegerMax = BigInteger.valueOf(max); 196 if (currentValue.compareTo(bigIntegerMax) > 0) { 197 log(ast, getMessageID(), currentValue, bigIntegerMax); 198 } 199 popValue(); 200 } 201}