KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > whitespace > WhitespaceAroundCheck


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.whitespace;
20
21 import com.puppycrawl.tools.checkstyle.api.Check;
22 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
23 import com.puppycrawl.tools.checkstyle.api.DetailAST;
24
25 /**
26  * <p>
27  * Checks that a token is surrounded by whitespace.
28  * </p>
29  * <p> By default the check will check the following operators:
30  * {@link TokenTypes#LITERAL_ASSERT ASSERT},
31  * {@link TokenTypes#ASSIGN ASSIGN},
32  * {@link TokenTypes#BAND BAND},
33  * {@link TokenTypes#BAND_ASSIGN BAND_ASSIGN},
34  * {@link TokenTypes#BOR BOR},
35  * {@link TokenTypes#BOR_ASSIGN BOR_ASSIGN},
36  * {@link TokenTypes#BSR BSR},
37  * {@link TokenTypes#BSR_ASSIGN BSR_ASSIGN},
38  * {@link TokenTypes#BXOR BXOR},
39  * {@link TokenTypes#BXOR_ASSIGN BXOR_ASSIGN},
40  * {@link TokenTypes#COLON COLON},
41  * {@link TokenTypes#DIV DIV},
42  * {@link TokenTypes#DIV_ASSIGN DIV_ASSIGN},
43  * {@link TokenTypes#EQUAL EQUAL},
44  * {@link TokenTypes#GE GE},
45  * {@link TokenTypes#GT GT},
46  * {@link TokenTypes#LAND LAND},
47  * {@link TokenTypes#LCURLY LCURLY},
48  * {@link TokenTypes#LE LE},
49  * {@link TokenTypes#LITERAL_CATCH LITERAL_CATCH},
50  * {@link TokenTypes#LITERAL_DO LITERAL_DO},
51  * {@link TokenTypes#LITERAL_ELSE LITERAL_ELSE},
52  * {@link TokenTypes#LITERAL_FINALLY LITERAL_FINALLY},
53  * {@link TokenTypes#LITERAL_FOR LITERAL_FOR},
54  * {@link TokenTypes#LITERAL_IF LITERAL_IF},
55  * {@link TokenTypes#LITERAL_RETURN LITERAL_RETURN},
56  * {@link TokenTypes#LITERAL_SYNCHRONIZED LITERAL_SYNCHRONIZED},
57  * {@link TokenTypes#LITERAL_TRY LITERAL_TRY},
58  * {@link TokenTypes#LITERAL_WHILE LITERAL_WHILE},
59  * {@link TokenTypes#LOR LOR},
60  * {@link TokenTypes#LT LT},
61  * {@link TokenTypes#MINUS MINUS},
62  * {@link TokenTypes#MINUS_ASSIGN MINUS_ASSIGN},
63  * {@link TokenTypes#MOD MOD},
64  * {@link TokenTypes#MOD_ASSIGN MOD_ASSIGN},
65  * {@link TokenTypes#NOT_EQUAL NOT_EQUAL},
66  * {@link TokenTypes#PLUS PLUS},
67  * {@link TokenTypes#PLUS_ASSIGN PLUS_ASSIGN},
68  * {@link TokenTypes#QUESTION QUESTION},
69  * {@link TokenTypes#RCURLY RCURLY},
70  * {@link TokenTypes#SL SL},
71  * {@link TokenTypes#SLIST SLIST},
72  * {@link TokenTypes#SL_ASSIGN SL_ASSIGN},
73  * {@link TokenTypes#SR SR},
74  * {@link TokenTypes#SR_ASSIGN SR_ASSIGN},
75  * {@link TokenTypes#STAR STAR},
76  * {@link TokenTypes#STAR_ASSIGN STAR_ASSIGN}.
77  * {@link TokenTypes#LITERAL_ASSERT LITERAL_ASSERT}.
78  * {@link TokenTypes#GENERIC_START GENERIC_START}.
79  * {@link TokenTypes#GENERIC_END GENERIC_END}.
80  * {@link TokenTypes#TYPE_EXTENSION_AND TYPE_EXTENSION_AND}.
81  * {@link TokenTypes#WILDCARD_TYPE WILDCARD_TYPE}.
82  * </p>
83  * <p>
84  * An example of how to configure the check is:
85  * </p>
86  * <pre>
87  * &lt;module name="WhitespaceAround"/&gt;
88  * </pre>
89  * <p> An example of how to configure the check for whitespace only around
90  * assignment operators is:
91  * </p>
92  * <pre>
93  * &lt;module name="WhitespaceAround"&gt;
94  * &lt;property name="tokens"
95  * value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/&gt;
96  * &lt;/module&gt;
97  * </pre>
98  * <p>
99  * In addition, this check can be configured to allow empty method and/or
100  * constructor bodies. For example, a method with an empty body might look
101  * like:
102  * </p>
103  * <p>
104  * <pre> public void doSomething(int val) {}</pre>
105  * </p>
106  * <p>
107  * To configure the check to allow empty method blocks use
108  * </p>
109  * <p>
110  * <pre> &lt;property name="allowEmptyMethods" value="true" /&gt;</pre>
111  * </p>
112  * <p>
113  * To configure the check to allow empty constructor blocks use
114  * </p>
115  * <p>
116  * <pre> &lt;property name="allowEmptyConstructors" value="true" /&gt;</pre>
117  * </p>
118  *
119  * @author Oliver Burn
120  * @version 1.0
121  */

122 public class WhitespaceAroundCheck extends Check
123 {
124     /** Whether or not empty constructor bodies are allowed. */
125     private boolean mAllowEmptyCtors;
126     /** Whether or not empty method bodies are allowed. */
127     private boolean mAllowEmptyMethods;
128
129     /** {@inheritDoc} */
130     public int[] getDefaultTokens()
131     {
132         return new int[] {
133             TokenTypes.ASSIGN,
134             TokenTypes.BAND,
135             TokenTypes.BAND_ASSIGN,
136             TokenTypes.BOR,
137             TokenTypes.BOR_ASSIGN,
138             TokenTypes.BSR,
139             TokenTypes.BSR_ASSIGN,
140             TokenTypes.BXOR,
141             TokenTypes.BXOR_ASSIGN,
142             TokenTypes.COLON,
143             TokenTypes.DIV,
144             TokenTypes.DIV_ASSIGN,
145             TokenTypes.EQUAL,
146             TokenTypes.GE,
147             TokenTypes.GT,
148             TokenTypes.LAND,
149             TokenTypes.LCURLY,
150             TokenTypes.LE,
151             TokenTypes.LITERAL_CATCH,
152             TokenTypes.LITERAL_DO,
153             TokenTypes.LITERAL_ELSE,
154             TokenTypes.LITERAL_FINALLY,
155             TokenTypes.LITERAL_FOR,
156             TokenTypes.LITERAL_IF,
157             TokenTypes.LITERAL_RETURN,
158             TokenTypes.LITERAL_SYNCHRONIZED,
159             TokenTypes.LITERAL_TRY,
160             TokenTypes.LITERAL_WHILE,
161             TokenTypes.LOR,
162             TokenTypes.LT,
163             TokenTypes.MINUS,
164             TokenTypes.MINUS_ASSIGN,
165             TokenTypes.MOD,
166             TokenTypes.MOD_ASSIGN,
167             TokenTypes.NOT_EQUAL,
168             TokenTypes.PLUS,
169             TokenTypes.PLUS_ASSIGN,
170             TokenTypes.QUESTION,
171             TokenTypes.RCURLY,
172             TokenTypes.SL,
173             TokenTypes.SLIST,
174             TokenTypes.SL_ASSIGN,
175             TokenTypes.SR,
176             TokenTypes.SR_ASSIGN,
177             TokenTypes.STAR,
178             TokenTypes.STAR_ASSIGN,
179             TokenTypes.LITERAL_ASSERT,
180             TokenTypes.GENERIC_START,
181             TokenTypes.GENERIC_END,
182             TokenTypes.TYPE_EXTENSION_AND,
183             TokenTypes.WILDCARD_TYPE,
184         };
185     }
186
187     /**
188      * Sets whether or now empty method bodies are allowed.
189      * @param aAllow <code>true</code> to allow empty method bodies.
190      */

191     public void setAllowEmptyMethods(boolean aAllow)
192     {
193         mAllowEmptyMethods = aAllow;
194     }
195
196     /**
197      * Sets whether or now empty constructor bodies are allowed.
198      * @param aAllow <code>true</code> to allow empty constructor bodies.
199      */

200     public void setAllowEmptyConstructors(boolean aAllow)
201     {
202         mAllowEmptyCtors = aAllow;
203     }
204
205     /** {@inheritDoc} */
206     public void visitToken(DetailAST aAST)
207     {
208         final int type = aAST.getType();
209         final int parentType = aAST.getParent().getType();
210
211         // Check for CURLY in array initializer
212
if (((type == TokenTypes.RCURLY) || (type == TokenTypes.LCURLY))
213             && (parentType == TokenTypes.ARRAY_INIT))
214         {
215             return;
216         }
217
218         // Check for import pkg.name.*;
219
if ((type == TokenTypes.STAR)
220             && (parentType == TokenTypes.DOT))
221         {
222             return;
223         }
224
225         // Check for an SLIST that has a parent CASE_GROUP. It is not a '{'.
226
if ((type == TokenTypes.SLIST)
227             && (parentType == TokenTypes.CASE_GROUP))
228         {
229             return;
230         }
231
232         //we do not want to check colon for cases and defaults
233
if ((type == TokenTypes.COLON)
234             && ((parentType == TokenTypes.LITERAL_DEFAULT)
235                 || (parentType == TokenTypes.LITERAL_CASE)))
236         {
237             return;
238         }
239
240         // Check for allowed empty method or ctor blocks.
241
if (emptyMethodBlockCheck(aAST, parentType)
242             || emptyCtorBlockCheck(aAST, parentType))
243         {
244             return;
245         }
246
247         final String JavaDoc[] lines = getLines();
248         final String JavaDoc line = lines[aAST.getLineNo() - 1];
249         final int before = aAST.getColumnNo() - 1;
250         final int after = aAST.getColumnNo() + aAST.getText().length();
251
252         if ((before >= 0) && !Character.isWhitespace(line.charAt(before))) {
253             log(aAST.getLineNo(), aAST.getColumnNo(),
254                     "ws.notPreceded", new Object JavaDoc[]{aAST.getText()});
255         }
256
257         if (after >= line.length()) {
258             return;
259         }
260
261         final char nextChar = line.charAt(after);
262         if (!Character.isWhitespace(nextChar)
263             // Check for "return;"
264
&& !((type == TokenTypes.LITERAL_RETURN)
265                 && (aAST.getFirstChild().getType() == TokenTypes.SEMI))
266             // Check for "})" or "};" or "},". Happens with anon-inners
267
&& !((type == TokenTypes.RCURLY)
268                 && ((nextChar == ')')
269                     || (nextChar == ';')
270                     || (nextChar == ','))))
271         {
272             log(
273                 aAST.getLineNo(),
274                 aAST.getColumnNo() + aAST.getText().length(),
275                 "ws.notFollowed",
276                 new Object JavaDoc[] {aAST.getText()});
277         }
278     }
279
280     /**
281      * Test if the given <code>DetailAST</code> is part of an allowed empty
282      * method block.
283      * @param aAST the <code>DetailAST</code> to test.
284      * @param aParentType the token type of <code>aAST</code>'s parent.
285      * @return <code>true</code> if <code>aAST</code> makes up part of an
286      * allowed empty method block.
287      */

288     private boolean emptyMethodBlockCheck(DetailAST aAST, int aParentType)
289     {
290         return mAllowEmptyMethods
291             && emptyBlockCheck(aAST, aParentType, TokenTypes.METHOD_DEF);
292     }
293
294     /**
295      * Test if the given <code>DetailAST</code> is part of an allowed empty
296      * constructor (ctor) block.
297      * @param aAST the <code>DetailAST</code> to test.
298      * @param aParentType the token type of <code>aAST</code>'s parent.
299      * @return <code>true</code> if <code>aAST</code> makes up part of an
300      * allowed empty constructor block.
301      */

302     private boolean emptyCtorBlockCheck(DetailAST aAST, int aParentType)
303     {
304         return mAllowEmptyCtors
305             && emptyBlockCheck(aAST, aParentType, TokenTypes.CTOR_DEF);
306     }
307
308     /**
309      * Test if the given <code>DetailAST</code> is part of an empty block.
310      * An example empty block might look like the following
311      * <p>
312      * <pre> public void myMethod(int val) {}</pre>
313      * <p>
314      * In the above, the method body is an empty block ("{}").
315      *
316      * @param aAST the <code>DetailAST</code> to test.
317      * @param aParentType the token type of <code>aAST</code>'s parent.
318      * @param aMatch the parent token type we're looking to match.
319      * @return <code>true</code> if <code>aAST</code> makes up part of an
320      * empty block contained under a <code>aMatch</code> token type
321      * node.
322      */

323     private boolean emptyBlockCheck(DetailAST aAST, int aParentType, int aMatch)
324     {
325         final int type = aAST.getType();
326         if (type == TokenTypes.RCURLY) {
327             final DetailAST grandParent = aAST.getParent().getParent();
328             return (aParentType == TokenTypes.SLIST)
329                 && (grandParent.getType() == aMatch);
330         }
331
332         return (type == TokenTypes.SLIST)
333             && (aParentType == aMatch)
334             && (aAST.getFirstChild().getType() == TokenTypes.RCURLY);
335     }
336 }
337
Popular Tags