1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
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 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
|
36 | |
|
37 | |
|
38 | 1 | public class JavaNCSSCheck extends Check |
39 | |
{ |
40 | |
|
41 | |
private static final int FILE_MAX_NCSS = 2000; |
42 | |
|
43 | |
|
44 | |
private static final int CLASS_MAX_NCSS = 1500; |
45 | |
|
46 | |
|
47 | |
private static final int METHOD_MAX_NCSS = 50; |
48 | |
|
49 | |
|
50 | 1 | private int mFileMax = FILE_MAX_NCSS; |
51 | |
|
52 | |
|
53 | 1 | private int mClassMax = CLASS_MAX_NCSS; |
54 | |
|
55 | |
|
56 | 1 | private int mMethodMax = METHOD_MAX_NCSS; |
57 | |
|
58 | |
|
59 | |
private FastStack<Counter> mCounters; |
60 | |
|
61 | |
@Override |
62 | |
public int[] getDefaultTokens() |
63 | |
{ |
64 | 1 | return new int[]{ |
65 | |
TokenTypes.CLASS_DEF, |
66 | |
TokenTypes.INTERFACE_DEF, |
67 | |
TokenTypes.METHOD_DEF, |
68 | |
TokenTypes.CTOR_DEF, |
69 | |
TokenTypes.INSTANCE_INIT, |
70 | |
TokenTypes.STATIC_INIT, |
71 | |
TokenTypes.PACKAGE_DEF, |
72 | |
TokenTypes.IMPORT, |
73 | |
TokenTypes.VARIABLE_DEF, |
74 | |
TokenTypes.CTOR_CALL, |
75 | |
TokenTypes.SUPER_CTOR_CALL, |
76 | |
TokenTypes.LITERAL_IF, |
77 | |
TokenTypes.LITERAL_ELSE, |
78 | |
TokenTypes.LITERAL_WHILE, |
79 | |
TokenTypes.LITERAL_DO, |
80 | |
TokenTypes.LITERAL_FOR, |
81 | |
TokenTypes.LITERAL_SWITCH, |
82 | |
TokenTypes.LITERAL_BREAK, |
83 | |
TokenTypes.LITERAL_CONTINUE, |
84 | |
TokenTypes.LITERAL_RETURN, |
85 | |
TokenTypes.LITERAL_THROW, |
86 | |
TokenTypes.LITERAL_SYNCHRONIZED, |
87 | |
TokenTypes.LITERAL_CATCH, |
88 | |
TokenTypes.LITERAL_FINALLY, |
89 | |
TokenTypes.EXPR, |
90 | |
TokenTypes.LABELED_STAT, |
91 | |
TokenTypes.LITERAL_CASE, |
92 | |
TokenTypes.LITERAL_DEFAULT, |
93 | |
}; |
94 | |
} |
95 | |
|
96 | |
@Override |
97 | |
public int[] getRequiredTokens() |
98 | |
{ |
99 | 0 | return new int[]{ |
100 | |
TokenTypes.CLASS_DEF, |
101 | |
TokenTypes.INTERFACE_DEF, |
102 | |
TokenTypes.METHOD_DEF, |
103 | |
TokenTypes.CTOR_DEF, |
104 | |
TokenTypes.INSTANCE_INIT, |
105 | |
TokenTypes.STATIC_INIT, |
106 | |
TokenTypes.PACKAGE_DEF, |
107 | |
TokenTypes.IMPORT, |
108 | |
TokenTypes.VARIABLE_DEF, |
109 | |
TokenTypes.CTOR_CALL, |
110 | |
TokenTypes.SUPER_CTOR_CALL, |
111 | |
TokenTypes.LITERAL_IF, |
112 | |
TokenTypes.LITERAL_ELSE, |
113 | |
TokenTypes.LITERAL_WHILE, |
114 | |
TokenTypes.LITERAL_DO, |
115 | |
TokenTypes.LITERAL_FOR, |
116 | |
TokenTypes.LITERAL_SWITCH, |
117 | |
TokenTypes.LITERAL_BREAK, |
118 | |
TokenTypes.LITERAL_CONTINUE, |
119 | |
TokenTypes.LITERAL_RETURN, |
120 | |
TokenTypes.LITERAL_THROW, |
121 | |
TokenTypes.LITERAL_SYNCHRONIZED, |
122 | |
TokenTypes.LITERAL_CATCH, |
123 | |
TokenTypes.LITERAL_FINALLY, |
124 | |
TokenTypes.EXPR, |
125 | |
TokenTypes.LABELED_STAT, |
126 | |
TokenTypes.LITERAL_CASE, |
127 | |
TokenTypes.LITERAL_DEFAULT, |
128 | |
}; |
129 | |
} |
130 | |
|
131 | |
@Override |
132 | |
public void beginTree(DetailAST aRootAST) |
133 | |
{ |
134 | 1 | mCounters = new FastStack<Counter>(); |
135 | |
|
136 | |
|
137 | 1 | mCounters.push(new Counter()); |
138 | 1 | } |
139 | |
|
140 | |
@Override |
141 | |
public void visitToken(DetailAST aAST) |
142 | |
{ |
143 | 55 | final int tokenType = aAST.getType(); |
144 | |
|
145 | 55 | if ((TokenTypes.CLASS_DEF == tokenType) |
146 | |
|| (TokenTypes.METHOD_DEF == tokenType) |
147 | |
|| (TokenTypes.CTOR_DEF == tokenType) |
148 | |
|| (TokenTypes.STATIC_INIT == tokenType) |
149 | |
|| (TokenTypes.INSTANCE_INIT == tokenType)) |
150 | |
{ |
151 | |
|
152 | 8 | mCounters.push(new Counter()); |
153 | |
} |
154 | |
|
155 | |
|
156 | 55 | if (isCountable(aAST)) { |
157 | |
|
158 | 35 | for (final Counter c : mCounters) { |
159 | 97 | c.increment(); |
160 | |
} |
161 | |
} |
162 | 55 | } |
163 | |
|
164 | |
@Override |
165 | |
public void leaveToken(DetailAST aAST) |
166 | |
{ |
167 | 55 | final int tokenType = aAST.getType(); |
168 | 55 | if ((TokenTypes.METHOD_DEF == tokenType) |
169 | |
|| (TokenTypes.CTOR_DEF == tokenType) |
170 | |
|| (TokenTypes.STATIC_INIT == tokenType) |
171 | |
|| (TokenTypes.INSTANCE_INIT == tokenType)) |
172 | |
{ |
173 | |
|
174 | 5 | final Counter counter = mCounters.pop(); |
175 | |
|
176 | 5 | final int count = counter.getCount(); |
177 | 5 | if (count > mMethodMax) { |
178 | 5 | log(aAST.getLineNo(), aAST.getColumnNo(), "ncss.method", |
179 | |
count, mMethodMax); |
180 | |
} |
181 | 5 | } |
182 | 50 | else if (TokenTypes.CLASS_DEF == tokenType) { |
183 | |
|
184 | 3 | final Counter counter = mCounters.pop(); |
185 | |
|
186 | 3 | final int count = counter.getCount(); |
187 | 3 | if (count > mClassMax) { |
188 | 3 | log(aAST.getLineNo(), aAST.getColumnNo(), "ncss.class", |
189 | |
count, mClassMax); |
190 | |
} |
191 | |
} |
192 | 55 | } |
193 | |
|
194 | |
@Override |
195 | |
public void finishTree(DetailAST aRootAST) |
196 | |
{ |
197 | |
|
198 | 1 | final Counter counter = mCounters.pop(); |
199 | |
|
200 | 1 | final int count = counter.getCount(); |
201 | 1 | if (count > mFileMax) { |
202 | 1 | log(aRootAST.getLineNo(), aRootAST.getColumnNo(), "ncss.file", |
203 | |
count, mFileMax); |
204 | |
} |
205 | 1 | } |
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | |
|
211 | |
|
212 | |
|
213 | |
public void setFileMaximum(int aFileMax) |
214 | |
{ |
215 | 1 | mFileMax = aFileMax; |
216 | 1 | } |
217 | |
|
218 | |
|
219 | |
|
220 | |
|
221 | |
|
222 | |
|
223 | |
|
224 | |
public void setClassMaximum(int aClassMax) |
225 | |
{ |
226 | 1 | mClassMax = aClassMax; |
227 | 1 | } |
228 | |
|
229 | |
|
230 | |
|
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | |
public void setMethodMaximum(int aMethodMax) |
236 | |
{ |
237 | 1 | mMethodMax = aMethodMax; |
238 | 1 | } |
239 | |
|
240 | |
|
241 | |
|
242 | |
|
243 | |
|
244 | |
|
245 | |
|
246 | |
|
247 | |
private boolean isCountable(DetailAST aAST) |
248 | |
{ |
249 | 55 | boolean countable = true; |
250 | |
|
251 | 55 | final int tokenType = aAST.getType(); |
252 | |
|
253 | |
|
254 | 55 | if (TokenTypes.EXPR == tokenType) { |
255 | 21 | countable = isExpressionCountable(aAST); |
256 | |
} |
257 | |
|
258 | 34 | else if (TokenTypes.VARIABLE_DEF == tokenType) { |
259 | 12 | countable = isVariableDefCountable(aAST); |
260 | |
} |
261 | 55 | return countable; |
262 | |
} |
263 | |
|
264 | |
|
265 | |
|
266 | |
|
267 | |
|
268 | |
|
269 | |
|
270 | |
private boolean isVariableDefCountable(DetailAST aAST) |
271 | |
{ |
272 | 12 | boolean countable = false; |
273 | |
|
274 | |
|
275 | |
|
276 | 12 | final int parentType = aAST.getParent().getType(); |
277 | |
|
278 | 12 | if ((TokenTypes.SLIST == parentType) |
279 | |
|| (TokenTypes.OBJBLOCK == parentType)) |
280 | |
{ |
281 | 11 | final DetailAST prevSibling = aAST.getPreviousSibling(); |
282 | |
|
283 | |
|
284 | |
|
285 | |
|
286 | |
|
287 | 11 | countable = (prevSibling == null) |
288 | |
|| (TokenTypes.COMMA != prevSibling.getType()); |
289 | |
} |
290 | |
|
291 | 12 | return countable; |
292 | |
} |
293 | |
|
294 | |
|
295 | |
|
296 | |
|
297 | |
|
298 | |
|
299 | |
|
300 | |
private boolean isExpressionCountable(DetailAST aAST) |
301 | |
{ |
302 | 21 | boolean countable = true; |
303 | |
|
304 | |
|
305 | |
|
306 | |
|
307 | 21 | final int parentType = aAST.getParent().getType(); |
308 | 21 | switch (parentType) { |
309 | |
case TokenTypes.SLIST : |
310 | |
case TokenTypes.LABELED_STAT : |
311 | |
case TokenTypes.LITERAL_FOR : |
312 | |
case TokenTypes.LITERAL_DO : |
313 | |
case TokenTypes.LITERAL_WHILE : |
314 | |
case TokenTypes.LITERAL_IF : |
315 | |
case TokenTypes.LITERAL_ELSE : |
316 | |
|
317 | 5 | final DetailAST prevSibling = aAST.getPreviousSibling(); |
318 | 5 | countable = (prevSibling == null) |
319 | |
|| (TokenTypes.LPAREN != prevSibling.getType()); |
320 | 5 | break; |
321 | |
default : |
322 | 16 | countable = false; |
323 | |
break; |
324 | |
} |
325 | 21 | return countable; |
326 | |
} |
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | |
|
332 | |
|
333 | 18 | private static class Counter |
334 | |
{ |
335 | |
|
336 | |
private int mIvCount; |
337 | |
|
338 | |
|
339 | |
|
340 | |
|
341 | |
public void increment() |
342 | |
{ |
343 | 97 | mIvCount++; |
344 | 97 | } |
345 | |
|
346 | |
|
347 | |
|
348 | |
|
349 | |
|
350 | |
|
351 | |
public int getCount() |
352 | |
{ |
353 | 9 | return mIvCount; |
354 | |
} |
355 | |
} |
356 | |
} |