001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2020 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.whitespace;
021
022import com.puppycrawl.tools.checkstyle.StatelessCheck;
023import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
024import com.puppycrawl.tools.checkstyle.api.DetailAST;
025import com.puppycrawl.tools.checkstyle.api.TokenTypes;
026import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
027
028/**
029 * <p>
030 * Checks that a token is surrounded by whitespace. Empty constructor,
031 * method, class, enum, interface, loop bodies (blocks), lambdas of the form
032 * </p>
033 * <pre>
034 * public MyClass() {}      // empty constructor
035 * public void func() {}    // empty method
036 * public interface Foo {} // empty interface
037 * public class Foo {} // empty class
038 * public enum Foo {} // empty enum
039 * MyClass c = new MyClass() {}; // empty anonymous class
040 * while (i = 1) {} // empty while loop
041 * for (int i = 1; i &gt; 1; i++) {} // empty for loop
042 * do {} while (i = 1); // empty do-while loop
043 * Runnable noop = () -&gt; {}; // empty lambda
044 * public @interface Beta {} // empty annotation type
045 * </pre>
046 * <p>
047 * may optionally be exempted from the policy using the {@code allowEmptyMethods},
048 * {@code allowEmptyConstructors}, {@code allowEmptyTypes}, {@code allowEmptyLoops},
049 * {@code allowEmptyLambdas} and {@code allowEmptyCatches} properties.
050 * </p>
051 * <p>
052 * This check does not flag as violation double brace initialization like:
053 * </p>
054 * <pre>
055 * new Properties() {{
056 *     setProperty("key", "value");
057 * }};
058 * </pre>
059 * <p>
060 * Parameter allowEmptyCatches allows to suppress violations when token list
061 * contains SLIST to check if beginning of block is surrounded by whitespace
062 * and catch block is empty, for example:
063 * </p>
064 * <pre>
065 * try {
066 *     k = 5 / i;
067 * } catch (ArithmeticException ex) {}
068 * </pre>
069 * <p>
070 * With this property turned off, this raises violation because the beginning
071 * of the catch block (left curly bracket) is not separated from the end
072 * of the catch block (right curly bracket).
073 * </p>
074 * <ul>
075 * <li>
076 * Property {@code allowEmptyConstructors} - Allow empty constructor bodies.
077 * Default value is {@code false}.
078 * </li>
079 * <li>
080 * Property {@code allowEmptyMethods} - Allow empty method bodies.
081 * Default value is {@code false}.
082 * </li>
083 * <li>
084 * Property {@code allowEmptyTypes} - Allow empty class, interface and enum bodies.
085 * Default value is {@code false}.
086 * </li>
087 * <li>
088 * Property {@code allowEmptyLoops} - Allow empty loop bodies.
089 * Default value is {@code false}.
090 * </li>
091 * <li>
092 * Property {@code allowEmptyLambdas} - Allow empty lambda bodies.
093 * Default value is {@code false}.
094 * </li>
095 * <li>
096 * Property {@code allowEmptyCatches} - Allow empty catch bodies.
097 * Default value is {@code false}.
098 * </li>
099 * <li>
100 * Property {@code ignoreEnhancedForColon} - Ignore whitespace around colon in
101 * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-14.14.2">
102 * enhanced for</a> loop.
103 * Default value is {@code true}.
104 * </li>
105 * <li>
106 * Property {@code tokens} - tokens to check Default value is:
107 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ASSIGN">
108 * ASSIGN</a>,
109 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BAND">
110 * BAND</a>,
111 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BAND_ASSIGN">
112 * BAND_ASSIGN</a>,
113 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BOR">
114 * BOR</a>,
115 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BOR_ASSIGN">
116 * BOR_ASSIGN</a>,
117 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BSR">
118 * BSR</a>,
119 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BSR_ASSIGN">
120 * BSR_ASSIGN</a>,
121 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BXOR">
122 * BXOR</a>,
123 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BXOR_ASSIGN">
124 * BXOR_ASSIGN</a>,
125 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COLON">
126 * COLON</a>,
127 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#DIV">
128 * DIV</a>,
129 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#DIV_ASSIGN">
130 * DIV_ASSIGN</a>,
131 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#DO_WHILE">
132 * DO_WHILE</a>,
133 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#EQUAL">
134 * EQUAL</a>,
135 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#GE">
136 * GE</a>,
137 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#GT">
138 * GT</a>,
139 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAMBDA">
140 * LAMBDA</a>,
141 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAND">
142 * LAND</a>,
143 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LCURLY">
144 * LCURLY</a>,
145 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LE">
146 * LE</a>,
147 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_CATCH">
148 * LITERAL_CATCH</a>,
149 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_DO">
150 * LITERAL_DO</a>,
151 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_ELSE">
152 * LITERAL_ELSE</a>,
153 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_FINALLY">
154 * LITERAL_FINALLY</a>,
155 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_FOR">
156 * LITERAL_FOR</a>,
157 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_IF">
158 * LITERAL_IF</a>,
159 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_RETURN">
160 * LITERAL_RETURN</a>,
161 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_SWITCH">
162 * LITERAL_SWITCH</a>,
163 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_SYNCHRONIZED">
164 * LITERAL_SYNCHRONIZED</a>,
165 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_TRY">
166 * LITERAL_TRY</a>,
167 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_WHILE">
168 * LITERAL_WHILE</a>,
169 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LOR">
170 * LOR</a>,
171 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LT">
172 * LT</a>,
173 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#MINUS">
174 * MINUS</a>,
175 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#MINUS_ASSIGN">
176 * MINUS_ASSIGN</a>,
177 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#MOD">
178 * MOD</a>,
179 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#MOD_ASSIGN">
180 * MOD_ASSIGN</a>,
181 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#NOT_EQUAL">
182 * NOT_EQUAL</a>,
183 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PLUS">
184 * PLUS</a>,
185 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PLUS_ASSIGN">
186 * PLUS_ASSIGN</a>,
187 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#QUESTION">
188 * QUESTION</a>,
189 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RCURLY">
190 * RCURLY</a>,
191 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SL">
192 * SL</a>,
193 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SLIST">
194 * SLIST</a>,
195 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SL_ASSIGN">
196 * SL_ASSIGN</a>,
197 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SR">
198 * SR</a>,
199 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SR_ASSIGN">
200 * SR_ASSIGN</a>,
201 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR">
202 * STAR</a>,
203 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR_ASSIGN">
204 * STAR_ASSIGN</a>,
205 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_ASSERT">
206 * LITERAL_ASSERT</a>,
207 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#TYPE_EXTENSION_AND">
208 * TYPE_EXTENSION_AND</a>.
209 * </li>
210 * </ul>
211 * <p>To configure the check:
212 * </p>
213 * <pre>
214 * &lt;module name=&quot;WhitespaceAround&quot;/&gt;
215 * </pre>
216 * <p>Example:
217 * </p>
218 * <pre>
219 * class Test {
220 *     public Test(){} // 2 violations, '{' is not followed and preceded by whitespace.
221 *     public static void main(String[] args) {
222 *         if (foo) { // ok
223 *             // body
224 *         }
225 *         else{ // violation
226 *             // body
227 *         }
228 *
229 *         for (int i = 1; i &gt; 1; i++) {} // violation, '{' is not followed by whitespace.
230 *
231 *         Runnable noop = () -&gt;{}; // 2 violations,
232 *                                     // '{' is not followed and preceded by whitespace.
233 *         try {
234 *             // body
235 *         } catch (Exception e){} // 2 violations,
236 *                                 // '{' is not followed and preceded by whitespace.
237 *
238 *         char[] vowels = {'a', 'e', 'i', 'o', 'u'};
239 *         for (char item: vowels) { // ok, because ignoreEnhancedForColon is true by default
240 *             // body
241 *         }
242 *     }
243 * }
244 * </pre>
245 * <p>To configure the check for whitespace only around
246 * assignment operators:
247 * </p>
248 * <pre>
249 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
250 *   &lt;property name=&quot;tokens&quot;
251 *     value=&quot;ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,
252 *            MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,
253 *            BOR_ASSIGN,BAND_ASSIGN&quot;/&gt;
254 * &lt;/module&gt;
255 * </pre>
256 * <p>Example:
257 * </p>
258 * <pre>
259 * class Test {
260 *     public static void main(String[] args) {
261 *         int b=10; // violation
262 *         int c = 10; // ok
263 *         b+=10; // violation
264 *         b += 10; // ok
265 *         c*=10; // violation
266 *         c *= 10; // ok
267 *         c-=5; // violation
268 *         c -= 5; // ok
269 *         c/=2; // violation
270 *         c /= 2; // ok
271 *         c%=1; // violation
272 *         c %= 1; // ok
273 *         c&gt;&gt;=1; // violation
274 *         c &gt;&gt;= 1; // ok
275 *         c&gt;&gt;&gt;=1; // violation
276 *         c &gt;&gt;&gt;= 1; // ok
277 *     }
278 *     public void myFunction() {
279 *         c^=1; // violation
280 *         c ^= 1; // ok
281 *         c|=1; // violation
282 *         c |= 1; // ok
283 *         c&amp;=1; // violation
284 *         c &amp;= 1; // ok
285 *         c&lt;&lt;=1; // violation
286 *         c &lt;&lt;= 1; // ok
287 *     }
288 * }
289 * </pre>
290 * <p>To configure the check for whitespace only around curly braces:
291 * </p>
292 * <pre>
293 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
294 *   &lt;property name=&quot;tokens&quot; value=&quot;LCURLY,RCURLY&quot;/&gt;
295 * &lt;/module&gt;
296 * </pre>
297 * <p>Example:
298 * </p>
299 * <pre>
300 * class Test {
301 *     public void myFunction() {} // violation
302 *     public void myFunction() { } // ok
303 * }
304 * </pre>
305 * <p>
306 * To configure the check to allow empty method bodies:
307 * </p>
308 * <pre>
309 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
310 *   &lt;property name=&quot;allowEmptyMethods&quot; value=&quot;true&quot;/&gt;
311 * &lt;/module&gt;
312 * </pre>
313 * <p>Example:
314 * </p>
315 * <pre>
316 * class Test {
317 *     public void muFunction() {} // ok
318 *     int a=4; // 2 violations, '=' is not followed and preceded by whitespace.
319 * }
320 * </pre>
321 * <p>
322 * To configure the check to allow empty constructor bodies:
323 * </p>
324 * <pre>
325 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
326 *   &lt;property name=&quot;allowEmptyConstructors&quot; value=&quot;true&quot;/&gt;
327 * &lt;/module&gt;
328 * </pre>
329 * <p>Example:
330 * </p>
331 * <pre>
332 * class Test {
333 *     public Test(){} // ok
334 *     public void muFunction() {} // violation, '{' is not followed by whitespace.
335 * }
336 * </pre>
337 * <p>
338 * To configure the check to allow empty type bodies:
339 * </p>
340 * <pre>
341 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
342 *   &lt;property name=&quot;allowEmptyTypes&quot; value=&quot;true&quot;/&gt;
343 * &lt;/module&gt;
344 * </pre>
345 * <p>Example:
346 * </p>
347 * <pre>
348 * class Test {} // ok
349 * interface testInterface{} // ok
350 * class anotherTest {
351 *     int a=4; // 2 violations, '=' is not followed and preceded by whitespace.
352 * }
353 * </pre>
354 * <p>
355 * To configure the check to allow empty loop bodies:
356 * </p>
357 * <pre>
358 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
359 *   &lt;property name=&quot;allowEmptyLoops&quot; value=&quot;true&quot;/&gt;
360 * &lt;/module&gt;
361 * </pre>
362 * <p>Example:
363 * </p>
364 * <pre>
365 * class Test {
366 *     public static void main(String[] args) {
367 *         for (int i = 100;i &gt; 10; i--){} // ok
368 *         do {} while (i = 1); // ok
369 *         int a=4; // 2 violations, '=' is not followed and preceded by whitespace.
370 *     }
371 * }
372 * </pre>
373 * <p>
374 * To configure the check to allow empty lambda bodies:
375 * </p>
376 * <pre>
377 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
378 *   &lt;property name=&quot;allowEmptyLambdas&quot; value=&quot;true&quot;/&gt;
379 * &lt;/module&gt;
380 * </pre>
381 * <p>Example:
382 * </p>
383 * <pre>
384 * class Test {
385 *     public static void main(String[] args) {
386 *         Runnable noop = () -&gt; {}; // ok
387 *         int a=4; // 2 violations, '=' is not followed and preceded by whitespace.
388 *     }
389 * }
390 * </pre>
391 * <p>
392 * To configure the check to allow empty catch bodies:
393 * </p>
394 * <pre>
395 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
396 *   &lt;property name=&quot;allowEmptyCatches&quot; value=&quot;true&quot;/&gt;
397 * &lt;/module&gt;
398 * </pre>
399 * <p>Example:
400 * </p>
401 * <pre>
402 * class Test {
403 *     public static void main(String[] args) {
404 *         int a=4; // 2 violations, '=' is not followed and preceded by whitespace.
405 *         try {
406 *             // body
407 *         } catch (Exception e){} // ok
408 *     }
409 * }
410 * </pre>
411 * <p>
412 * Also, this check can be configured to ignore the colon in an enhanced for
413 * loop. The colon in an enhanced for loop is ignored by default.
414 * </p>
415 * <p>
416 * To configure the check to ignore the colon:
417 * </p>
418 * <pre>
419 * &lt;module name=&quot;WhitespaceAround&quot;&gt;
420 *   &lt;property name=&quot;ignoreEnhancedForColon&quot; value=&quot;false&quot; /&gt;
421 * &lt;/module&gt;
422 * </pre>
423 * <p>Example:
424 * </p>
425 * <pre>
426 * class Test {
427 *     public static void main(String[] args) {
428 *         int a=4; // 2 violations , '=' is not followed and preceded by whitespace.
429 *         char[] vowels = {'a', 'e', 'i', 'o', 'u'};
430 *         for (char item: vowels) { // violation, ':' is not preceded by whitespace.
431 *             // body
432 *         }
433 *     }
434 * }
435 * </pre>
436 *
437 * @since 3.0
438 */
439@StatelessCheck
440public class WhitespaceAroundCheck extends AbstractCheck {
441
442    /**
443     * A key is pointing to the warning message text in "messages.properties"
444     * file.
445     */
446    public static final String MSG_WS_NOT_PRECEDED = "ws.notPreceded";
447
448    /**
449     * A key is pointing to the warning message text in "messages.properties"
450     * file.
451     */
452    public static final String MSG_WS_NOT_FOLLOWED = "ws.notFollowed";
453
454    /** Allow empty constructor bodies. */
455    private boolean allowEmptyConstructors;
456    /** Allow empty method bodies. */
457    private boolean allowEmptyMethods;
458    /** Allow empty class, interface and enum bodies. */
459    private boolean allowEmptyTypes;
460    /** Allow empty loop bodies. */
461    private boolean allowEmptyLoops;
462    /** Allow empty lambda bodies. */
463    private boolean allowEmptyLambdas;
464    /** Allow empty catch bodies. */
465    private boolean allowEmptyCatches;
466    /**
467     * Ignore whitespace around colon in
468     * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-14.14.2">
469     * enhanced for</a> loop.
470     */
471    private boolean ignoreEnhancedForColon = true;
472
473    @Override
474    public int[] getDefaultTokens() {
475        return new int[] {
476            TokenTypes.ASSIGN,
477            TokenTypes.BAND,
478            TokenTypes.BAND_ASSIGN,
479            TokenTypes.BOR,
480            TokenTypes.BOR_ASSIGN,
481            TokenTypes.BSR,
482            TokenTypes.BSR_ASSIGN,
483            TokenTypes.BXOR,
484            TokenTypes.BXOR_ASSIGN,
485            TokenTypes.COLON,
486            TokenTypes.DIV,
487            TokenTypes.DIV_ASSIGN,
488            TokenTypes.DO_WHILE,
489            TokenTypes.EQUAL,
490            TokenTypes.GE,
491            TokenTypes.GT,
492            TokenTypes.LAMBDA,
493            TokenTypes.LAND,
494            TokenTypes.LCURLY,
495            TokenTypes.LE,
496            TokenTypes.LITERAL_CATCH,
497            TokenTypes.LITERAL_DO,
498            TokenTypes.LITERAL_ELSE,
499            TokenTypes.LITERAL_FINALLY,
500            TokenTypes.LITERAL_FOR,
501            TokenTypes.LITERAL_IF,
502            TokenTypes.LITERAL_RETURN,
503            TokenTypes.LITERAL_SWITCH,
504            TokenTypes.LITERAL_SYNCHRONIZED,
505            TokenTypes.LITERAL_TRY,
506            TokenTypes.LITERAL_WHILE,
507            TokenTypes.LOR,
508            TokenTypes.LT,
509            TokenTypes.MINUS,
510            TokenTypes.MINUS_ASSIGN,
511            TokenTypes.MOD,
512            TokenTypes.MOD_ASSIGN,
513            TokenTypes.NOT_EQUAL,
514            TokenTypes.PLUS,
515            TokenTypes.PLUS_ASSIGN,
516            TokenTypes.QUESTION,
517            TokenTypes.RCURLY,
518            TokenTypes.SL,
519            TokenTypes.SLIST,
520            TokenTypes.SL_ASSIGN,
521            TokenTypes.SR,
522            TokenTypes.SR_ASSIGN,
523            TokenTypes.STAR,
524            TokenTypes.STAR_ASSIGN,
525            TokenTypes.LITERAL_ASSERT,
526            TokenTypes.TYPE_EXTENSION_AND,
527        };
528    }
529
530    @Override
531    public int[] getAcceptableTokens() {
532        return new int[] {
533            TokenTypes.ASSIGN,
534            TokenTypes.ARRAY_INIT,
535            TokenTypes.BAND,
536            TokenTypes.BAND_ASSIGN,
537            TokenTypes.BOR,
538            TokenTypes.BOR_ASSIGN,
539            TokenTypes.BSR,
540            TokenTypes.BSR_ASSIGN,
541            TokenTypes.BXOR,
542            TokenTypes.BXOR_ASSIGN,
543            TokenTypes.COLON,
544            TokenTypes.DIV,
545            TokenTypes.DIV_ASSIGN,
546            TokenTypes.DO_WHILE,
547            TokenTypes.EQUAL,
548            TokenTypes.GE,
549            TokenTypes.GT,
550            TokenTypes.LAMBDA,
551            TokenTypes.LAND,
552            TokenTypes.LCURLY,
553            TokenTypes.LE,
554            TokenTypes.LITERAL_CATCH,
555            TokenTypes.LITERAL_DO,
556            TokenTypes.LITERAL_ELSE,
557            TokenTypes.LITERAL_FINALLY,
558            TokenTypes.LITERAL_FOR,
559            TokenTypes.LITERAL_IF,
560            TokenTypes.LITERAL_RETURN,
561            TokenTypes.LITERAL_SWITCH,
562            TokenTypes.LITERAL_SYNCHRONIZED,
563            TokenTypes.LITERAL_TRY,
564            TokenTypes.LITERAL_WHILE,
565            TokenTypes.LOR,
566            TokenTypes.LT,
567            TokenTypes.MINUS,
568            TokenTypes.MINUS_ASSIGN,
569            TokenTypes.MOD,
570            TokenTypes.MOD_ASSIGN,
571            TokenTypes.NOT_EQUAL,
572            TokenTypes.PLUS,
573            TokenTypes.PLUS_ASSIGN,
574            TokenTypes.QUESTION,
575            TokenTypes.RCURLY,
576            TokenTypes.SL,
577            TokenTypes.SLIST,
578            TokenTypes.SL_ASSIGN,
579            TokenTypes.SR,
580            TokenTypes.SR_ASSIGN,
581            TokenTypes.STAR,
582            TokenTypes.STAR_ASSIGN,
583            TokenTypes.LITERAL_ASSERT,
584            TokenTypes.TYPE_EXTENSION_AND,
585            TokenTypes.WILDCARD_TYPE,
586            TokenTypes.GENERIC_START,
587            TokenTypes.GENERIC_END,
588            TokenTypes.ELLIPSIS,
589        };
590    }
591
592    @Override
593    public int[] getRequiredTokens() {
594        return CommonUtil.EMPTY_INT_ARRAY;
595    }
596
597    /**
598     * Setter to allow empty method bodies.
599     *
600     * @param allow {@code true} to allow empty method bodies.
601     */
602    public void setAllowEmptyMethods(boolean allow) {
603        allowEmptyMethods = allow;
604    }
605
606    /**
607     * Setter to allow empty constructor bodies.
608     *
609     * @param allow {@code true} to allow empty constructor bodies.
610     */
611    public void setAllowEmptyConstructors(boolean allow) {
612        allowEmptyConstructors = allow;
613    }
614
615    /**
616     * Setter to ignore whitespace around colon in
617     * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-14.14.2">
618     * enhanced for</a> loop.
619     *
620     * @param ignore {@code true} to ignore enhanced for colon.
621     */
622    public void setIgnoreEnhancedForColon(boolean ignore) {
623        ignoreEnhancedForColon = ignore;
624    }
625
626    /**
627     * Setter to allow empty class, interface and enum bodies.
628     *
629     * @param allow {@code true} to allow empty type bodies.
630     */
631    public void setAllowEmptyTypes(boolean allow) {
632        allowEmptyTypes = allow;
633    }
634
635    /**
636     * Setter to allow empty loop bodies.
637     *
638     * @param allow {@code true} to allow empty loops bodies.
639     */
640    public void setAllowEmptyLoops(boolean allow) {
641        allowEmptyLoops = allow;
642    }
643
644    /**
645     * Setter to allow empty lambda bodies.
646     *
647     * @param allow {@code true} to allow empty lambda expressions.
648     */
649    public void setAllowEmptyLambdas(boolean allow) {
650        allowEmptyLambdas = allow;
651    }
652
653    /**
654     * Setter to allow empty catch bodies.
655     *
656     * @param allow {@code true} to allow empty catch blocks.
657     */
658    public void setAllowEmptyCatches(boolean allow) {
659        allowEmptyCatches = allow;
660    }
661
662    @Override
663    public void visitToken(DetailAST ast) {
664        final int currentType = ast.getType();
665        if (!isNotRelevantSituation(ast, currentType)) {
666            final String line = getLine(ast.getLineNo() - 1);
667            final int before = ast.getColumnNo() - 1;
668            final int after = ast.getColumnNo() + ast.getText().length();
669
670            if (before >= 0) {
671                final char prevChar = line.charAt(before);
672                if (shouldCheckSeparationFromPreviousToken(ast)
673                        && !Character.isWhitespace(prevChar)) {
674                    log(ast, MSG_WS_NOT_PRECEDED, ast.getText());
675                }
676            }
677
678            if (after < line.length()) {
679                final char nextChar = line.charAt(after);
680                if (shouldCheckSeparationFromNextToken(ast, nextChar)
681                        && !Character.isWhitespace(nextChar)) {
682                    log(ast, MSG_WS_NOT_FOLLOWED, ast.getText());
683                }
684            }
685        }
686    }
687
688    /**
689     * Is ast not a target of Check.
690     *
691     * @param ast ast
692     * @param currentType type of ast
693     * @return true is ok to skip validation
694     */
695    private boolean isNotRelevantSituation(DetailAST ast, int currentType) {
696        final int parentType = ast.getParent().getType();
697        final boolean starImport = currentType == TokenTypes.STAR
698                && parentType == TokenTypes.DOT;
699        final boolean insideCaseGroup = parentType == TokenTypes.CASE_GROUP;
700
701        final boolean starImportOrSlistInsideCaseGroup = starImport || insideCaseGroup;
702        final boolean colonOfCaseOrDefaultOrForEach =
703                isColonOfCaseOrDefault(parentType)
704                        || isColonOfForEach(parentType);
705        final boolean emptyBlockOrType =
706                isEmptyBlock(ast, parentType)
707                    || allowEmptyTypes && isEmptyType(ast);
708
709        return starImportOrSlistInsideCaseGroup
710                || colonOfCaseOrDefaultOrForEach
711                || emptyBlockOrType
712                || isArrayInitialization(currentType, parentType);
713    }
714
715    /**
716     * Check if it should be checked if previous token is separated from current by
717     * whitespace.
718     * This function is needed to recognise double brace initialization as valid,
719     * unfortunately its not possible to implement this functionality
720     * in isNotRelevantSituation method, because in this method when we return
721     * true(is not relevant) ast is later doesn't check at all. For example:
722     * new Properties() {{setProperty("double curly braces", "are not a style violation");
723     * }};
724     * For second left curly brace in first line when we would return true from
725     * isNotRelevantSituation it wouldn't later check that the next token(setProperty)
726     * is not separated from previous token.
727     *
728     * @param ast current AST.
729     * @return true if it should be checked if previous token is separated by whitespace,
730     *      false otherwise.
731     */
732    private static boolean shouldCheckSeparationFromPreviousToken(DetailAST ast) {
733        return !isPartOfDoubleBraceInitializerForPreviousToken(ast);
734    }
735
736    /**
737     * Check if it should be checked if next token is separated from current by
738     * whitespace. Explanation why this method is needed is identical to one
739     * included in shouldCheckSeparationFromPreviousToken method.
740     *
741     * @param ast current AST.
742     * @param nextChar next character.
743     * @return true if it should be checked if next token is separated by whitespace,
744     *      false otherwise.
745     */
746    private static boolean shouldCheckSeparationFromNextToken(DetailAST ast, char nextChar) {
747        return !(ast.getType() == TokenTypes.LITERAL_RETURN
748                    && ast.getFirstChild().getType() == TokenTypes.SEMI)
749                && ast.getType() != TokenTypes.ARRAY_INIT
750                && !isAnonymousInnerClassEnd(ast.getType(), nextChar)
751                && !isPartOfDoubleBraceInitializerForNextToken(ast);
752    }
753
754    /**
755     * Check for "})" or "};" or "},". Happens with anon-inners
756     *
757     * @param currentType token
758     * @param nextChar next symbol
759     * @return true is that is end of anon inner class
760     */
761    private static boolean isAnonymousInnerClassEnd(int currentType, char nextChar) {
762        return currentType == TokenTypes.RCURLY
763                && (nextChar == ')'
764                        || nextChar == ';'
765                        || nextChar == ','
766                        || nextChar == '.');
767    }
768
769    /**
770     * Is empty block.
771     *
772     * @param ast ast
773     * @param parentType parent
774     * @return true is block is empty
775     */
776    private boolean isEmptyBlock(DetailAST ast, int parentType) {
777        return isEmptyMethodBlock(ast, parentType)
778                || isEmptyCtorBlock(ast, parentType)
779                || isEmptyLoop(ast, parentType)
780                || isEmptyLambda(ast, parentType)
781                || isEmptyCatch(ast, parentType);
782    }
783
784    /**
785     * Tests if a given {@code DetailAST} is part of an empty block.
786     * An example empty block might look like the following
787     * <p>
788     * <pre>   public void myMethod(int val) {}</pre>
789     * </p>
790     * In the above, the method body is an empty block ("{}").
791     *
792     * @param ast the {@code DetailAST} to test.
793     * @param parentType the token type of {@code ast}'s parent.
794     * @param match the parent token type we're looking to match.
795     * @return {@code true} if {@code ast} makes up part of an
796     *         empty block contained under a {@code match} token type
797     *         node.
798     */
799    private static boolean isEmptyBlock(DetailAST ast, int parentType, int match) {
800        final boolean result;
801        final int type = ast.getType();
802        if (type == TokenTypes.RCURLY) {
803            final DetailAST parent = ast.getParent();
804            final DetailAST grandParent = ast.getParent().getParent();
805            result = parent.getFirstChild().getType() == TokenTypes.RCURLY
806                    && grandParent.getType() == match;
807        }
808        else {
809            result = type == TokenTypes.SLIST
810                && parentType == match
811                && ast.getFirstChild().getType() == TokenTypes.RCURLY;
812        }
813        return result;
814    }
815
816    /**
817     * Whether colon belongs to cases or defaults.
818     *
819     * @param parentType parent
820     * @return true if current token in colon of case or default tokens
821     */
822    private static boolean isColonOfCaseOrDefault(int parentType) {
823        return parentType == TokenTypes.LITERAL_DEFAULT
824                    || parentType == TokenTypes.LITERAL_CASE;
825    }
826
827    /**
828     * Whether colon belongs to for-each.
829     *
830     * @param parentType parent
831     * @return true if current token in colon of for-each token
832     */
833    private boolean isColonOfForEach(int parentType) {
834        return parentType == TokenTypes.FOR_EACH_CLAUSE
835                && ignoreEnhancedForColon;
836    }
837
838    /**
839     * Is array initialization.
840     *
841     * @param currentType current token
842     * @param parentType parent token
843     * @return true is current token inside array initialization
844     */
845    private static boolean isArrayInitialization(int currentType, int parentType) {
846        return currentType == TokenTypes.RCURLY
847                && (parentType == TokenTypes.ARRAY_INIT
848                        || parentType == TokenTypes.ANNOTATION_ARRAY_INIT);
849    }
850
851    /**
852     * Test if the given {@code DetailAST} is part of an allowed empty
853     * method block.
854     *
855     * @param ast the {@code DetailAST} to test.
856     * @param parentType the token type of {@code ast}'s parent.
857     * @return {@code true} if {@code ast} makes up part of an
858     *         allowed empty method block.
859     */
860    private boolean isEmptyMethodBlock(DetailAST ast, int parentType) {
861        return allowEmptyMethods
862                && isEmptyBlock(ast, parentType, TokenTypes.METHOD_DEF);
863    }
864
865    /**
866     * Test if the given {@code DetailAST} is part of an allowed empty
867     * constructor (ctor) block.
868     *
869     * @param ast the {@code DetailAST} to test.
870     * @param parentType the token type of {@code ast}'s parent.
871     * @return {@code true} if {@code ast} makes up part of an
872     *         allowed empty constructor block.
873     */
874    private boolean isEmptyCtorBlock(DetailAST ast, int parentType) {
875        return allowEmptyConstructors
876                && isEmptyBlock(ast, parentType, TokenTypes.CTOR_DEF);
877    }
878
879    /**
880     * Checks if loop is empty.
881     *
882     * @param ast ast the {@code DetailAST} to test.
883     * @param parentType the token type of {@code ast}'s parent.
884     * @return {@code true} if {@code ast} makes up part of an
885     *         allowed empty loop block.
886     */
887    private boolean isEmptyLoop(DetailAST ast, int parentType) {
888        return allowEmptyLoops
889                && (isEmptyBlock(ast, parentType, TokenTypes.LITERAL_FOR)
890                        || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_WHILE)
891                        || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_DO));
892    }
893
894    /**
895     * Test if the given {@code DetailAST} is part of an allowed empty
896     * lambda block.
897     *
898     * @param ast the {@code DetailAST} to test.
899     * @param parentType the token type of {@code ast}'s parent.
900     * @return {@code true} if {@code ast} makes up part of an
901     *         allowed empty lambda block.
902     */
903    private boolean isEmptyLambda(DetailAST ast, int parentType) {
904        return allowEmptyLambdas && isEmptyBlock(ast, parentType, TokenTypes.LAMBDA);
905    }
906
907    /**
908     * Tests if the given {@code DetailAst} is part of an allowed empty
909     * catch block.
910     *
911     * @param ast the {@code DetailAst} to test.
912     * @param parentType the token type of {@code ast}'s parent
913     * @return {@code true} if {@code ast} makes up part of an
914     *         allowed empty catch block.
915     */
916    private boolean isEmptyCatch(DetailAST ast, int parentType) {
917        return allowEmptyCatches && isEmptyBlock(ast, parentType, TokenTypes.LITERAL_CATCH);
918    }
919
920    /**
921     * Test if the given {@code DetailAST} is part of an empty block.
922     * An example empty block might look like the following
923     * <p>
924     * <pre>   class Foo {}</pre>
925     * </p>
926     *
927     * @param ast ast the {@code DetailAST} to test.
928     * @return {@code true} if {@code ast} makes up part of an
929     *         empty block contained under a {@code match} token type
930     *         node.
931     */
932    private static boolean isEmptyType(DetailAST ast) {
933        final int type = ast.getType();
934        final DetailAST nextSibling = ast.getNextSibling();
935        final DetailAST previousSibling = ast.getPreviousSibling();
936        return type == TokenTypes.LCURLY
937                    && nextSibling.getType() == TokenTypes.RCURLY
938                || previousSibling != null
939                    && previousSibling.getType() == TokenTypes.LCURLY;
940    }
941
942    /**
943     * Check if given ast is part of double brace initializer and if it
944     * should omit checking if previous token is separated by whitespace.
945     *
946     * @param ast ast to check
947     * @return true if it should omit checking for previous token, false otherwise
948     */
949    private static boolean isPartOfDoubleBraceInitializerForPreviousToken(DetailAST ast) {
950        final boolean initializerBeginsAfterClassBegins =
951                ast.getParent().getType() == TokenTypes.INSTANCE_INIT;
952        final boolean classEndsAfterInitializerEnds = ast.getPreviousSibling() != null
953                && ast.getPreviousSibling().getType() == TokenTypes.INSTANCE_INIT;
954        return initializerBeginsAfterClassBegins || classEndsAfterInitializerEnds;
955    }
956
957    /**
958     * Check if given ast is part of double brace initializer and if it
959     * should omit checking if next token is separated by whitespace.
960     * See <a href="https://github.com/checkstyle/checkstyle/pull/2845">
961     * PR#2845</a> for more information why this function was needed.
962     *
963     * @param ast ast to check
964     * @return true if it should omit checking for next token, false otherwise
965     */
966    private static boolean isPartOfDoubleBraceInitializerForNextToken(DetailAST ast) {
967        final boolean classBeginBeforeInitializerBegin = ast.getType() == TokenTypes.LCURLY
968            && ast.getNextSibling().getType() == TokenTypes.INSTANCE_INIT;
969        final boolean initializerEndsBeforeClassEnds =
970            ast.getParent().getParent().getType() == TokenTypes.INSTANCE_INIT
971            && ast.getParent().getParent().getNextSibling().getType() == TokenTypes.RCURLY;
972        return classBeginBeforeInitializerBegin || initializerEndsBeforeClassEnds;
973    }
974
975}