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