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