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 * <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 /** 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 * <pre> public void myMethod(int val) {}</pre> 457 * In the above, the method body is an empty block ("{}"). 458 * 459 * @param ast the {@code DetailAST} to test. 460 * @param parentType the token type of {@code ast}'s parent. 461 * @param match the parent token type we're looking to match. 462 * @return {@code true} if {@code ast} makes up part of an 463 * empty block contained under a {@code match} token type 464 * node. 465 */ 466 private static boolean isEmptyBlock(DetailAST ast, int parentType, int match) { 467 final boolean result; 468 final int type = ast.getType(); 469 if (type == TokenTypes.RCURLY) { 470 final DetailAST parent = ast.getParent(); 471 final DetailAST grandParent = ast.getParent().getParent(); 472 result = parent.getFirstChild().getType() == TokenTypes.RCURLY 473 && grandParent.getType() == match; 474 } 475 else { 476 result = type == TokenTypes.SLIST 477 && parentType == match 478 && ast.getFirstChild().getType() == TokenTypes.RCURLY; 479 } 480 return result; 481 } 482 483 /** 484 * Test if the given {@code DetailAST} is part of an allowed empty 485 * method block. 486 * 487 * @param ast the {@code DetailAST} to test. 488 * @param parentType the token type of {@code ast}'s parent. 489 * @return {@code true} if {@code ast} makes up part of an 490 * allowed empty method block. 491 */ 492 private boolean isEmptyMethodBlock(DetailAST ast, int parentType) { 493 return allowEmptyMethods 494 && isEmptyBlock(ast, parentType, TokenTypes.METHOD_DEF); 495 } 496 497 /** 498 * Test if the given {@code DetailAST} is part of an allowed empty 499 * constructor (ctor) block checked from RCURLY. 500 * 501 * @param ast the {@code DetailAST} to test. 502 * @return {@code true} if {@code ast} makes up part of an 503 * allowed empty constructor block. 504 */ 505 private boolean isEmptyCtorBlockCheckedFromRcurly(DetailAST ast) { 506 final DetailAST parent = ast.getParent(); 507 final DetailAST grandParent = ast.getParent().getParent(); 508 return allowEmptyConstructors 509 && parent.getFirstChild().getType() == TokenTypes.RCURLY 510 && (grandParent.getType() == TokenTypes.CTOR_DEF 511 || grandParent.getType() == TokenTypes.COMPACT_CTOR_DEF); 512 513 } 514 515 /** 516 * Test if the given {@code DetailAST} is a part of an allowed 517 * empty constructor checked from SLIST token. 518 * 519 * @param ast the {@code DetailAST} to test. 520 * @return {@code true} if {@code ast} makes up part of an 521 * empty constructor block. 522 */ 523 private boolean isEmptyCtorBlockCheckedFromSlist(DetailAST ast) { 524 return allowEmptyConstructors 525 && (ast.getParent().getType() == TokenTypes.CTOR_DEF 526 || ast.getParent().getType() == TokenTypes.COMPACT_CTOR_DEF) 527 && ast.getFirstChild().getType() == TokenTypes.RCURLY; 528 } 529 530 /** 531 * Checks if loop is empty. 532 * 533 * @param ast ast the {@code DetailAST} to test. 534 * @param parentType the token type of {@code ast}'s parent. 535 * @return {@code true} if {@code ast} makes up part of an 536 * allowed empty loop block. 537 */ 538 private boolean isEmptyLoop(DetailAST ast, int parentType) { 539 return allowEmptyLoops 540 && (isEmptyBlock(ast, parentType, TokenTypes.LITERAL_FOR) 541 || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_WHILE) 542 || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_DO)); 543 } 544 545 /** 546 * Test if the given {@code DetailAST} is part of an allowed empty 547 * lambda block. 548 * 549 * @param ast the {@code DetailAST} to test. 550 * @param parentType the token type of {@code ast}'s parent. 551 * @return {@code true} if {@code ast} makes up part of an 552 * allowed empty lambda block. 553 */ 554 private boolean isEmptyLambda(DetailAST ast, int parentType) { 555 return allowEmptyLambdas && isEmptyBlock(ast, parentType, TokenTypes.LAMBDA); 556 } 557 558 /** 559 * Tests if the given {@code DetailAst} is part of an allowed empty 560 * catch block. 561 * 562 * @param ast the {@code DetailAst} to test. 563 * @param parentType the token type of {@code ast}'s parent 564 * @return {@code true} if {@code ast} makes up part of an 565 * allowed empty catch block. 566 */ 567 private boolean isEmptyCatch(DetailAST ast, int parentType) { 568 return allowEmptyCatches && isEmptyBlock(ast, parentType, TokenTypes.LITERAL_CATCH); 569 } 570 571 /** 572 * Tests if the given {@code DetailAst} is part of an allowed empty 573 * switch case or default block. 574 * 575 * @param ast the {@code DetailAst} to test. 576 * @return {@code true} if {@code ast} makes up part of an allowed 577 * empty switch case or default block. 578 */ 579 private boolean isEmptySwitchBlockStatement(DetailAST ast) { 580 final boolean isEmptySwitchBlockStatement; 581 582 if (allowEmptySwitchBlockStatements) { 583 final DetailAST parent = ast.getParent(); 584 final DetailAST grandParent = parent.getParent(); 585 586 final boolean isEmptyCaseInSwitchRule = 587 isEmptyBlock(ast, parent.getType(), TokenTypes.SWITCH_RULE); 588 589 final boolean isEmptyCaseGroupCheckedFromLcurly = 590 isEmptyBlock(ast, grandParent.getType(), TokenTypes.CASE_GROUP); 591 592 final boolean isEmptyCaseGroupCheckedFromRcurly = 593 parent.getFirstChild().getType() == TokenTypes.RCURLY 594 && grandParent.getParent().getType() == TokenTypes.CASE_GROUP; 595 596 isEmptySwitchBlockStatement = isEmptyCaseInSwitchRule 597 || isEmptyCaseGroupCheckedFromLcurly || isEmptyCaseGroupCheckedFromRcurly; 598 } 599 else { 600 isEmptySwitchBlockStatement = false; 601 } 602 603 return isEmptySwitchBlockStatement; 604 } 605 606 /** 607 * Test if the given {@code DetailAST} is part of an empty block. 608 * An example empty block might look like the following 609 * <pre> class Foo {}</pre> 610 * 611 * @param ast ast the {@code DetailAST} to test. 612 * @return {@code true} if {@code ast} makes up part of an 613 * empty block contained under a {@code match} token type 614 * node. 615 */ 616 private static boolean isEmptyType(DetailAST ast) { 617 final int type = ast.getType(); 618 final DetailAST nextSibling = ast.getNextSibling(); 619 final DetailAST previousSibling = ast.getPreviousSibling(); 620 return type == TokenTypes.LCURLY 621 && nextSibling.getType() == TokenTypes.RCURLY 622 || previousSibling != null 623 && previousSibling.getType() == TokenTypes.LCURLY; 624 } 625 626 /** 627 * Check if given ast is part of double brace initializer and if it 628 * should omit checking if previous token is separated by whitespace. 629 * 630 * @param ast ast to check 631 * @return true if it should omit checking for previous token, false otherwise 632 */ 633 private static boolean isPartOfDoubleBraceInitializerForPreviousToken(DetailAST ast) { 634 final boolean initializerBeginsAfterClassBegins = 635 ast.getParent().getType() == TokenTypes.INSTANCE_INIT; 636 final boolean classEndsAfterInitializerEnds = ast.getPreviousSibling() != null 637 && ast.getPreviousSibling().getType() == TokenTypes.INSTANCE_INIT; 638 return initializerBeginsAfterClassBegins || classEndsAfterInitializerEnds; 639 } 640 641 /** 642 * Check if given ast is part of double brace initializer and if it 643 * should omit checking if next token is separated by whitespace. 644 * See <a href="https://github.com/checkstyle/checkstyle/pull/2845"> 645 * PR#2845</a> for more information why this function was needed. 646 * 647 * @param ast ast to check 648 * @return true if it should omit checking for next token, false otherwise 649 */ 650 private static boolean isPartOfDoubleBraceInitializerForNextToken(DetailAST ast) { 651 final boolean classBeginBeforeInitializerBegin = ast.getType() == TokenTypes.LCURLY 652 && ast.getNextSibling().getType() == TokenTypes.INSTANCE_INIT; 653 final boolean initializerEndsBeforeClassEnds = 654 ast.getParent().getParent().getType() == TokenTypes.INSTANCE_INIT 655 && ast.getParent().getParent().getNextSibling().getType() == TokenTypes.RCURLY; 656 return classBeginBeforeInitializerBegin || initializerEndsBeforeClassEnds; 657 } 658 659}