Source code: com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2003 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 * </p>
78 * <p>
79 * An example of how to configure the check is:
80 * </p>
81 * <pre>
82 * <module name="WhitespaceAround"/>
83 * </pre>
84 * <p> An example of how to configure the check for whitespace only around
85 * assignment operators is:
86 * </p>
87 * <pre>
88 * <module name="WhitespaceAround">
89 * <property name="tokens"
90 * value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/>
91 * </module>
92 * </pre>
93 *
94 * @author Oliver Burn
95 * @version 1.0
96 */
97 public class WhitespaceAroundCheck
98 extends Check
99 {
100 /** @see com.puppycrawl.tools.checkstyle.api.Check */
101 public int[] getDefaultTokens()
102 {
103 return new int[] {
104 TokenTypes.ASSIGN,
105 TokenTypes.BAND,
106 TokenTypes.BAND_ASSIGN,
107 TokenTypes.BOR,
108 TokenTypes.BOR_ASSIGN,
109 TokenTypes.BSR,
110 TokenTypes.BSR_ASSIGN,
111 TokenTypes.BXOR,
112 TokenTypes.BXOR_ASSIGN,
113 TokenTypes.COLON, // TODO: dont flag after "case"
114 TokenTypes.DIV,
115 TokenTypes.DIV_ASSIGN,
116 TokenTypes.EQUAL,
117 TokenTypes.GE,
118 TokenTypes.GT,
119 TokenTypes.LAND,
120 TokenTypes.LCURLY,
121 TokenTypes.LE,
122 TokenTypes.LITERAL_CATCH,
123 TokenTypes.LITERAL_DO,
124 TokenTypes.LITERAL_ELSE,
125 TokenTypes.LITERAL_FINALLY,
126 TokenTypes.LITERAL_FOR,
127 TokenTypes.LITERAL_IF,
128 TokenTypes.LITERAL_RETURN,
129 TokenTypes.LITERAL_SYNCHRONIZED,
130 TokenTypes.LITERAL_TRY,
131 TokenTypes.LITERAL_WHILE,
132 TokenTypes.LOR,
133 TokenTypes.LT,
134 TokenTypes.MINUS,
135 TokenTypes.MINUS_ASSIGN,
136 TokenTypes.MOD,
137 TokenTypes.MOD_ASSIGN,
138 TokenTypes.NOT_EQUAL,
139 TokenTypes.PLUS,
140 TokenTypes.PLUS_ASSIGN,
141 TokenTypes.QUESTION,
142 TokenTypes.RCURLY,
143 TokenTypes.SL,
144 TokenTypes.SLIST,
145 TokenTypes.SL_ASSIGN,
146 TokenTypes.SR,
147 TokenTypes.SR_ASSIGN,
148 TokenTypes.STAR,
149 TokenTypes.STAR_ASSIGN,
150 TokenTypes.LITERAL_ASSERT,
151 };
152 }
153
154 /** @see com.puppycrawl.tools.checkstyle.api.Check */
155 public void visitToken(DetailAST aAST)
156 {
157 final int type = aAST.getType();
158 final int parentType = aAST.getParent().getType();
159
160 // Check for CURLY in array initializer
161 if ((type == TokenTypes.RCURLY || type == TokenTypes.LCURLY)
162 && (parentType == TokenTypes.ARRAY_INIT))
163 {
164 return;
165 }
166
167 // Check for import pkg.name.*;
168 if ((type == TokenTypes.STAR)
169 && (parentType == TokenTypes.DOT))
170 {
171 return;
172 }
173
174 // Check for an SLIST that has a parent CASE_GROUP. It is not a '{'.
175 if ((type == TokenTypes.SLIST)
176 && (parentType == TokenTypes.CASE_GROUP))
177 {
178 return;
179 }
180
181 final String[] lines = getLines();
182 final String line = lines[aAST.getLineNo() - 1];
183 final int before = aAST.getColumnNo() - 1;
184 final int after = aAST.getColumnNo() + aAST.getText().length();
185
186 if ((before >= 0) && !Character.isWhitespace(line.charAt(before))) {
187 log(aAST.getLineNo(), aAST.getColumnNo(),
188 "ws.notPreceded", new Object[]{aAST.getText()});
189 }
190
191 if (after >= line.length()) {
192 return;
193 }
194
195 final char nextChar = line.charAt(after);
196 if (!Character.isWhitespace(nextChar)
197 // Check for "return;"
198 && !((type == TokenTypes.LITERAL_RETURN)
199 && (aAST.getFirstChild().getType() == TokenTypes.SEMI))
200 // Check for "})" or "};" or "},". Happens with anon-inners
201 && !((type == TokenTypes.RCURLY)
202 && ((nextChar == ')')
203 || (nextChar == ';')
204 || (nextChar == ','))))
205 {
206 log(
207 aAST.getLineNo(),
208 aAST.getColumnNo() + aAST.getText().length(),
209 "ws.notFollowed",
210 new Object[] {aAST.getText()});
211 }
212 }
213 }