001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 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 * <div> 030 * Checks that a token is surrounded by whitespace. Empty constructor, 031 * method, class, enum, interface, loop bodies (blocks), lambdas of the form 032 * </div> 033 * {@snippet lang="text" : 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 * } 046 * 047 * <p> 048 * may optionally be exempted from the policy using the {@code allowEmptyMethods}, 049 * {@code allowEmptyConstructors}, {@code allowEmptyTypes}, {@code allowEmptyLoops}, 050 * {@code allowEmptyLambdas}, {@code allowEmptyCatches} 051 * and {@code allowEmptySwitchBlockStatements} properties. 052 * </p> 053 * 054 * <p> 055 * This check does not flag as violation double brace initialization like: 056 * </p> 057 * {@snippet : 058 * new Properties() {{ 059 * setProperty("key", "value"); 060 * }}; 061 * } 062 * 063 * <p> 064 * Parameter allowEmptyCatches allows to suppress violations when token list 065 * contains SLIST to check if beginning of block is surrounded by whitespace 066 * and catch block is empty, for example: 067 * </p> 068 * {@snippet : 069 * try { 070 * k = 5 / i; 071 * } catch (ArithmeticException ex) {} 072 * } 073 * 074 * <p> 075 * With this property turned off, this raises violation because the beginning 076 * of the catch block (left curly bracket) is not separated from the end 077 * of the catch block (right curly bracket). 078 * </p> 079 * 080 * <p> 081 * Note: <a href="https://openjdk.org/jeps/361"> 082 * Switch expressions</a> are ignored by this check. 083 * </p> 084 * 085 * @since 3.0 086 */ 087@StatelessCheck 088public class WhitespaceAroundCheck extends AbstractCheck { 089 090 /** 091 * A key is pointing to the warning message text in "messages.properties" 092 * file. 093 */ 094 public static final String MSG_WS_NOT_PRECEDED = "ws.notPreceded"; 095 096 /** 097 * A key is pointing to the warning message text in "messages.properties" 098 * file. 099 */ 100 public static final String MSG_WS_NOT_FOLLOWED = "ws.notFollowed"; 101 102 /** Allow empty constructor bodies. */ 103 private boolean allowEmptyConstructors; 104 /** Allow empty method bodies. */ 105 private boolean allowEmptyMethods; 106 /** Allow empty class, interface and enum bodies. */ 107 private boolean allowEmptyTypes; 108 /** Allow empty loop bodies. */ 109 private boolean allowEmptyLoops; 110 /** Allow empty lambda bodies. */ 111 private boolean allowEmptyLambdas; 112 /** Allow empty catch bodies. */ 113 private boolean allowEmptyCatches; 114 /** Allow empty switch blocks and block statements. */ 115 private boolean allowEmptySwitchBlockStatements; 116 /** 117 * Ignore whitespace around colon in 118 * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-14.14.2"> 119 * enhanced for</a> loop. 120 */ 121 private boolean ignoreEnhancedForColon = true; 122 123 /** 124 * Creates a new {@code WhitespaceAroundCheck} instance. 125 */ 126 public WhitespaceAroundCheck() { 127 // no code by default 128 } 129 130 @Override 131 public int[] getDefaultTokens() { 132 return new int[] { 133 TokenTypes.ASSIGN, 134 TokenTypes.BAND, 135 TokenTypes.BAND_ASSIGN, 136 TokenTypes.BOR, 137 TokenTypes.BOR_ASSIGN, 138 TokenTypes.BSR, 139 TokenTypes.BSR_ASSIGN, 140 TokenTypes.BXOR, 141 TokenTypes.BXOR_ASSIGN, 142 TokenTypes.COLON, 143 TokenTypes.DIV, 144 TokenTypes.DIV_ASSIGN, 145 TokenTypes.DO_WHILE, 146 TokenTypes.EQUAL, 147 TokenTypes.GE, 148 TokenTypes.GT, 149 TokenTypes.LAMBDA, 150 TokenTypes.LAND, 151 TokenTypes.LCURLY, 152 TokenTypes.LE, 153 TokenTypes.LITERAL_CATCH, 154 TokenTypes.LITERAL_DO, 155 TokenTypes.LITERAL_ELSE, 156 TokenTypes.LITERAL_FINALLY, 157 TokenTypes.LITERAL_FOR, 158 TokenTypes.LITERAL_IF, 159 TokenTypes.LITERAL_RETURN, 160 TokenTypes.LITERAL_SWITCH, 161 TokenTypes.LITERAL_SYNCHRONIZED, 162 TokenTypes.LITERAL_TRY, 163 TokenTypes.LITERAL_WHILE, 164 TokenTypes.LOR, 165 TokenTypes.LT, 166 TokenTypes.MINUS, 167 TokenTypes.MINUS_ASSIGN, 168 TokenTypes.MOD, 169 TokenTypes.MOD_ASSIGN, 170 TokenTypes.NOT_EQUAL, 171 TokenTypes.PLUS, 172 TokenTypes.PLUS_ASSIGN, 173 TokenTypes.QUESTION, 174 TokenTypes.RCURLY, 175 TokenTypes.SL, 176 TokenTypes.SLIST, 177 TokenTypes.SL_ASSIGN, 178 TokenTypes.SR, 179 TokenTypes.SR_ASSIGN, 180 TokenTypes.STAR, 181 TokenTypes.STAR_ASSIGN, 182 TokenTypes.LITERAL_ASSERT, 183 TokenTypes.TYPE_EXTENSION_AND, 184 TokenTypes.LITERAL_WHEN, 185 }; 186 } 187 188 @Override 189 public int[] getAcceptableTokens() { 190 return new int[] { 191 TokenTypes.ASSIGN, 192 TokenTypes.ARRAY_INIT, 193 TokenTypes.BAND, 194 TokenTypes.BAND_ASSIGN, 195 TokenTypes.BOR, 196 TokenTypes.BOR_ASSIGN, 197 TokenTypes.BSR, 198 TokenTypes.BSR_ASSIGN, 199 TokenTypes.BXOR, 200 TokenTypes.BXOR_ASSIGN, 201 TokenTypes.COLON, 202 TokenTypes.DIV, 203 TokenTypes.DIV_ASSIGN, 204 TokenTypes.DO_WHILE, 205 TokenTypes.EQUAL, 206 TokenTypes.GE, 207 TokenTypes.GT, 208 TokenTypes.LAMBDA, 209 TokenTypes.LAND, 210 TokenTypes.LCURLY, 211 TokenTypes.LE, 212 TokenTypes.LITERAL_CATCH, 213 TokenTypes.LITERAL_DO, 214 TokenTypes.LITERAL_ELSE, 215 TokenTypes.LITERAL_FINALLY, 216 TokenTypes.LITERAL_FOR, 217 TokenTypes.LITERAL_IF, 218 TokenTypes.LITERAL_RETURN, 219 TokenTypes.LITERAL_SWITCH, 220 TokenTypes.LITERAL_SYNCHRONIZED, 221 TokenTypes.LITERAL_TRY, 222 TokenTypes.LITERAL_WHILE, 223 TokenTypes.LOR, 224 TokenTypes.LT, 225 TokenTypes.MINUS, 226 TokenTypes.MINUS_ASSIGN, 227 TokenTypes.MOD, 228 TokenTypes.MOD_ASSIGN, 229 TokenTypes.NOT_EQUAL, 230 TokenTypes.PLUS, 231 TokenTypes.PLUS_ASSIGN, 232 TokenTypes.QUESTION, 233 TokenTypes.RCURLY, 234 TokenTypes.SL, 235 TokenTypes.SLIST, 236 TokenTypes.SL_ASSIGN, 237 TokenTypes.SR, 238 TokenTypes.SR_ASSIGN, 239 TokenTypes.STAR, 240 TokenTypes.STAR_ASSIGN, 241 TokenTypes.LITERAL_ASSERT, 242 TokenTypes.TYPE_EXTENSION_AND, 243 TokenTypes.WILDCARD_TYPE, 244 TokenTypes.GENERIC_START, 245 TokenTypes.GENERIC_END, 246 TokenTypes.ELLIPSIS, 247 TokenTypes.LITERAL_WHEN, 248 }; 249 } 250 251 @Override 252 public int[] getRequiredTokens() { 253 return CommonUtil.EMPTY_INT_ARRAY; 254 } 255 256 /** 257 * Setter to allow empty method bodies. 258 * 259 * @param allow {@code true} to allow empty method bodies. 260 * @since 4.0 261 */ 262 public void setAllowEmptyMethods(boolean allow) { 263 allowEmptyMethods = allow; 264 } 265 266 /** 267 * Setter to allow empty constructor bodies. 268 * 269 * @param allow {@code true} to allow empty constructor bodies. 270 * @since 4.0 271 */ 272 public void setAllowEmptyConstructors(boolean allow) { 273 allowEmptyConstructors = allow; 274 } 275 276 /** 277 * Setter to ignore whitespace around colon in 278 * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-14.14.2"> 279 * enhanced for</a> loop. 280 * 281 * @param ignore {@code true} to ignore enhanced for colon. 282 * @since 5.5 283 */ 284 public void setIgnoreEnhancedForColon(boolean ignore) { 285 ignoreEnhancedForColon = ignore; 286 } 287 288 /** 289 * Setter to allow empty class, interface and enum bodies. 290 * 291 * @param allow {@code true} to allow empty type bodies. 292 * @since 5.8 293 */ 294 public void setAllowEmptyTypes(boolean allow) { 295 allowEmptyTypes = allow; 296 } 297 298 /** 299 * Setter to allow empty loop bodies. 300 * 301 * @param allow {@code true} to allow empty loops bodies. 302 * @since 5.8 303 */ 304 public void setAllowEmptyLoops(boolean allow) { 305 allowEmptyLoops = allow; 306 } 307 308 /** 309 * Setter to allow empty lambda bodies. 310 * 311 * @param allow {@code true} to allow empty lambda expressions. 312 * @since 6.14 313 */ 314 public void setAllowEmptyLambdas(boolean allow) { 315 allowEmptyLambdas = allow; 316 } 317 318 /** 319 * Setter to allow empty catch bodies. 320 * 321 * @param allow {@code true} to allow empty catch blocks. 322 * @since 7.6 323 */ 324 public void setAllowEmptyCatches(boolean allow) { 325 allowEmptyCatches = allow; 326 } 327 328 /** 329 * Setter to allow empty switch blocks and block statements. 330 * 331 * @param allow {@code true} to allow empty switch case and default blocks. 332 * @since 10.19.0 333 */ 334 public void setAllowEmptySwitchBlockStatements(boolean allow) { 335 allowEmptySwitchBlockStatements = allow; 336 } 337 338 @Override 339 public void visitToken(DetailAST ast) { 340 final int currentType = ast.getType(); 341 if (!isNotRelevantSituation(ast, currentType)) { 342 final int[] line = getLineCodePoints(ast.getLineNo() - 1); 343 final int before = ast.getColumnNo() - 1; 344 final int after = ast.getColumnNo() + ast.getText().length(); 345 346 if (before >= 0 && shouldCheckSeparationFromPreviousToken(ast) 347 && !CommonUtil.isCodePointWhitespace(line, before)) { 348 log(ast, MSG_WS_NOT_PRECEDED, ast.getText()); 349 } 350 351 if (after < line.length) { 352 final char nextChar = Character.toChars(line[after])[0]; 353 if (shouldCheckSeparationFromNextToken(ast, nextChar) 354 && !Character.isWhitespace(nextChar)) { 355 log(ast, MSG_WS_NOT_FOLLOWED, ast.getText()); 356 } 357 } 358 } 359 } 360 361 /** 362 * Is ast not a target of Check. 363 * 364 * @param ast ast 365 * @param currentType type of ast 366 * @return true is ok to skip validation 367 */ 368 private boolean isNotRelevantSituation(DetailAST ast, int currentType) { 369 final int parentType = ast.getParent().getType(); 370 return switch (parentType) { 371 case TokenTypes.DOT -> currentType == TokenTypes.STAR; 372 case TokenTypes.LITERAL_DEFAULT, TokenTypes.LITERAL_CASE, TokenTypes.CASE_GROUP -> true; 373 case TokenTypes.FOR_EACH_CLAUSE -> ignoreEnhancedForColon; 374 case TokenTypes.EXPR -> currentType == TokenTypes.LITERAL_SWITCH; 375 case TokenTypes.ARRAY_INIT, TokenTypes.ANNOTATION_ARRAY_INIT -> 376 currentType == TokenTypes.RCURLY; 377 default -> isEmptyBlock(ast, parentType) 378 || allowEmptyTypes && isEmptyType(ast); 379 }; 380 } 381 382 /** 383 * Check if it should be checked if previous token is separated from current by 384 * whitespace. 385 * This function is needed to recognise double brace initialization as valid, 386 * unfortunately it's not possible to implement this functionality 387 * in isNotRelevantSituation method, because in this method when we return 388 * true(is not relevant) ast is later doesn't check at all. For example: 389 * new Properties() {{setProperty("double curly braces", "are not a style violation"); 390 * }}; 391 * For second left curly brace in first line when we would return true from 392 * isNotRelevantSituation it wouldn't later check that the next token(setProperty) 393 * is not separated from previous token. 394 * 395 * @param ast current AST. 396 * @return true if it should be checked if previous token is separated by whitespace, 397 * false otherwise. 398 */ 399 private static boolean shouldCheckSeparationFromPreviousToken(DetailAST ast) { 400 return !isPartOfDoubleBraceInitializerForPreviousToken(ast); 401 } 402 403 /** 404 * Check if it should be checked if next token is separated from current by 405 * whitespace. Explanation why this method is needed is identical to one 406 * included in shouldCheckSeparationFromPreviousToken method. 407 * 408 * @param ast current AST. 409 * @param nextChar next character. 410 * @return true if it should be checked if next token is separated by whitespace, 411 * false otherwise. 412 */ 413 private boolean shouldCheckSeparationFromNextToken(DetailAST ast, char nextChar) { 414 return !isEmptyCtorBlockCheckedFromSlist(ast) 415 && !(ast.getType() == TokenTypes.LITERAL_RETURN 416 && ast.getFirstChild().getType() == TokenTypes.SEMI) 417 && ast.getType() != TokenTypes.ARRAY_INIT 418 && !isAnonymousInnerClassEnd(ast.getType(), nextChar) 419 && !isPartOfDoubleBraceInitializerForNextToken(ast); 420 } 421 422 /** 423 * Check for "})" or "};" or "},". Happens with anon-inners 424 * 425 * @param currentType token 426 * @param nextChar next symbol 427 * @return true is that is end of anon inner class 428 */ 429 private static boolean isAnonymousInnerClassEnd(int currentType, char nextChar) { 430 return currentType == TokenTypes.RCURLY 431 && (nextChar == ')' 432 || nextChar == ';' 433 || nextChar == ',' 434 || nextChar == '.'); 435 } 436 437 /** 438 * Is empty block. 439 * 440 * @param ast ast 441 * @param parentType parent 442 * @return true is block is empty 443 */ 444 private boolean isEmptyBlock(DetailAST ast, int parentType) { 445 return isEmptyMethodBlock(ast, parentType) 446 || isEmptyCtorBlockCheckedFromRcurly(ast) 447 || isEmptyLoop(ast, parentType) 448 || isEmptyLambda(ast, parentType) 449 || isEmptyCatch(ast, parentType) 450 || isEmptySwitchBlockStatement(ast); 451 } 452 453 /** 454 * Tests if a given {@code DetailAST} is part of an empty block. 455 * An example empty block might look like the following 456 * <br> 457 * {@code public void myMethod(int val) {}} 458 * <br> 459 * In the above, the method body is an empty block ("{}"). 460 * 461 * @param ast the {@code DetailAST} to test. 462 * @param parentType the token type of {@code ast}'s parent. 463 * @param match the parent token type we're looking to match. 464 * @return {@code true} if {@code ast} makes up part of an 465 * empty block contained under a {@code match} token type 466 * node. 467 */ 468 private static boolean isEmptyBlock(DetailAST ast, int parentType, int match) { 469 final boolean result; 470 final int type = ast.getType(); 471 if (type == TokenTypes.RCURLY) { 472 final DetailAST parent = ast.getParent(); 473 final DetailAST grandParent = ast.getParent().getParent(); 474 result = parent.getFirstChild().getType() == TokenTypes.RCURLY 475 && grandParent.getType() == match; 476 } 477 else { 478 result = type == TokenTypes.SLIST 479 && parentType == match 480 && ast.getFirstChild().getType() == TokenTypes.RCURLY; 481 } 482 return result; 483 } 484 485 /** 486 * Test if the given {@code DetailAST} is part of an allowed empty 487 * method block. 488 * 489 * @param ast the {@code DetailAST} to test. 490 * @param parentType the token type of {@code ast}'s parent. 491 * @return {@code true} if {@code ast} makes up part of an 492 * allowed empty method block. 493 */ 494 private boolean isEmptyMethodBlock(DetailAST ast, int parentType) { 495 return allowEmptyMethods 496 && isEmptyBlock(ast, parentType, TokenTypes.METHOD_DEF); 497 } 498 499 /** 500 * Test if the given {@code DetailAST} is part of an allowed empty 501 * constructor (ctor) block checked from RCURLY. 502 * 503 * @param ast the {@code DetailAST} to test. 504 * @return {@code true} if {@code ast} makes up part of an 505 * allowed empty constructor block. 506 */ 507 private boolean isEmptyCtorBlockCheckedFromRcurly(DetailAST ast) { 508 final DetailAST parent = ast.getParent(); 509 final DetailAST grandParent = ast.getParent().getParent(); 510 return allowEmptyConstructors 511 && parent.getFirstChild().getType() == TokenTypes.RCURLY 512 && (grandParent.getType() == TokenTypes.CTOR_DEF 513 || grandParent.getType() == TokenTypes.COMPACT_CTOR_DEF); 514 515 } 516 517 /** 518 * Test if the given {@code DetailAST} is a part of an allowed 519 * empty constructor checked from SLIST token. 520 * 521 * @param ast the {@code DetailAST} to test. 522 * @return {@code true} if {@code ast} makes up part of an 523 * empty constructor block. 524 */ 525 private boolean isEmptyCtorBlockCheckedFromSlist(DetailAST ast) { 526 return allowEmptyConstructors 527 && (ast.getParent().getType() == TokenTypes.CTOR_DEF 528 || ast.getParent().getType() == TokenTypes.COMPACT_CTOR_DEF) 529 && ast.getFirstChild().getType() == TokenTypes.RCURLY; 530 } 531 532 /** 533 * Checks if loop is empty. 534 * 535 * @param ast ast the {@code DetailAST} to test. 536 * @param parentType the token type of {@code ast}'s parent. 537 * @return {@code true} if {@code ast} makes up part of an 538 * allowed empty loop block. 539 */ 540 private boolean isEmptyLoop(DetailAST ast, int parentType) { 541 return allowEmptyLoops 542 && (isEmptyBlock(ast, parentType, TokenTypes.LITERAL_FOR) 543 || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_WHILE) 544 || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_DO)); 545 } 546 547 /** 548 * Test if the given {@code DetailAST} is part of an allowed empty 549 * lambda block. 550 * 551 * @param ast the {@code DetailAST} to test. 552 * @param parentType the token type of {@code ast}'s parent. 553 * @return {@code true} if {@code ast} makes up part of an 554 * allowed empty lambda block. 555 */ 556 private boolean isEmptyLambda(DetailAST ast, int parentType) { 557 return allowEmptyLambdas && isEmptyBlock(ast, parentType, TokenTypes.LAMBDA); 558 } 559 560 /** 561 * Tests if the given {@code DetailAst} is part of an allowed empty 562 * catch block. 563 * 564 * @param ast the {@code DetailAst} to test. 565 * @param parentType the token type of {@code ast}'s parent 566 * @return {@code true} if {@code ast} makes up part of an 567 * allowed empty catch block. 568 */ 569 private boolean isEmptyCatch(DetailAST ast, int parentType) { 570 return allowEmptyCatches && isEmptyBlock(ast, parentType, TokenTypes.LITERAL_CATCH); 571 } 572 573 /** 574 * Tests if the given {@code DetailAst} is part of an allowed empty 575 * switch case or default block. 576 * 577 * @param ast the {@code DetailAst} to test. 578 * @return {@code true} if {@code ast} makes up part of an allowed 579 * empty switch case or default block. 580 */ 581 private boolean isEmptySwitchBlockStatement(DetailAST ast) { 582 final boolean isEmptySwitchBlockStatement; 583 584 if (allowEmptySwitchBlockStatements) { 585 final DetailAST parent = ast.getParent(); 586 final DetailAST grandParent = parent.getParent(); 587 588 final boolean isEmptyCaseInSwitchRule = 589 isEmptyBlock(ast, parent.getType(), TokenTypes.SWITCH_RULE); 590 591 final boolean isEmptyCaseGroupCheckedFromLcurly = 592 isEmptyBlock(ast, grandParent.getType(), TokenTypes.CASE_GROUP); 593 594 final boolean isEmptyCaseGroupCheckedFromRcurly = 595 parent.getFirstChild().getType() == TokenTypes.RCURLY 596 && grandParent.getParent().getType() == TokenTypes.CASE_GROUP; 597 598 isEmptySwitchBlockStatement = isEmptyCaseInSwitchRule 599 || isEmptyCaseGroupCheckedFromLcurly || isEmptyCaseGroupCheckedFromRcurly; 600 } 601 else { 602 isEmptySwitchBlockStatement = false; 603 } 604 605 return isEmptySwitchBlockStatement; 606 } 607 608 /** 609 * Test if the given {@code DetailAST} is part of an empty block. 610 * An example empty block might look like {@code class Foo {}} 611 * 612 * @param ast ast the {@code DetailAST} to test. 613 * @return {@code true} if {@code ast} makes up part of an 614 * empty block contained under a {@code match} token type 615 * node. 616 */ 617 private static boolean isEmptyType(DetailAST ast) { 618 final int type = ast.getType(); 619 final DetailAST nextSibling = ast.getNextSibling(); 620 final DetailAST previousSibling = ast.getPreviousSibling(); 621 return type == TokenTypes.LCURLY 622 && nextSibling.getType() == TokenTypes.RCURLY 623 || previousSibling != null 624 && previousSibling.getType() == TokenTypes.LCURLY; 625 } 626 627 /** 628 * Check if given ast is part of double brace initializer and if it 629 * should omit checking if previous token is separated by whitespace. 630 * 631 * @param ast ast to check 632 * @return true if it should omit checking for previous token, false otherwise 633 */ 634 private static boolean isPartOfDoubleBraceInitializerForPreviousToken(DetailAST ast) { 635 final boolean initializerBeginsAfterClassBegins = 636 ast.getParent().getType() == TokenTypes.INSTANCE_INIT; 637 final boolean classEndsAfterInitializerEnds = ast.getPreviousSibling() != null 638 && ast.getPreviousSibling().getType() == TokenTypes.INSTANCE_INIT; 639 return initializerBeginsAfterClassBegins || classEndsAfterInitializerEnds; 640 } 641 642 /** 643 * Check if given ast is part of double brace initializer and if it 644 * should omit checking if next token is separated by whitespace. 645 * See <a href="https://github.com/checkstyle/checkstyle/pull/2845"> 646 * PR#2845</a> for more information why this function was needed. 647 * 648 * @param ast ast to check 649 * @return true if it should omit checking for next token, false otherwise 650 */ 651 private static boolean isPartOfDoubleBraceInitializerForNextToken(DetailAST ast) { 652 final boolean classBeginBeforeInitializerBegin = ast.getType() == TokenTypes.LCURLY 653 && ast.getNextSibling().getType() == TokenTypes.INSTANCE_INIT; 654 final boolean initializerEndsBeforeClassEnds = 655 ast.getParent().getParent().getType() == TokenTypes.INSTANCE_INIT 656 && ast.getParent().getParent().getNextSibling().getType() == TokenTypes.RCURLY; 657 return classBeginBeforeInitializerBegin || initializerEndsBeforeClassEnds; 658 } 659 660}