KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > DescendantTokenCheck


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;
20
21 import java.util.Arrays JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import antlr.collections.AST;
26
27 import com.puppycrawl.tools.checkstyle.api.Check;
28 import com.puppycrawl.tools.checkstyle.api.DetailAST;
29 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
30
31 /**
32  * <p>
33  * Checks for restricted tokens beneath other tokens.
34  * </p>
35  * <p>
36  * Examples of how to configure the check:
37  * </p>
38  * <pre>
39  * &lt;!-- String literal equality check --&gt;
40  * &lt;module name="DescendantToken"&gt;
41  * &lt;property name="tokens" value="EQUAL,NOT_EQUAL"/&gt;
42  * &lt;property name="limitedTokens" value="STRING_LITERAL"/&gt;
43  * &lt;property name="maximumNumber" value="0"/&gt;
44  * &lt;property name="maximumDepth" value="1"/&gt;
45  * &lt;/module&gt;
46  *
47  * &lt;!-- Switch with no default --&gt;
48  * &lt;module name="DescendantToken"&gt;
49  * &lt;property name="tokens" value="LITERAL_SWITCH"/&gt;
50  * &lt;property name="maximumDepth" value="2"/&gt;
51  * &lt;property name="limitedTokens" value="LITERAL_DEFAULT"/&gt;
52  * &lt;property name="minimumNumber" value="1"/&gt;
53  * &lt;/module&gt;
54  *
55  * &lt;!-- Assert statement may have side effects --&gt;
56  * &lt;module name="DescendantToken"&gt;
57  * &lt;property name="tokens" value="LITERAL_ASSERT"/&gt;
58  * &lt;property name="limitedTokens" value="ASSIGN,DEC,INC,POST_DEC,
59  * POST_INC,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,DIV_ASSIGN,MOD_ASSIGN,
60  * BSR_ASSIGN,SR_ASSIGN,SL_ASSIGN,BAND_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,
61  * METHOD_CALL"/&gt;
62  * &lt;property name="maximumNumber" value="0"/&gt;
63  * &lt;/module&gt;
64  *
65  * &lt;!-- Initialiser in for performs no setup - use while instead? --&gt;
66  * &lt;module name="DescendantToken"&gt;
67  * &lt;property name="tokens" value="FOR_INIT"/&gt;
68  * &lt;property name="limitedTokens" value="EXPR"/&gt;
69  * &lt;property name="minimumNumber" value="1"/&gt;
70  * &lt;/module&gt;
71  *
72  * &lt;!-- Condition in for performs no check --&gt;
73  * &lt;module name="DescendantToken"&gt;
74  * &lt;property name="tokens" value="FOR_CONDITION"/&gt;
75  * &lt;property name="limitedTokens" value="EXPR"/&gt;
76  * &lt;property name="minimumNumber" value="1"/&gt;
77  * &lt;/module&gt;
78  *
79  * &lt;!-- Switch within switch --&gt;
80  * &lt;module name="DescendantToken"&gt;
81  * &lt;property name="tokens" value="LITERAL_SWITCH"/&gt;
82  * &lt;property name="limitedTokens" value="LITERAL_SWITCH"/&gt;
83  * &lt;property name="maximumNumber" value="0"/&gt;
84  * &lt;property name="minimumDepth" value="1"/&gt;
85  * &lt;/module&gt;
86  *
87  * &lt;!-- Return from within a catch or finally block --&gt;
88  * &lt;module name="DescendantToken"&gt;
89  * &lt;property name="tokens" value="LITERAL_FINALLY,LITERAL_CATCH"/&gt;
90  * &lt;property name="limitedTokens" value="LITERAL_RETURN"/&gt;
91  * &lt;property name="maximumNumber" value="0"/&gt;
92  * &lt;/module&gt;
93  *
94  * &lt;!-- Try within catch or finally block --&gt;
95  * &lt;module name="DescendantToken"&gt;
96  * &lt;property name="tokens" value="LITERAL_CATCH,LITERAL_FINALLY"/&gt;
97  * &lt;property name="limitedTokens" value="LITERAL_TRY"/&gt;
98  * &lt;property name="maximumNumber" value="0"/&gt;
99  * &lt;/module&gt;
100  *
101  * &lt;!-- Too many cases within a switch --&gt;
102  * &lt;module name="DescendantToken"&gt;
103  * &lt;property name="tokens" value="LITERAL_SWITCH"/&gt;
104  * &lt;property name="limitedTokens" value="LITERAL_CASE"/&gt;
105  * &lt;property name="maximumDepth" value="2"/&gt;
106  * &lt;property name="maximumNumber" value="10"/&gt;
107  * &lt;/module&gt;
108  *
109  * &lt;!-- Too many local variables within a method --&gt;
110  * &lt;module name="DescendantToken"&gt;
111  * &lt;property name="tokens" value="METHOD_DEF"/&gt;
112  * &lt;property name="limitedTokens" value="VARIABLE_DEF"/&gt;
113  * &lt;property name="maximumDepth" value="2"/&gt;
114  * &lt;property name="maximumNumber" value="10"/&gt;
115  * &lt;/module&gt;
116  *
117  * &lt;!-- Too many returns from within a method --&gt;
118  * &lt;module name="DescendantToken"&gt;
119  * &lt;property name="tokens" value="METHOD_DEF"/&gt;
120  * &lt;property name="limitedTokens" value="LITERAL_RETURN"/&gt;
121  * &lt;property name="maximumNumber" value="3"/&gt;
122  * &lt;/module&gt;
123  *
124  * &lt;!-- Too many fields within an interface --&gt;
125  * &lt;module name="DescendantToken"&gt;
126  * &lt;property name="tokens" value="INTERFACE_DEF"/&gt;
127  * &lt;property name="limitedTokens" value="VARIABLE_DEF"/&gt;
128  * &lt;property name="maximumDepth" value="2"/&gt;
129  * &lt;property name="maximumNumber" value="0"/&gt;
130  * &lt;/module&gt;
131  *
132  * &lt;!-- Limit the number of exceptions a method can throw --&gt;
133  * &lt;module name="DescendantToken"&gt;
134  * &lt;property name="tokens" value="LITERAL_THROWS"/&gt;
135  * &lt;property name="limitedTokens" value="IDENT"/&gt;
136  * &lt;property name="maximumNumber" value="1"/&gt;
137  * &lt;/module&gt;
138  *
139  * &lt;!-- Limit the number of expressions in a method --&gt;
140  * &lt;module name="DescendantToken"&gt;
141  * &lt;property name="tokens" value="METHOD_DEF"/&gt;
142  * &lt;property name="limitedTokens" value="EXPR"/&gt;
143  * &lt;property name="maximumNumber" value="200"/&gt;
144  * &lt;/module&gt;
145  *
146  * &lt;!-- Disallow empty statements --&gt;
147  * &lt;module name="DescendantToken"&gt;
148  * &lt;property name="tokens" value="EMPTY_STAT"/&gt;
149  * &lt;property name="limitedTokens" value="EMPTY_STAT"/&gt;
150  * &lt;property name="maximumNumber" value="0"/&gt;
151  * &lt;property name="maximumDepth" value="0"/&gt;
152  * &lt;property name="maximumMessage"
153  * value="Empty statement is not allowed."/&gt;
154  * &lt;/module&gt;
155  *
156  * &lt;!-- Too many fields within a class --&gt;
157  * &lt;module name="DescendantToken"&gt;
158  * &lt;property name="tokens" value="CLASS_DEF"/&gt;
159  * &lt;property name="limitedTokens" value="VARIABLE_DEF"/&gt;
160  * &lt;property name="maximumDepth" value="2"/&gt;
161  * &lt;property name="maximumNumber" value="10"/&gt;
162  * &lt;/module&gt;
163  * </pre>
164  *
165  * @author Tim Tyler &lt;tim@tt1.org&gt;
166  * @author Rick Giles
167  */

168 public class DescendantTokenCheck extends Check
169 {
170      /** minimum depth */
171     private int mMinimumDepth;
172
173     /** maximum depth */
174     private int mMaximumDepth = Integer.MAX_VALUE;
175
176     /** minimum number */
177     private int mMinimumNumber;
178
179     /** maximum number */
180     private int mMaximumNumber = Integer.MAX_VALUE;
181
182     /** limited tokens */
183     private int[] mLimitedTokens = new int[0];
184
185     /** error message when minimum count not reached */
186     private String JavaDoc mMinimumMessage = "descendant.token.min";
187
188     /** error message when maximum count exceeded */
189     private String JavaDoc mMaximumMessage = "descendant.token.max";
190
191     /**
192      * Counts of descendant tokens.
193      * Indexed by (token ID - 1) for performance.
194      */

195     private int[] mCounts = new int[0];
196
197     /** {@inheritDoc} */
198     public int[] getDefaultTokens()
199     {
200         return new int[0];
201     }
202
203     /** {@inheritDoc} */
204     public void visitToken(DetailAST aAST)
205     {
206         //reset counts
207
Arrays.fill(mCounts, 0);
208
209         countTokens(aAST, 0);
210
211         // name of this token
212
final String JavaDoc name = TokenTypes.getTokenName(aAST.getType());
213
214         for (int i = 0; i < mLimitedTokens.length; i++) {
215             final int tokenCount = mCounts[mLimitedTokens[i] - 1];
216             if (tokenCount < mMinimumNumber) {
217                 final String JavaDoc descendantName =
218                     TokenTypes.getTokenName(mLimitedTokens[i]);
219                 log(aAST.getLineNo(),
220                     aAST.getColumnNo(),
221                     mMinimumMessage,
222                     new String JavaDoc[] {
223                         "" + tokenCount,
224                         "" + mMinimumNumber,
225                         name,
226                         descendantName,
227                     });
228             }
229             if (tokenCount > mMaximumNumber) {
230                 final String JavaDoc descendantName =
231                     TokenTypes.getTokenName(mLimitedTokens[i]);
232                 log(aAST.getLineNo(),
233                     aAST.getColumnNo(),
234                     mMaximumMessage,
235                     new String JavaDoc[] {
236                         "" + tokenCount,
237                         "" + mMaximumNumber,
238                         name,
239                         descendantName,
240                     });
241             }
242         }
243     }
244
245     /**
246      * Counts the number of occurrences of descendant tokens.
247      * @param aAST the root token for descendants.
248      * @param aDepth the maximum depth of the counted descendants.
249      */

250     private void countTokens(AST aAST, int aDepth)
251     {
252         if (aDepth <= mMaximumDepth) {
253             //update count
254
if (aDepth >= mMinimumDepth) {
255                 final int type = aAST.getType();
256                 if (type <= mCounts.length) {
257                     mCounts[type - 1]++;
258                 }
259             }
260             AST child = aAST.getFirstChild();
261             final int nextDepth = aDepth + 1;
262             while (child != null) {
263                 countTokens(child, nextDepth);
264                 child = child.getNextSibling();
265             }
266         }
267     }
268
269     /** {@inheritDoc} */
270     public int[] getAcceptableTokens()
271     {
272         // Any tokens set by property 'tokens' are acceptable
273
final Set JavaDoc tokenNames = getTokenNames();
274         final int[] result = new int[tokenNames.size()];
275         int i = 0;
276         final Iterator JavaDoc it = tokenNames.iterator();
277         while (it.hasNext()) {
278             final String JavaDoc name = (String JavaDoc) it.next();
279             result[i] = TokenTypes.getTokenId(name);
280             i++;
281         }
282         return result;
283     }
284
285     /**
286      * Sets the tokens which occurance as descendant is limited.
287      * @param aLimitedTokens - list of tokens to ignore.
288      */

289     public void setLimitedTokens(String JavaDoc[] aLimitedTokens)
290     {
291         mLimitedTokens = new int[aLimitedTokens.length];
292
293         int maxToken = 0;
294         for (int i = 0; i < aLimitedTokens.length; i++) {
295             mLimitedTokens[i] = TokenTypes.getTokenId(aLimitedTokens[i]);
296             if (mLimitedTokens[i] > maxToken) {
297                 maxToken = mLimitedTokens[i];
298             }
299         }
300         mCounts = new int[maxToken];
301     }
302
303     /**
304      * Sets the mimimum depth for descendant counts.
305      * @param aMinimumDepth the mimimum depth for descendant counts.
306      */

307     public void setMinimumDepth(int aMinimumDepth)
308     {
309         mMinimumDepth = aMinimumDepth;
310     }
311
312     /**
313      * Sets the maximum depth for descendant counts.
314      * @param aMaximumDepth the maximum depth for descendant counts.
315      */

316     public void setMaximumDepth(int aMaximumDepth)
317     {
318         mMaximumDepth = aMaximumDepth;
319     }
320
321    /**
322     * Sets a minimum count for descendants.
323     * @param aMinimumNumber the minimum count for descendants.
324     */

325     public void setMinimumNumber(int aMinimumNumber)
326     {
327         mMinimumNumber = aMinimumNumber;
328     }
329
330     /**
331       * Sets a maximum count for descendants.
332       * @param aMaximumNumber the maximum count for descendants.
333       */

334     public void setMaximumNumber(int aMaximumNumber)
335     {
336         mMaximumNumber = aMaximumNumber;
337     }
338
339     /**
340      * Sets the error message for minimum count not reached.
341      * @param aMessage the error message for minimum count not reached.
342      * Used as a <code>MessageFormat</code> pattern with arguments
343      * <ul>
344      * <li>{0} - token count</li>
345      * <li>{1} - minimum number</li>
346      * <li>{2} - name of token</li>
347      * <li>{3} - name of limited token</li>
348      * </ul>
349      */

350     public void setMinimumMessage(String JavaDoc aMessage)
351     {
352         mMinimumMessage = aMessage;
353     }
354
355     /**
356      * Sets the error message for maximum count exceeded.
357      * @param aMessage the error message for maximum count exceeded.
358      * Used as a <code>MessageFormat</code> pattern with arguments
359      * <ul>
360      * <li>{0} - token count</li>
361      * <li>{1} - maximum number</li>
362      * <li>{2} - name of token</li>
363      * <li>{3} - name of limited token</li>
364      * </ul>
365      */

366
367     public void setMaximumMessage(String JavaDoc aMessage)
368     {
369         mMaximumMessage = aMessage;
370     }
371 }
372
Popular Tags