001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2022 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.blocks; 021 022import java.util.Optional; 023 024import com.puppycrawl.tools.checkstyle.StatelessCheck; 025import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 026import com.puppycrawl.tools.checkstyle.api.DetailAST; 027import com.puppycrawl.tools.checkstyle.api.TokenTypes; 028import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 029import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 030 031/** 032 * <p> 033 * Checks for braces around code blocks. 034 * </p> 035 * <ul> 036 * <li> 037 * Property {@code allowSingleLineStatement} - allow single-line statements without braces. 038 * Type is {@code boolean}. 039 * Default value is {@code false}. 040 * </li> 041 * <li> 042 * Property {@code allowEmptyLoopBody} - allow loops with empty bodies. 043 * Type is {@code boolean}. 044 * Default value is {@code false}. 045 * </li> 046 * <li> 047 * Property {@code tokens} - tokens to check 048 * Type is {@code java.lang.String[]}. 049 * Validation type is {@code tokenSet}. 050 * Default value is: 051 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_DO"> 052 * LITERAL_DO</a>, 053 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_ELSE"> 054 * LITERAL_ELSE</a>, 055 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_FOR"> 056 * LITERAL_FOR</a>, 057 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_IF"> 058 * LITERAL_IF</a>, 059 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_WHILE"> 060 * LITERAL_WHILE</a>. 061 * </li> 062 * </ul> 063 * <p> 064 * To configure the check: 065 * </p> 066 * <pre> 067 * <module name="NeedBraces"/> 068 * </pre> 069 * <p>Example:</p> 070 * <pre> 071 * if (obj.isValid()) return true; // violation, single-line statements not allowed without braces 072 * if (true) { // OK 073 * return true; 074 * } else // violation, single-line statements not allowed without braces 075 * return false; 076 * for (int i = 0; i < 5; i++) { // OK 077 * ++count; 078 * } 079 * do // violation, single-line statements not allowed without braces 080 * ++count; 081 * while (false); 082 * for (int j = 0; j < 10; j++); // violation, empty loop body not allowed 083 * for(int i = 0; i < 10; value.incrementValue()); // violation, empty loop body not allowed 084 * while (counter < 10) // violation, single-line statements not allowed without braces 085 * ++count; 086 * while (value.incrementValue() < 5); // violation, empty loop body not allowed 087 * switch (num) { 088 * case 1: counter++; break; // OK 089 * } 090 * </pre> 091 * <p> 092 * To configure the check for {@code if} and {@code else} blocks: 093 * </p> 094 * <pre> 095 * <module name="NeedBraces"> 096 * <property name="tokens" value="LITERAL_IF, LITERAL_ELSE"/> 097 * </module> 098 * </pre> 099 * <p>Example:</p> 100 * <pre> 101 * if (obj.isValid()) return true; // violation, single-line statements not allowed without braces 102 * if (true) { // OK 103 * return true; 104 * } else // violation, single-line statements not allowed without braces 105 * return false; 106 * for (int i = 0; i < 5; i++) { // OK 107 * ++count; 108 * } 109 * do // OK 110 * ++count; 111 * while (false); 112 * for (int j = 0; j < 10; j++); // OK 113 * for(int i = 0; i < 10; value.incrementValue()); // OK 114 * while (counter < 10) // OK 115 * ++count; 116 * while (value.incrementValue() < 5); // OK 117 * switch (num) { 118 * case 1: counter++; break; // OK 119 * } 120 * </pre> 121 * <p> 122 * To configure the check to allow single-line statements 123 * ({@code if, while, do-while, for}) without braces: 124 * </p> 125 * <pre> 126 * <module name="NeedBraces"> 127 * <property name="allowSingleLineStatement" value="true"/> 128 * <property name="tokens" 129 * value="LITERAL_IF, LITERAL_WHILE, LITERAL_DO, LITERAL_FOR"/> 130 * </module> 131 * </pre> 132 * <p> 133 * Example: 134 * </p> 135 * <pre> 136 * if (obj.isValid()) return true; // OK 137 * if (true) { // OK 138 * return true; 139 * } else // OK 140 * return false; 141 * for (int i = 0; i < 5; i++) { // OK 142 * ++count; 143 * } 144 * do // OK 145 * ++count; 146 * while (false); 147 * for (int j = 0; j < 10; j++); // violation, empty loop body not allowed 148 * for(int i = 0; i < 10; value.incrementValue()); // violation, empty loop body not allowed 149 * while (counter < 10) // OK 150 * ++count; 151 * while (value.incrementValue() < 5); // violation, empty loop body not allowed 152 * switch (num) { 153 * case 1: counter++; break; // OK 154 * } 155 * while (obj.isValid()) return true; // OK 156 * do this.notify(); while (o != null); // OK 157 * for (int i = 0; ; ) this.notify(); // OK 158 * </pre> 159 * <p> 160 * To configure the check to allow {@code case, default} single-line statements without braces: 161 * </p> 162 * <pre> 163 * <module name="NeedBraces"> 164 * <property name="tokens" value="LITERAL_CASE, LITERAL_DEFAULT"/> 165 * <property name="allowSingleLineStatement" value="true"/> 166 * </module> 167 * </pre> 168 * <p> 169 * Next statements won't be violated by check: 170 * </p> 171 * <pre> 172 * if (obj.isValid()) return true; // OK 173 * if (true) { // OK 174 * return true; 175 * } else // OK 176 * return false; 177 * for (int i = 0; i < 5; i++) { // OK 178 * ++count; 179 * } 180 * do // OK 181 * ++count; 182 * while (false); 183 * for (int j = 0; j < 10; j++); // OK 184 * for(int i = 0; i < 10; value.incrementValue()); // OK 185 * while (counter < 10) // OK 186 * ++count; 187 * while (value.incrementValue() < 5); // OK 188 * switch (num) { 189 * case 1: counter++; break; // OK 190 * case 6: counter += 10; break; // OK 191 * default: counter = 100; break; // OK 192 * } 193 * </pre> 194 * <p> 195 * To configure the check to allow loops ({@code while, for}) with empty bodies: 196 * </p> 197 * <pre> 198 * <module name="NeedBraces"> 199 * <property name="allowEmptyLoopBody" value="true"/> 200 * <property name="tokens" value="LITERAL_WHILE, LITERAL_FOR"/> 201 * </module> 202 * </pre> 203 * <p> 204 * Example: 205 * </p> 206 * <pre> 207 * if (obj.isValid()) return true; // OK 208 * if (true) { // OK 209 * return true; 210 * } else // OK 211 * return false; 212 * for (int i = 0; i < 5; i++) { // OK 213 * ++count; 214 * } 215 * do // OK 216 * ++count; 217 * while (false); 218 * for (int j = 0; j < 10; j++); // OK 219 * for(int i = 0; i < 10; value.incrementValue()); // OK 220 * while (counter < 10) // violation, single-line statements not allowed without braces 221 * ++count; 222 * while (value.incrementValue() < 5); // OK 223 * switch (num) { 224 * case 1: counter++; break; // OK 225 * } 226 * </pre> 227 * <p> 228 * To configure the check to lambdas: 229 * </p> 230 * <pre> 231 * <module name="NeedBraces"> 232 * <property name="tokens" value="LAMBDA"/> 233 * <property name="allowSingleLineStatement" value="true"/> 234 * </module> 235 * </pre> 236 * <p> 237 * Results in following: 238 * </p> 239 * <pre> 240 * allowedFuture.addCallback(result -> assertEquals("Invalid response", 241 * EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS), result), // violation, lambda spans 2 lines 242 * ex -> fail(ex.getMessage())); // OK 243 * 244 * allowedFuture.addCallback(result -> { 245 * return assertEquals("Invalid response", 246 * EnumSet.of(HttpMethod.GET, HttpMethod.OPTIONS), result); 247 * }, // OK 248 * ex -> fail(ex.getMessage())); 249 * </pre> 250 * <p> 251 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 252 * </p> 253 * <p> 254 * Violation Message Keys: 255 * </p> 256 * <ul> 257 * <li> 258 * {@code needBraces} 259 * </li> 260 * </ul> 261 * 262 * @since 3.0 263 */ 264@StatelessCheck 265public class NeedBracesCheck extends AbstractCheck { 266 267 /** 268 * A key is pointing to the warning message text in "messages.properties" 269 * file. 270 */ 271 public static final String MSG_KEY_NEED_BRACES = "needBraces"; 272 273 /** 274 * Allow single-line statements without braces. 275 */ 276 private boolean allowSingleLineStatement; 277 278 /** 279 * Allow loops with empty bodies. 280 */ 281 private boolean allowEmptyLoopBody; 282 283 /** 284 * Setter to allow single-line statements without braces. 285 * 286 * @param allowSingleLineStatement Check's option for skipping single-line statements 287 */ 288 public void setAllowSingleLineStatement(boolean allowSingleLineStatement) { 289 this.allowSingleLineStatement = allowSingleLineStatement; 290 } 291 292 /** 293 * Setter to allow loops with empty bodies. 294 * 295 * @param allowEmptyLoopBody Check's option for allowing loops with empty body. 296 */ 297 public void setAllowEmptyLoopBody(boolean allowEmptyLoopBody) { 298 this.allowEmptyLoopBody = allowEmptyLoopBody; 299 } 300 301 @Override 302 public int[] getDefaultTokens() { 303 return new int[] { 304 TokenTypes.LITERAL_DO, 305 TokenTypes.LITERAL_ELSE, 306 TokenTypes.LITERAL_FOR, 307 TokenTypes.LITERAL_IF, 308 TokenTypes.LITERAL_WHILE, 309 }; 310 } 311 312 @Override 313 public int[] getAcceptableTokens() { 314 return new int[] { 315 TokenTypes.LITERAL_DO, 316 TokenTypes.LITERAL_ELSE, 317 TokenTypes.LITERAL_FOR, 318 TokenTypes.LITERAL_IF, 319 TokenTypes.LITERAL_WHILE, 320 TokenTypes.LITERAL_CASE, 321 TokenTypes.LITERAL_DEFAULT, 322 TokenTypes.LAMBDA, 323 }; 324 } 325 326 @Override 327 public int[] getRequiredTokens() { 328 return CommonUtil.EMPTY_INT_ARRAY; 329 } 330 331 @Override 332 public void visitToken(DetailAST ast) { 333 final boolean hasNoSlist = ast.findFirstToken(TokenTypes.SLIST) == null; 334 if (hasNoSlist && !isSkipStatement(ast) && isBracesNeeded(ast)) { 335 log(ast, MSG_KEY_NEED_BRACES, ast.getText()); 336 } 337 } 338 339 /** 340 * Checks if token needs braces. 341 * Some tokens have additional conditions: 342 * <ul> 343 * <li>{@link TokenTypes#LITERAL_FOR}</li> 344 * <li>{@link TokenTypes#LITERAL_WHILE}</li> 345 * <li>{@link TokenTypes#LITERAL_CASE}</li> 346 * <li>{@link TokenTypes#LITERAL_DEFAULT}</li> 347 * <li>{@link TokenTypes#LITERAL_ELSE}</li> 348 * <li>{@link TokenTypes#LAMBDA}</li> 349 * </ul> 350 * For all others default value {@code true} is returned. 351 * 352 * @param ast token to check 353 * @return result of additional checks for specific token types, 354 * {@code true} if there is no additional checks for token 355 */ 356 private boolean isBracesNeeded(DetailAST ast) { 357 final boolean result; 358 switch (ast.getType()) { 359 case TokenTypes.LITERAL_FOR: 360 case TokenTypes.LITERAL_WHILE: 361 result = !isEmptyLoopBodyAllowed(ast); 362 break; 363 case TokenTypes.LITERAL_CASE: 364 case TokenTypes.LITERAL_DEFAULT: 365 result = hasUnbracedStatements(ast) 366 && !isSwitchLabeledExpression(ast); 367 break; 368 case TokenTypes.LITERAL_ELSE: 369 result = ast.findFirstToken(TokenTypes.LITERAL_IF) == null; 370 break; 371 case TokenTypes.LAMBDA: 372 result = !isInSwitchRule(ast); 373 break; 374 default: 375 result = true; 376 break; 377 } 378 return result; 379 } 380 381 /** 382 * Checks if current loop has empty body and can be skipped by this check. 383 * 384 * @param ast for, while statements. 385 * @return true if current loop can be skipped by check. 386 */ 387 private boolean isEmptyLoopBodyAllowed(DetailAST ast) { 388 return allowEmptyLoopBody && ast.findFirstToken(TokenTypes.EMPTY_STAT) != null; 389 } 390 391 /** 392 * Checks if switch member (case, default statements) has statements without curly braces. 393 * 394 * @param ast case, default statements. 395 * @return true if switch member has unbraced statements, false otherwise. 396 */ 397 private static boolean hasUnbracedStatements(DetailAST ast) { 398 final DetailAST nextSibling = ast.getNextSibling(); 399 boolean result = false; 400 401 if (isInSwitchRule(ast)) { 402 final DetailAST parent = ast.getParent(); 403 result = parent.getLastChild().getType() != TokenTypes.SLIST; 404 } 405 else if (nextSibling != null 406 && nextSibling.getType() == TokenTypes.SLIST 407 && nextSibling.getFirstChild().getType() != TokenTypes.SLIST) { 408 result = true; 409 } 410 return result; 411 } 412 413 /** 414 * Checks if current statement can be skipped by "need braces" warning. 415 * 416 * @param statement if, for, while, do-while, lambda, else, case, default statements. 417 * @return true if current statement can be skipped by Check. 418 */ 419 private boolean isSkipStatement(DetailAST statement) { 420 return allowSingleLineStatement && isSingleLineStatement(statement); 421 } 422 423 /** 424 * Checks if current statement is single-line statement, e.g.: 425 * <p> 426 * {@code 427 * if (obj.isValid()) return true; 428 * } 429 * </p> 430 * <p> 431 * {@code 432 * while (obj.isValid()) return true; 433 * } 434 * </p> 435 * 436 * @param statement if, for, while, do-while, lambda, else, case, default statements. 437 * @return true if current statement is single-line statement. 438 */ 439 private static boolean isSingleLineStatement(DetailAST statement) { 440 final boolean result; 441 442 switch (statement.getType()) { 443 case TokenTypes.LITERAL_IF: 444 result = isSingleLineIf(statement); 445 break; 446 case TokenTypes.LITERAL_FOR: 447 result = isSingleLineFor(statement); 448 break; 449 case TokenTypes.LITERAL_DO: 450 result = isSingleLineDoWhile(statement); 451 break; 452 case TokenTypes.LITERAL_WHILE: 453 result = isSingleLineWhile(statement); 454 break; 455 case TokenTypes.LAMBDA: 456 result = !isInSwitchRule(statement) 457 && isSingleLineLambda(statement); 458 break; 459 case TokenTypes.LITERAL_CASE: 460 case TokenTypes.LITERAL_DEFAULT: 461 result = isSingleLineSwitchMember(statement); 462 break; 463 default: 464 result = isSingleLineElse(statement); 465 break; 466 } 467 468 return result; 469 } 470 471 /** 472 * Checks if current while statement is single-line statement, e.g.: 473 * <p> 474 * {@code 475 * while (obj.isValid()) return true; 476 * } 477 * </p> 478 * 479 * @param literalWhile {@link TokenTypes#LITERAL_WHILE while statement}. 480 * @return true if current while statement is single-line statement. 481 */ 482 private static boolean isSingleLineWhile(DetailAST literalWhile) { 483 boolean result = false; 484 if (literalWhile.getParent().getType() == TokenTypes.SLIST) { 485 final DetailAST block = literalWhile.getLastChild().getPreviousSibling(); 486 result = TokenUtil.areOnSameLine(literalWhile, block); 487 } 488 return result; 489 } 490 491 /** 492 * Checks if current do-while statement is single-line statement, e.g.: 493 * <p> 494 * {@code 495 * do this.notify(); while (o != null); 496 * } 497 * </p> 498 * 499 * @param literalDo {@link TokenTypes#LITERAL_DO do-while statement}. 500 * @return true if current do-while statement is single-line statement. 501 */ 502 private static boolean isSingleLineDoWhile(DetailAST literalDo) { 503 boolean result = false; 504 if (literalDo.getParent().getType() == TokenTypes.SLIST) { 505 final DetailAST block = literalDo.getFirstChild(); 506 result = TokenUtil.areOnSameLine(block, literalDo); 507 } 508 return result; 509 } 510 511 /** 512 * Checks if current for statement is single-line statement, e.g.: 513 * <p> 514 * {@code 515 * for (int i = 0; ; ) this.notify(); 516 * } 517 * </p> 518 * 519 * @param literalFor {@link TokenTypes#LITERAL_FOR for statement}. 520 * @return true if current for statement is single-line statement. 521 */ 522 private static boolean isSingleLineFor(DetailAST literalFor) { 523 boolean result = false; 524 if (literalFor.getLastChild().getType() == TokenTypes.EMPTY_STAT) { 525 result = true; 526 } 527 else if (literalFor.getParent().getType() == TokenTypes.SLIST) { 528 result = TokenUtil.areOnSameLine(literalFor, literalFor.getLastChild()); 529 } 530 return result; 531 } 532 533 /** 534 * Checks if current if statement is single-line statement, e.g.: 535 * <p> 536 * {@code 537 * if (obj.isValid()) return true; 538 * } 539 * </p> 540 * 541 * @param literalIf {@link TokenTypes#LITERAL_IF if statement}. 542 * @return true if current if statement is single-line statement. 543 */ 544 private static boolean isSingleLineIf(DetailAST literalIf) { 545 boolean result = false; 546 if (literalIf.getParent().getType() == TokenTypes.SLIST) { 547 final DetailAST literalIfLastChild = literalIf.getLastChild(); 548 final DetailAST block; 549 if (literalIfLastChild.getType() == TokenTypes.LITERAL_ELSE) { 550 block = literalIfLastChild.getPreviousSibling(); 551 } 552 else { 553 block = literalIfLastChild; 554 } 555 final DetailAST ifCondition = literalIf.findFirstToken(TokenTypes.EXPR); 556 result = TokenUtil.areOnSameLine(ifCondition, block); 557 } 558 return result; 559 } 560 561 /** 562 * Checks if current lambda statement is single-line statement, e.g.: 563 * <p> 564 * {@code 565 * Runnable r = () -> System.out.println("Hello, world!"); 566 * } 567 * </p> 568 * 569 * @param lambda {@link TokenTypes#LAMBDA lambda statement}. 570 * @return true if current lambda statement is single-line statement. 571 */ 572 private static boolean isSingleLineLambda(DetailAST lambda) { 573 final DetailAST lastLambdaToken = getLastLambdaToken(lambda); 574 return TokenUtil.areOnSameLine(lambda, lastLambdaToken); 575 } 576 577 /** 578 * Looks for the last token in lambda. 579 * 580 * @param lambda token to check. 581 * @return last token in lambda 582 */ 583 private static DetailAST getLastLambdaToken(DetailAST lambda) { 584 DetailAST node = lambda; 585 do { 586 node = node.getLastChild(); 587 } while (node.getLastChild() != null); 588 return node; 589 } 590 591 /** 592 * Checks if current ast's parent is a switch rule, e.g.: 593 * <p> 594 * {@code 595 * case 1 -> monthString = "January"; 596 * } 597 * </p> 598 * 599 * @param ast the ast to check. 600 * @return true if current ast belongs to a switch rule. 601 */ 602 private static boolean isInSwitchRule(DetailAST ast) { 603 return ast.getParent().getType() == TokenTypes.SWITCH_RULE; 604 } 605 606 /** 607 * Checks if current expression is a switch labeled expression. If so, 608 * braces are not allowed e.g.: 609 * <p> 610 * {@code 611 * case 1 -> 4; 612 * } 613 * </p> 614 * 615 * @param ast the ast to check 616 * @return true if current expression is a switch labeled expression. 617 */ 618 private static boolean isSwitchLabeledExpression(DetailAST ast) { 619 final DetailAST parent = ast.getParent(); 620 return switchRuleHasSingleExpression(parent); 621 } 622 623 /** 624 * Checks if current switch labeled expression contains only a single expression. 625 * 626 * @param switchRule {@link TokenTypes#SWITCH_RULE}. 627 * @return true if current switch rule has a single expression. 628 */ 629 private static boolean switchRuleHasSingleExpression(DetailAST switchRule) { 630 final DetailAST possibleExpression = switchRule.findFirstToken(TokenTypes.EXPR); 631 return possibleExpression != null 632 && possibleExpression.getFirstChild().getFirstChild() == null; 633 } 634 635 /** 636 * Checks if switch member (case or default statement) in a switch rule or 637 * case group is on a single line. 638 * 639 * @param statement {@link TokenTypes#LITERAL_CASE case statement} or 640 * {@link TokenTypes#LITERAL_DEFAULT default statement}. 641 * @return true if current switch member is single-line statement. 642 */ 643 private static boolean isSingleLineSwitchMember(DetailAST statement) { 644 final boolean result; 645 if (isInSwitchRule(statement)) { 646 result = isSingleLineSwitchRule(statement); 647 } 648 else { 649 result = isSingleLineCaseGroup(statement); 650 } 651 return result; 652 } 653 654 /** 655 * Checks if switch member in case group (case or default statement) 656 * is single-line statement, e.g.: 657 * <p> 658 * {@code 659 * case 1: System.out.println("case one"); break; 660 * case 2: System.out.println("case two"); break; 661 * case 3: ; 662 * default: System.out.println("default"); break; 663 * } 664 * </p> 665 * 666 * 667 * @param ast {@link TokenTypes#LITERAL_CASE case statement} or 668 * {@link TokenTypes#LITERAL_DEFAULT default statement}. 669 * @return true if current switch member is single-line statement. 670 */ 671 private static boolean isSingleLineCaseGroup(DetailAST ast) { 672 return Optional.of(ast) 673 .map(DetailAST::getNextSibling) 674 .map(DetailAST::getLastChild) 675 .map(lastToken -> TokenUtil.areOnSameLine(ast, lastToken)) 676 .orElse(Boolean.TRUE); 677 } 678 679 /** 680 * Checks if switch member in switch rule (case or default statement) is 681 * single-line statement, e.g.: 682 * <p> 683 * {@code 684 * case 1 -> System.out.println("case one"); 685 * case 2 -> System.out.println("case two"); 686 * default -> System.out.println("default"); 687 * } 688 * </p> 689 * 690 * @param ast {@link TokenTypes#LITERAL_CASE case statement} or 691 * {@link TokenTypes#LITERAL_DEFAULT default statement}. 692 * @return true if current switch label is single-line statement. 693 */ 694 private static boolean isSingleLineSwitchRule(DetailAST ast) { 695 final DetailAST lastSibling = ast.getParent().getLastChild(); 696 return TokenUtil.areOnSameLine(ast, lastSibling); 697 } 698 699 /** 700 * Checks if current else statement is single-line statement, e.g.: 701 * <p> 702 * {@code 703 * else doSomeStuff(); 704 * } 705 * </p> 706 * 707 * @param literalElse {@link TokenTypes#LITERAL_ELSE else statement}. 708 * @return true if current else statement is single-line statement. 709 */ 710 private static boolean isSingleLineElse(DetailAST literalElse) { 711 final DetailAST block = literalElse.getFirstChild(); 712 return TokenUtil.areOnSameLine(literalElse, block); 713 } 714 715}