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