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