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