KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > metrics > JavaNCSSCheck


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2005 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.metrics;
20
21 import java.util.Stack JavaDoc;
22
23 import com.puppycrawl.tools.checkstyle.api.Check;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26
27 /**
28  * This check calculates the Non Commenting Source Statements (NCSS) metric for
29  * java source files and methods. The check adheres to the <a
30  * HREF="http://www.kclee.com/clemens/java/javancss/">JavaNCSS specification
31  * </a> and gives the same results as the JavaNCSS tool.
32  *
33  * The NCSS-metric tries to determine complexity of methods, classes and files
34  * by counting the non commenting lines. Roughly said this is (nearly)
35  * equivalent to counting the semicolons and opening curly braces.
36  *
37  * @author Lars Ködderitzsch
38  */

39 public class JavaNCSSCheck extends Check
40 {
41     /** default constant for max file ncss */
42     private static final int FILE_MAX_NCSS = 2000;
43
44     /** default constant for max file ncss */
45     private static final int CLASS_MAX_NCSS = 1500;
46
47     /** default constant for max method ncss */
48     private static final int METHOD_MAX_NCSS = 50;
49
50     /** maximum ncss for a complete source file */
51     private int mFileMax = FILE_MAX_NCSS;
52
53     /** maximum ncss for a class */
54     private int mClassMax = CLASS_MAX_NCSS;
55
56     /** maximum ncss for a method */
57     private int mMethodMax = METHOD_MAX_NCSS;
58
59     /** list containing the stacked counters */
60     private Stack JavaDoc mCounters;
61
62     /**
63      * {@inheritDoc}
64      */

65     public int[] getDefaultTokens()
66     {
67         return new int[]{
68             TokenTypes.CLASS_DEF,
69             TokenTypes.INTERFACE_DEF,
70             TokenTypes.METHOD_DEF,
71             TokenTypes.CTOR_DEF,
72             TokenTypes.INSTANCE_INIT,
73             TokenTypes.STATIC_INIT,
74             TokenTypes.PACKAGE_DEF,
75             TokenTypes.IMPORT,
76             TokenTypes.VARIABLE_DEF,
77             TokenTypes.CTOR_CALL,
78             TokenTypes.SUPER_CTOR_CALL,
79             TokenTypes.LITERAL_IF,
80             TokenTypes.LITERAL_ELSE,
81             TokenTypes.LITERAL_WHILE,
82             TokenTypes.LITERAL_DO,
83             TokenTypes.LITERAL_FOR,
84             TokenTypes.LITERAL_SWITCH,
85             TokenTypes.LITERAL_BREAK,
86             TokenTypes.LITERAL_CONTINUE,
87             TokenTypes.LITERAL_RETURN,
88             TokenTypes.LITERAL_THROW,
89             TokenTypes.LITERAL_SYNCHRONIZED,
90             TokenTypes.LITERAL_CATCH,
91             TokenTypes.LITERAL_FINALLY,
92             TokenTypes.EXPR,
93             TokenTypes.LABELED_STAT,
94             TokenTypes.LITERAL_CASE,
95             TokenTypes.LITERAL_DEFAULT,
96         };
97     }
98
99     /**
100      * {@inheritDoc}
101      */

102     public int[] getRequiredTokens()
103     {
104         return new int[]{
105             TokenTypes.CLASS_DEF,
106             TokenTypes.INTERFACE_DEF,
107             TokenTypes.METHOD_DEF,
108             TokenTypes.CTOR_DEF,
109             TokenTypes.INSTANCE_INIT,
110             TokenTypes.STATIC_INIT,
111             TokenTypes.PACKAGE_DEF,
112             TokenTypes.IMPORT,
113             TokenTypes.VARIABLE_DEF,
114             TokenTypes.CTOR_CALL,
115             TokenTypes.SUPER_CTOR_CALL,
116             TokenTypes.LITERAL_IF,
117             TokenTypes.LITERAL_ELSE,
118             TokenTypes.LITERAL_WHILE,
119             TokenTypes.LITERAL_DO,
120             TokenTypes.LITERAL_FOR,
121             TokenTypes.LITERAL_SWITCH,
122             TokenTypes.LITERAL_BREAK,
123             TokenTypes.LITERAL_CONTINUE,
124             TokenTypes.LITERAL_RETURN,
125             TokenTypes.LITERAL_THROW,
126             TokenTypes.LITERAL_SYNCHRONIZED,
127             TokenTypes.LITERAL_CATCH,
128             TokenTypes.LITERAL_FINALLY,
129             TokenTypes.EXPR,
130             TokenTypes.LABELED_STAT,
131             TokenTypes.LITERAL_CASE,
132             TokenTypes.LITERAL_DEFAULT,
133         };
134     }
135
136     /**
137      * {@inheritDoc}
138      */

139     public void beginTree(DetailAST aRootAST)
140     {
141         mCounters = new Stack JavaDoc();
142
143         //add a counter for the file
144
mCounters.push(new Counter());
145     }
146
147     /**
148      * {@inheritDoc}
149      */

150     public void visitToken(DetailAST aAST)
151     {
152         final int tokenType = aAST.getType();
153
154         if ((TokenTypes.CLASS_DEF == tokenType)
155             || (TokenTypes.METHOD_DEF == tokenType)
156             || (TokenTypes.CTOR_DEF == tokenType)
157             || (TokenTypes.STATIC_INIT == tokenType)
158             || (TokenTypes.INSTANCE_INIT == tokenType))
159         {
160             //add a counter for this class/method
161
mCounters.push(new Counter());
162         }
163
164         //check if token is countable
165
if (isCountable(aAST)) {
166             //increment the stacked counters
167
final int size = mCounters.size();
168             for (int i = 0; i < size; i++) {
169                 ((Counter) mCounters.get(i)).increment();
170             }
171         }
172     }
173
174     /**
175      * {@inheritDoc}
176      */

177     public void leaveToken(DetailAST aAST)
178     {
179         final int tokenType = aAST.getType();
180         if ((TokenTypes.METHOD_DEF == tokenType)
181             || (TokenTypes.CTOR_DEF == tokenType)
182             || (TokenTypes.STATIC_INIT == tokenType)
183             || (TokenTypes.INSTANCE_INIT == tokenType))
184         {
185             //pop counter from the stack
186
final Counter counter = (Counter) mCounters.pop();
187
188             final int count = counter.getCount();
189             if (count > mMethodMax) {
190                 log(aAST.getLineNo(), aAST.getColumnNo(), "ncss.method",
191                         new Integer JavaDoc(count), new Integer JavaDoc(mMethodMax));
192             }
193         }
194         else if (TokenTypes.CLASS_DEF == tokenType) {
195             //pop counter from the stack
196
final Counter counter = (Counter) mCounters.pop();
197
198             final int count = counter.getCount();
199             if (count > mClassMax) {
200                 log(aAST.getLineNo(), aAST.getColumnNo(), "ncss.class",
201                         new Integer JavaDoc(count), new Integer JavaDoc(mClassMax));
202             }
203         }
204     }
205
206     /**
207      * {@inheritDoc}
208      */

209     public void finishTree(DetailAST aRootAST)
210     {
211         //pop counter from the stack
212
final Counter counter = (Counter) mCounters.pop();
213
214         final int count = counter.getCount();
215         if (count > mFileMax) {
216             log(aRootAST.getLineNo(), aRootAST.getColumnNo(), "ncss.file",
217                     new Integer JavaDoc(count), new Integer JavaDoc(mMethodMax));
218         }
219     }
220
221     /**
222      * Sets the maximum ncss for a file.
223      *
224      * @param aFileMax
225      * the maximum ncss
226      */

227     public void setFileMaximum(int aFileMax)
228     {
229         mFileMax = aFileMax;
230     }
231
232     /**
233      * Sets the maximum ncss for a class.
234      *
235      * @param aClassMax
236      * the maximum ncss
237      */

238     public void setClassMaximum(int aClassMax)
239     {
240         mClassMax = aClassMax;
241     }
242
243     /**
244      * Sets the maximum ncss for a method.
245      *
246      * @param aMethodMax
247      * the maximum ncss
248      */

249     public void setMethodMaximum(int aMethodMax)
250     {
251         mMethodMax = aMethodMax;
252     }
253
254     /**
255      * Checks if a token is countable for the ncss metric
256      *
257      * @param aAST
258      * the AST
259      * @return true if the token is countable
260      */

261     private boolean isCountable(DetailAST aAST)
262     {
263         boolean countable = true;
264
265         final int tokenType = aAST.getType();
266
267         //check if an expression is countable
268
if (TokenTypes.EXPR == tokenType) {
269             countable = isExpressionCountable(aAST);
270         }
271         //check if an variable definition is countable
272
else if (TokenTypes.VARIABLE_DEF == tokenType) {
273             countable = isVariableDefCountable(aAST);
274         }
275         return countable;
276     }
277
278     /**
279      * Checks if a variable definition is countable.
280      *
281      * @param aAST the AST
282      * @return true if the variable definition is countable, false otherwise
283      */

284     private boolean isVariableDefCountable(DetailAST aAST)
285     {
286         boolean countable = false;
287
288         //count variable defs only if they are direct child to a slist or
289
// object block
290
final int parentType = aAST.getParent().getType();
291
292         if ((TokenTypes.SLIST == parentType)
293             || (TokenTypes.OBJBLOCK == parentType))
294         {
295             final DetailAST prevSibling = aAST.getPreviousSibling();
296
297             //is countable if no previous sibling is found or
298
//the sibling is no COMMA.
299
//This is done because multiple assignment on one line are countes
300
// as 1
301
countable = (prevSibling == null)
302                     || (TokenTypes.COMMA != prevSibling.getType());
303         }
304
305         return countable;
306     }
307
308     /**
309      * Checks if an expression is countable for the ncss metric.
310      *
311      * @param aAST the AST
312      * @return true if the expression is countable, false otherwise
313      */

314     private boolean isExpressionCountable(DetailAST aAST)
315     {
316         boolean countable = true;
317
318         //count expressions only if they are direct child to a slist (method
319
// body, for loop...)
320
//or direct child of label,if,else,do,while,for
321
final int parentType = aAST.getParent().getType();
322         switch (parentType) {
323         case TokenTypes.SLIST :
324         case TokenTypes.LABELED_STAT :
325         case TokenTypes.LITERAL_FOR :
326         case TokenTypes.LITERAL_DO :
327         case TokenTypes.LITERAL_WHILE :
328         case TokenTypes.LITERAL_IF :
329         case TokenTypes.LITERAL_ELSE :
330             //don't count if or loop conditions
331
final DetailAST prevSibling = aAST.getPreviousSibling();
332             countable = (prevSibling == null)
333                 || (TokenTypes.LPAREN != prevSibling.getType());
334             break;
335         default :
336             countable = false;
337             break;
338         }
339         return countable;
340     }
341
342     /**
343      * @author Lars Ködderitzsch
344      *
345      * Class representing a counter,
346      */

347     private class Counter
348     {
349         /** the counters internal integer */
350         private int mIvCount;
351
352         /**
353          * Increments the counter.
354          */

355         public void increment()
356         {
357             mIvCount++;
358         }
359
360         /**
361          * Gets the counters value
362          *
363          * @return the counter
364          */

365         public int getCount()
366         {
367             return mIvCount;
368         }
369     }
370 }
371
Popular Tags