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 * 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 * <module name="WhitespaceAround"/> 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 > 1; i++) {} // violation, '{' is not followed by whitespace. 240 * 241 * Runnable noop = () ->{}; // 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 * <module name="WhitespaceAround"> 260 * <property name="tokens" 261 * value="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"/> 264 * </module> 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>>=1; // violation 284 * c >>= 1; // ok 285 * c>>>=1; // violation 286 * c >>>= 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&=1; // violation 294 * c &= 1; // ok 295 * c<<=1; // violation 296 * c <<= 1; // ok 297 * } 298 * } 299 * </pre> 300 * <p>To configure the check for whitespace only around curly braces: 301 * </p> 302 * <pre> 303 * <module name="WhitespaceAround"> 304 * <property name="tokens" value="LCURLY,RCURLY"/> 305 * </module> 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 * <module name="WhitespaceAround"> 320 * <property name="allowEmptyMethods" value="true"/> 321 * </module> 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 * <module name="WhitespaceAround"> 336 * <property name="allowEmptyConstructors" value="true"/> 337 * </module> 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 * <module name="WhitespaceAround"> 352 * <property name="allowEmptyTypes" value="true"/> 353 * </module> 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 * <module name="WhitespaceAround"> 369 * <property name="allowEmptyLoops" value="true"/> 370 * </module> 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 > 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 * <module name="WhitespaceAround"> 388 * <property name="allowEmptyLambdas" value="true"/> 389 * </module> 390 * </pre> 391 * <p>Example: 392 * </p> 393 * <pre> 394 * class Test { 395 * public static void main(String[] args) { 396 * Runnable noop = () -> {}; // 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 * <module name="WhitespaceAround"> 406 * <property name="allowEmptyCatches" value="true"/> 407 * </module> 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 * <module name="WhitespaceAround"> 430 * <property name="ignoreEnhancedForColon" value="false" /> 431 * </module> 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}