1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2015 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 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 java.math.BigInteger;
26
27 /**
28 * Base class for checks the calculate complexity based around methods.
29 *
30 * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
31 * @author Oliver Burn
32 */
33 public abstract class AbstractComplexityCheck
34 extends Check
35 {
36 /** the initial current value */
37 private static final BigInteger INITIAL_VALUE = BigInteger.ONE;
38
39 /** stack of values - all but the current value */
40 private final FastStack<BigInteger> valueStack = FastStack.newInstance();
41
42 /** the current value */
43 private BigInteger currentValue = BigInteger.ZERO;
44
45 /** threshold to report error for */
46 private int max;
47
48 /**
49 * Creates an instance.
50 * @param max the threshold of when to report an error
51 */
52 public AbstractComplexityCheck(int max)
53 {
54 this.max = max;
55 }
56
57 /**
58 * @return the message ID to log violations with
59 */
60 protected abstract String getMessageID();
61
62 /**
63 * Hook called when visiting a token. Will not be called the method
64 * definition tokens.
65 *
66 * @param ast the token being visited
67 */
68 protected void visitTokenHook(DetailAST ast)
69 {
70 }
71
72 /**
73 * Hook called when leaving a token. Will not be called the method
74 * definition tokens.
75 *
76 * @param ast the token being left
77 */
78 protected void leaveTokenHook(DetailAST ast)
79 {
80 }
81
82 @Override
83 public final int[] getRequiredTokens()
84 {
85 return new int[] {
86 TokenTypes.CTOR_DEF,
87 TokenTypes.METHOD_DEF,
88 TokenTypes.INSTANCE_INIT,
89 TokenTypes.STATIC_INIT,
90 };
91 }
92
93 /** @return the maximum threshold allowed */
94 public final int getMax()
95 {
96 return max;
97 }
98
99 /**
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 }