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 > 1; i++) {} // empty for loop 042 * do {} while (i = 1); // empty do-while loop 043 * Runnable noop = () -> {}; // 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 * <module name="WhitespaceAround"/> 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 > 1; i++) {} // violation, '{' is not followed by whitespace. 230 * 231 * Runnable noop = () ->{}; // 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 * <module name="WhitespaceAround"> 250 * <property name="tokens" 251 * value="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"/> 254 * </module> 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>>=1; // violation 274 * c >>= 1; // ok 275 * c>>>=1; // violation 276 * c >>>= 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&=1; // violation 284 * c &= 1; // ok 285 * c<<=1; // violation 286 * c <<= 1; // ok 287 * } 288 * } 289 * </pre> 290 * <p>To configure the check for whitespace only around curly braces: 291 * </p> 292 * <pre> 293 * <module name="WhitespaceAround"> 294 * <property name="tokens" value="LCURLY,RCURLY"/> 295 * </module> 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 * <module name="WhitespaceAround"> 310 * <property name="allowEmptyMethods" value="true"/> 311 * </module> 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 * <module name="WhitespaceAround"> 326 * <property name="allowEmptyConstructors" value="true"/> 327 * </module> 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 * <module name="WhitespaceAround"> 342 * <property name="allowEmptyTypes" value="true"/> 343 * </module> 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 * <module name="WhitespaceAround"> 359 * <property name="allowEmptyLoops" value="true"/> 360 * </module> 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 > 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 * <module name="WhitespaceAround"> 378 * <property name="allowEmptyLambdas" value="true"/> 379 * </module> 380 * </pre> 381 * <p>Example: 382 * </p> 383 * <pre> 384 * class Test { 385 * public static void main(String[] args) { 386 * Runnable noop = () -> {}; // 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 * <module name="WhitespaceAround"> 396 * <property name="allowEmptyCatches" value="true"/> 397 * </module> 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 * <module name="WhitespaceAround"> 420 * <property name="ignoreEnhancedForColon" value="false" /> 421 * </module> 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}