1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks.sizes;
21
22 import java.util.ArrayDeque;
23 import java.util.Deque;
24 import java.util.EnumMap;
25 import java.util.Map;
26
27 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
28 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
29 import com.puppycrawl.tools.checkstyle.api.DetailAST;
30 import com.puppycrawl.tools.checkstyle.api.Scope;
31 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
32 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
33
34
35
36
37
38 @FileStatefulCheck
39 public final class MethodCountCheck extends AbstractCheck {
40
41
42
43
44
45 public static final String MSG_PRIVATE_METHODS = "too.many.privateMethods";
46
47
48
49
50
51 public static final String MSG_PACKAGE_METHODS = "too.many.packageMethods";
52
53
54
55
56
57 public static final String MSG_PROTECTED_METHODS = "too.many.protectedMethods";
58
59
60
61
62
63 public static final String MSG_PUBLIC_METHODS = "too.many.publicMethods";
64
65
66
67
68
69 public static final String MSG_MANY_METHODS = "too.many.methods";
70
71
72 private static final int DEFAULT_MAX_METHODS = 100;
73
74
75 private final Deque<MethodCounter> counters = new ArrayDeque<>();
76
77
78 private int maxPrivate = DEFAULT_MAX_METHODS;
79
80 private int maxPackage = DEFAULT_MAX_METHODS;
81
82 private int maxProtected = DEFAULT_MAX_METHODS;
83
84 private int maxPublic = DEFAULT_MAX_METHODS;
85
86 private int maxTotal = DEFAULT_MAX_METHODS;
87
88 @Override
89 public int[] getDefaultTokens() {
90 return getAcceptableTokens();
91 }
92
93 @Override
94 public int[] getAcceptableTokens() {
95 return new int[] {
96 TokenTypes.CLASS_DEF,
97 TokenTypes.ENUM_CONSTANT_DEF,
98 TokenTypes.ENUM_DEF,
99 TokenTypes.INTERFACE_DEF,
100 TokenTypes.ANNOTATION_DEF,
101 TokenTypes.METHOD_DEF,
102 };
103 }
104
105 @Override
106 public int[] getRequiredTokens() {
107 return new int[] {TokenTypes.METHOD_DEF};
108 }
109
110 @Override
111 public void visitToken(DetailAST ast) {
112 if (ast.getType() == TokenTypes.METHOD_DEF) {
113 if (isInLatestScopeDefinition(ast)) {
114 raiseCounter(ast);
115 }
116 }
117 else {
118 counters.push(new MethodCounter(ast));
119 }
120 }
121
122 @Override
123 public void leaveToken(DetailAST ast) {
124 if (ast.getType() != TokenTypes.METHOD_DEF) {
125 final MethodCounter counter = counters.pop();
126
127 checkCounters(counter, ast);
128 }
129 }
130
131
132
133
134
135
136
137
138
139 private boolean isInLatestScopeDefinition(DetailAST methodDef) {
140 boolean result = false;
141
142 if (!counters.isEmpty()) {
143 final DetailAST latestDefinition = counters.peek().getScopeDefinition();
144
145 result = latestDefinition == methodDef.getParent().getParent();
146 }
147
148 return result;
149 }
150
151
152
153
154
155
156 private void raiseCounter(DetailAST method) {
157 final MethodCounter actualCounter = counters.peek();
158 final DetailAST temp = method.findFirstToken(TokenTypes.MODIFIERS);
159 final Scope scope = ScopeUtil.getScopeFromMods(temp);
160 actualCounter.increment(scope);
161 }
162
163
164
165
166
167
168 private void checkCounters(MethodCounter counter, DetailAST ast) {
169 checkMax(maxPrivate, counter.value(Scope.PRIVATE),
170 MSG_PRIVATE_METHODS, ast);
171 checkMax(maxPackage, counter.value(Scope.PACKAGE),
172 MSG_PACKAGE_METHODS, ast);
173 checkMax(maxProtected, counter.value(Scope.PROTECTED),
174 MSG_PROTECTED_METHODS, ast);
175 checkMax(maxPublic, counter.value(Scope.PUBLIC),
176 MSG_PUBLIC_METHODS, ast);
177 checkMax(maxTotal, counter.getTotal(), MSG_MANY_METHODS, ast);
178 }
179
180
181
182
183
184
185
186
187 private void checkMax(int max, int value, String msg, DetailAST ast) {
188 if (max < value) {
189 log(ast.getLineNo(), msg, value, max);
190 }
191 }
192
193
194
195
196
197 public void setMaxPrivate(int value) {
198 maxPrivate = value;
199 }
200
201
202
203
204
205 public void setMaxPackage(int value) {
206 maxPackage = value;
207 }
208
209
210
211
212
213 public void setMaxProtected(int value) {
214 maxProtected = value;
215 }
216
217
218
219
220
221 public void setMaxPublic(int value) {
222 maxPublic = value;
223 }
224
225
226
227
228
229 public void setMaxTotal(int value) {
230 maxTotal = value;
231 }
232
233
234
235
236
237
238 private static class MethodCounter {
239
240
241 private final Map<Scope, Integer> counts = new EnumMap<>(Scope.class);
242
243 private final boolean inInterface;
244
245
246
247
248 private final DetailAST scopeDefinition;
249
250 private int total;
251
252
253
254
255
256
257
258 MethodCounter(DetailAST scopeDefinition) {
259 this.scopeDefinition = scopeDefinition;
260 inInterface = scopeDefinition.getType() == TokenTypes.INTERFACE_DEF;
261 }
262
263
264
265
266
267 private void increment(Scope scope) {
268 total++;
269 if (inInterface) {
270 counts.put(Scope.PUBLIC, 1 + value(Scope.PUBLIC));
271 }
272 else {
273 counts.put(scope, 1 + value(scope));
274 }
275 }
276
277
278
279
280
281
282 private int value(Scope scope) {
283 Integer value = counts.get(scope);
284 if (value == null) {
285 value = 0;
286 }
287 return value;
288 }
289
290 private DetailAST getScopeDefinition() {
291 return scopeDefinition;
292 }
293
294
295
296
297
298 private int getTotal() {
299 return total;
300 }
301
302 }
303
304 }