001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2019 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 java.util.ArrayList; 023import java.util.Arrays; 024import java.util.LinkedList; 025import java.util.List; 026 027import com.puppycrawl.tools.checkstyle.StatelessCheck; 028import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 029import com.puppycrawl.tools.checkstyle.api.DetailAST; 030import com.puppycrawl.tools.checkstyle.api.FileContents; 031import com.puppycrawl.tools.checkstyle.api.TokenTypes; 032import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 033import com.puppycrawl.tools.checkstyle.utils.JavadocUtil; 034 035/** 036 * <p> 037 * Checks for empty line separators after header, package, all import declarations, 038 * fields, constructors, methods, nested classes, 039 * static initializers and instance initializers. 040 * </p> 041 * <p> 042 * ATTENTION: empty line separator is required between AST siblings, 043 * not after line where token is found. 044 * </p> 045 * <ul> 046 * <li> 047 * Property {@code allowNoEmptyLineBetweenFields} - Allow no empty line between fields. 048 * Default value is {@code false}. 049 * </li> 050 * <li> 051 * Property {@code allowMultipleEmptyLines} - Allow multiple empty lines between class members. 052 * Default value is {@code true}. 053 * </li> 054 * <li> 055 * Property {@code allowMultipleEmptyLinesInsideClassMembers} - Allow multiple 056 * empty lines inside class members. 057 * Default value is {@code true}. 058 * </li> 059 * <li> 060 * Property {@code tokens} - tokens to check 061 * Default value is: 062 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PACKAGE_DEF"> 063 * PACKAGE_DEF</a>, 064 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPORT"> 065 * IMPORT</a>, 066 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STATIC_IMPORT"> 067 * STATIC_IMPORT</a>, 068 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 069 * CLASS_DEF</a>, 070 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 071 * INTERFACE_DEF</a>, 072 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 073 * ENUM_DEF</a>, 074 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 075 * STATIC_INIT</a>, 076 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT"> 077 * INSTANCE_INIT</a>, 078 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 079 * METHOD_DEF</a>, 080 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF"> 081 * CTOR_DEF</a>, 082 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF"> 083 * VARIABLE_DEF</a>. 084 * </li> 085 * </ul> 086 * <p> 087 * Example of declarations without empty line separator: 088 * </p> 089 * 090 * <pre> 091 * /////////////////////////////////////////////////// 092 * //HEADER 093 * /////////////////////////////////////////////////// 094 * package com.puppycrawl.tools.checkstyle.whitespace; 095 * import java.io.Serializable; 096 * class Foo 097 * { 098 * public static final int FOO_CONST = 1; 099 * public void foo() {} //should be separated from previous statement. 100 * } 101 * </pre> 102 * 103 * <p> 104 * To configure the check with default parameters: 105 * </p> 106 * 107 * <pre> 108 * <module name="EmptyLineSeparator"/> 109 * </pre> 110 * 111 * <p> 112 * Example of declarations with empty line separator 113 * that is expected by the Check by default: 114 * </p> 115 * 116 * <pre> 117 * /////////////////////////////////////////////////// 118 * //HEADER 119 * /////////////////////////////////////////////////// 120 * 121 * package com.puppycrawl.tools.checkstyle.whitespace; 122 * 123 * import java.io.Serializable; 124 * 125 * class Foo 126 * { 127 * public static final int FOO_CONST = 1; 128 * 129 * public void foo() {} 130 * } 131 * </pre> 132 * <p> 133 * To check empty line after 134 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF"> 135 * VARIABLE_DEF</a> and 136 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 137 * METHOD_DEF</a>: 138 * </p> 139 * 140 * <pre> 141 * <module name="EmptyLineSeparator"> 142 * <property name="tokens" value="VARIABLE_DEF, METHOD_DEF"/> 143 * </module> 144 * </pre> 145 * 146 * <p> 147 * To allow no empty line between fields: 148 * </p> 149 * <pre> 150 * <module name="EmptyLineSeparator"> 151 * <property name="allowNoEmptyLineBetweenFields" value="true"/> 152 * </module> 153 * </pre> 154 * 155 * <p> 156 * Example of declarations with multiple empty lines between class members (allowed by default): 157 * </p> 158 * 159 * <pre> 160 * /////////////////////////////////////////////////// 161 * //HEADER 162 * /////////////////////////////////////////////////// 163 * 164 * 165 * package com.puppycrawl.tools.checkstyle.whitespace; 166 * 167 * 168 * 169 * import java.io.Serializable; 170 * 171 * 172 * class Foo 173 * { 174 * public static final int FOO_CONST = 1; 175 * 176 * 177 * 178 * public void foo() {} //should be separated from previous statement. 179 * } 180 * </pre> 181 * <p> 182 * To disallow multiple empty lines between class members: 183 * </p> 184 * <pre> 185 * <module name="EmptyLineSeparator"> 186 * <property name="allowMultipleEmptyLines" value="false"/> 187 * </module> 188 * </pre> 189 * 190 * <p> 191 * To disallow multiple empty lines inside constructor, initialization block and method: 192 * </p> 193 * <pre> 194 * <module name="EmptyLineSeparator"> 195 * <property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/> 196 * </module> 197 * </pre> 198 * 199 * <p> 200 * The check is valid only for statements that have body: 201 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 202 * CLASS_DEF</a>, 203 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 204 * INTERFACE_DEF</a>, 205 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 206 * ENUM_DEF</a>, 207 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 208 * STATIC_INIT</a>, 209 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT"> 210 * INSTANCE_INIT</a>, 211 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 212 * METHOD_DEF</a>, 213 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF"> 214 * CTOR_DEF</a>. 215 * </p> 216 * <p> 217 * Example of declarations with multiple empty lines inside method: 218 * </p> 219 * 220 * <pre> 221 * /////////////////////////////////////////////////// 222 * //HEADER 223 * /////////////////////////////////////////////////// 224 * 225 * package com.puppycrawl.tools.checkstyle.whitespace; 226 * 227 * class Foo 228 * { 229 * 230 * public void foo() { 231 * 232 * 233 * System.out.println(1); // violation since method has 2 empty lines subsequently 234 * } 235 * } 236 * </pre> 237 * 238 * @since 5.8 239 */ 240@StatelessCheck 241public class EmptyLineSeparatorCheck extends AbstractCheck { 242 243 /** 244 * A key is pointing to the warning message empty.line.separator in "messages.properties" 245 * file. 246 */ 247 public static final String MSG_SHOULD_BE_SEPARATED = "empty.line.separator"; 248 249 /** 250 * A key is pointing to the warning message empty.line.separator.multiple.lines 251 * in "messages.properties" 252 * file. 253 */ 254 public static final String MSG_MULTIPLE_LINES = "empty.line.separator.multiple.lines"; 255 256 /** 257 * A key is pointing to the warning message empty.line.separator.lines.after 258 * in "messages.properties" file. 259 */ 260 public static final String MSG_MULTIPLE_LINES_AFTER = 261 "empty.line.separator.multiple.lines.after"; 262 263 /** 264 * A key is pointing to the warning message empty.line.separator.multiple.lines.inside 265 * in "messages.properties" file. 266 */ 267 public static final String MSG_MULTIPLE_LINES_INSIDE = 268 "empty.line.separator.multiple.lines.inside"; 269 270 /** List of AST token types, which can not have comment nodes to check inside. */ 271 private static final List<Integer> TOKEN_TYPES_WITHOUT_COMMENTS_TO_CHECK_INSIDE = 272 Arrays.asList(TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, 273 TokenTypes.STATIC_INIT); 274 275 /** Allow no empty line between fields. */ 276 private boolean allowNoEmptyLineBetweenFields; 277 278 /** Allow multiple empty lines between class members. */ 279 private boolean allowMultipleEmptyLines = true; 280 281 /** Allow multiple empty lines inside class members. */ 282 private boolean allowMultipleEmptyLinesInsideClassMembers = true; 283 284 /** 285 * Setter to allow no empty line between fields. 286 * @param allow 287 * User's value. 288 */ 289 public final void setAllowNoEmptyLineBetweenFields(boolean allow) { 290 allowNoEmptyLineBetweenFields = allow; 291 } 292 293 /** 294 * Setter to allow multiple empty lines between class members. 295 * @param allow User's value. 296 */ 297 public void setAllowMultipleEmptyLines(boolean allow) { 298 allowMultipleEmptyLines = allow; 299 } 300 301 /** 302 * Setter to allow multiple empty lines inside class members. 303 * @param allow User's value. 304 */ 305 public void setAllowMultipleEmptyLinesInsideClassMembers(boolean allow) { 306 allowMultipleEmptyLinesInsideClassMembers = allow; 307 } 308 309 @Override 310 public boolean isCommentNodesRequired() { 311 return true; 312 } 313 314 @Override 315 public int[] getDefaultTokens() { 316 return getAcceptableTokens(); 317 } 318 319 @Override 320 public int[] getAcceptableTokens() { 321 return new int[] { 322 TokenTypes.PACKAGE_DEF, 323 TokenTypes.IMPORT, 324 TokenTypes.STATIC_IMPORT, 325 TokenTypes.CLASS_DEF, 326 TokenTypes.INTERFACE_DEF, 327 TokenTypes.ENUM_DEF, 328 TokenTypes.STATIC_INIT, 329 TokenTypes.INSTANCE_INIT, 330 TokenTypes.METHOD_DEF, 331 TokenTypes.CTOR_DEF, 332 TokenTypes.VARIABLE_DEF, 333 }; 334 } 335 336 @Override 337 public int[] getRequiredTokens() { 338 return CommonUtil.EMPTY_INT_ARRAY; 339 } 340 341 @Override 342 public void visitToken(DetailAST ast) { 343 checkComments(ast); 344 if (hasMultipleLinesBefore(ast)) { 345 log(ast.getLineNo(), MSG_MULTIPLE_LINES, ast.getText()); 346 } 347 if (!allowMultipleEmptyLinesInsideClassMembers) { 348 processMultipleLinesInside(ast); 349 } 350 351 DetailAST nextToken = ast.getNextSibling(); 352 while (nextToken != null && isComment(nextToken)) { 353 nextToken = nextToken.getNextSibling(); 354 } 355 if (nextToken != null) { 356 final int astType = ast.getType(); 357 switch (astType) { 358 case TokenTypes.VARIABLE_DEF: 359 processVariableDef(ast, nextToken); 360 break; 361 case TokenTypes.IMPORT: 362 case TokenTypes.STATIC_IMPORT: 363 processImport(ast, nextToken); 364 break; 365 case TokenTypes.PACKAGE_DEF: 366 processPackage(ast, nextToken); 367 break; 368 default: 369 if (nextToken.getType() == TokenTypes.RCURLY) { 370 if (hasNotAllowedTwoEmptyLinesBefore(nextToken)) { 371 log(ast.getLineNo(), MSG_MULTIPLE_LINES_AFTER, ast.getText()); 372 } 373 } 374 else if (!hasEmptyLineAfter(ast)) { 375 log(nextToken.getLineNo(), MSG_SHOULD_BE_SEPARATED, 376 nextToken.getText()); 377 } 378 } 379 } 380 } 381 382 /** 383 * Log violation in case there are multiple empty lines inside constructor, 384 * initialization block or method. 385 * @param ast the ast to check. 386 */ 387 private void processMultipleLinesInside(DetailAST ast) { 388 final int astType = ast.getType(); 389 if (isClassMemberBlock(astType)) { 390 final List<Integer> emptyLines = getEmptyLines(ast); 391 final List<Integer> emptyLinesToLog = getEmptyLinesToLog(emptyLines); 392 393 for (Integer lineNo : emptyLinesToLog) { 394 // Checkstyle counts line numbers from 0 but IDE from 1 395 log(lineNo + 1, MSG_MULTIPLE_LINES_INSIDE); 396 } 397 } 398 } 399 400 /** 401 * Whether the AST is a class member block. 402 * @param astType the AST to check. 403 * @return true if the AST is a class member block. 404 */ 405 private static boolean isClassMemberBlock(int astType) { 406 return astType == TokenTypes.STATIC_INIT 407 || astType == TokenTypes.INSTANCE_INIT 408 || astType == TokenTypes.METHOD_DEF 409 || astType == TokenTypes.CTOR_DEF; 410 } 411 412 /** 413 * Get list of empty lines. 414 * @param ast the ast to check. 415 * @return list of line numbers for empty lines. 416 */ 417 private List<Integer> getEmptyLines(DetailAST ast) { 418 final DetailAST lastToken = ast.getLastChild().getLastChild(); 419 int lastTokenLineNo = 0; 420 if (lastToken != null) { 421 // -1 as count starts from 0 422 // -2 as last token line cannot be empty, because it is a RCURLY 423 lastTokenLineNo = lastToken.getLineNo() - 2; 424 } 425 final List<Integer> emptyLines = new ArrayList<>(); 426 final FileContents fileContents = getFileContents(); 427 428 for (int lineNo = ast.getLineNo(); lineNo <= lastTokenLineNo; lineNo++) { 429 if (fileContents.lineIsBlank(lineNo)) { 430 emptyLines.add(lineNo); 431 } 432 } 433 return emptyLines; 434 } 435 436 /** 437 * Get list of empty lines to log. 438 * @param emptyLines list of empty lines. 439 * @return list of empty lines to log. 440 */ 441 private static List<Integer> getEmptyLinesToLog(List<Integer> emptyLines) { 442 final List<Integer> emptyLinesToLog = new ArrayList<>(); 443 if (emptyLines.size() >= 2) { 444 int previousEmptyLineNo = emptyLines.get(0); 445 for (int emptyLineNo : emptyLines) { 446 if (previousEmptyLineNo + 1 == emptyLineNo) { 447 emptyLinesToLog.add(emptyLineNo); 448 } 449 previousEmptyLineNo = emptyLineNo; 450 } 451 } 452 return emptyLinesToLog; 453 } 454 455 /** 456 * Whether the token has not allowed multiple empty lines before. 457 * @param ast the ast to check. 458 * @return true if the token has not allowed multiple empty lines before. 459 */ 460 private boolean hasMultipleLinesBefore(DetailAST ast) { 461 boolean result = false; 462 if ((ast.getType() != TokenTypes.VARIABLE_DEF 463 || isTypeField(ast)) 464 && hasNotAllowedTwoEmptyLinesBefore(ast)) { 465 result = true; 466 } 467 return result; 468 } 469 470 /** 471 * Process Package. 472 * @param ast token 473 * @param nextToken next token 474 */ 475 private void processPackage(DetailAST ast, DetailAST nextToken) { 476 if (ast.getLineNo() > 1 && !hasEmptyLineBefore(ast)) { 477 if (getFileContents().getFileName().endsWith("package-info.java")) { 478 if (ast.getFirstChild().getChildCount() == 0 && !isPrecededByJavadoc(ast)) { 479 log(ast.getLineNo(), MSG_SHOULD_BE_SEPARATED, ast.getText()); 480 } 481 } 482 else { 483 log(ast.getLineNo(), MSG_SHOULD_BE_SEPARATED, ast.getText()); 484 } 485 } 486 if (!hasEmptyLineAfter(ast)) { 487 log(nextToken.getLineNo(), MSG_SHOULD_BE_SEPARATED, nextToken.getText()); 488 } 489 } 490 491 /** 492 * Process Import. 493 * @param ast token 494 * @param nextToken next token 495 */ 496 private void processImport(DetailAST ast, DetailAST nextToken) { 497 if (nextToken.getType() != TokenTypes.IMPORT 498 && nextToken.getType() != TokenTypes.STATIC_IMPORT && !hasEmptyLineAfter(ast)) { 499 log(nextToken.getLineNo(), MSG_SHOULD_BE_SEPARATED, nextToken.getText()); 500 } 501 } 502 503 /** 504 * Process Variable. 505 * @param ast token 506 * @param nextToken next Token 507 */ 508 private void processVariableDef(DetailAST ast, DetailAST nextToken) { 509 if (isTypeField(ast) && !hasEmptyLineAfter(ast) 510 && isViolatingEmptyLineBetweenFieldsPolicy(nextToken)) { 511 log(nextToken.getLineNo(), MSG_SHOULD_BE_SEPARATED, 512 nextToken.getText()); 513 } 514 } 515 516 /** 517 * Checks whether token placement violates policy of empty line between fields. 518 * @param detailAST token to be analyzed 519 * @return true if policy is violated and warning should be raised; false otherwise 520 */ 521 private boolean isViolatingEmptyLineBetweenFieldsPolicy(DetailAST detailAST) { 522 return detailAST.getType() != TokenTypes.RCURLY 523 && (!allowNoEmptyLineBetweenFields 524 || detailAST.getType() != TokenTypes.VARIABLE_DEF); 525 } 526 527 /** 528 * Checks if a token has empty two previous lines and multiple empty lines is not allowed. 529 * @param token DetailAST token 530 * @return true, if token has empty two lines before and allowMultipleEmptyLines is false 531 */ 532 private boolean hasNotAllowedTwoEmptyLinesBefore(DetailAST token) { 533 return !allowMultipleEmptyLines && hasEmptyLineBefore(token) 534 && isPrePreviousLineEmpty(token); 535 } 536 537 /** 538 * Check if group of comments located right before token has more than one previous empty line. 539 * @param token DetailAST token 540 */ 541 private void checkComments(DetailAST token) { 542 if (!allowMultipleEmptyLines) { 543 if (TOKEN_TYPES_WITHOUT_COMMENTS_TO_CHECK_INSIDE.contains(token.getType())) { 544 DetailAST previousNode = token.getPreviousSibling(); 545 while (isCommentInBeginningOfLine(previousNode)) { 546 if (hasEmptyLineBefore(previousNode) && isPrePreviousLineEmpty(previousNode)) { 547 log(previousNode, MSG_MULTIPLE_LINES, previousNode.getText()); 548 } 549 previousNode = previousNode.getPreviousSibling(); 550 } 551 } 552 else { 553 checkCommentsInsideToken(token); 554 } 555 } 556 } 557 558 /** 559 * Check if group of comments located at the start of token has more than one previous empty 560 * line. 561 * @param token DetailAST token 562 */ 563 private void checkCommentsInsideToken(DetailAST token) { 564 final List<DetailAST> childNodes = new LinkedList<>(); 565 DetailAST childNode = token.getLastChild(); 566 while (childNode != null) { 567 if (childNode.getType() == TokenTypes.MODIFIERS) { 568 for (DetailAST node = token.getFirstChild().getLastChild(); 569 node != null; 570 node = node.getPreviousSibling()) { 571 if (isCommentInBeginningOfLine(node)) { 572 childNodes.add(node); 573 } 574 } 575 } 576 else if (isCommentInBeginningOfLine(childNode)) { 577 childNodes.add(childNode); 578 } 579 childNode = childNode.getPreviousSibling(); 580 } 581 for (DetailAST node : childNodes) { 582 if (hasEmptyLineBefore(node) && isPrePreviousLineEmpty(node)) { 583 log(node, MSG_MULTIPLE_LINES, node.getText()); 584 } 585 } 586 } 587 588 /** 589 * Checks if a token has empty pre-previous line. 590 * @param token DetailAST token. 591 * @return true, if token has empty lines before. 592 */ 593 private boolean isPrePreviousLineEmpty(DetailAST token) { 594 boolean result = false; 595 final int lineNo = token.getLineNo(); 596 // 3 is the number of the pre-previous line because the numbering starts from zero. 597 final int number = 3; 598 if (lineNo >= number) { 599 final String prePreviousLine = getLines()[lineNo - number]; 600 result = CommonUtil.isBlank(prePreviousLine); 601 } 602 return result; 603 } 604 605 /** 606 * Checks if token have empty line after. 607 * @param token token. 608 * @return true if token have empty line after. 609 */ 610 private boolean hasEmptyLineAfter(DetailAST token) { 611 DetailAST lastToken = token.getLastChild().getLastChild(); 612 if (lastToken == null) { 613 lastToken = token.getLastChild(); 614 } 615 DetailAST nextToken = token.getNextSibling(); 616 if (isComment(nextToken)) { 617 nextToken = nextToken.getNextSibling(); 618 } 619 // Start of the next token 620 final int nextBegin = nextToken.getLineNo(); 621 // End of current token. 622 final int currentEnd = lastToken.getLineNo(); 623 return hasEmptyLine(currentEnd + 1, nextBegin - 1); 624 } 625 626 /** 627 * Checks, whether there are empty lines within the specified line range. Line numbering is 628 * started from 1 for parameter values 629 * @param startLine number of the first line in the range 630 * @param endLine number of the second line in the range 631 * @return {@code true} if found any blank line within the range, {@code false} 632 * otherwise 633 */ 634 private boolean hasEmptyLine(int startLine, int endLine) { 635 // Initial value is false - blank line not found 636 boolean result = false; 637 final FileContents fileContents = getFileContents(); 638 for (int line = startLine; line <= endLine; line++) { 639 // Check, if the line is blank. Lines are numbered from 0, so subtract 1 640 if (fileContents.lineIsBlank(line - 1)) { 641 result = true; 642 break; 643 } 644 } 645 return result; 646 } 647 648 /** 649 * Checks if a token has a empty line before. 650 * @param token token. 651 * @return true, if token have empty line before. 652 */ 653 private boolean hasEmptyLineBefore(DetailAST token) { 654 boolean result = false; 655 final int lineNo = token.getLineNo(); 656 if (lineNo != 1) { 657 // [lineNo - 2] is the number of the previous line as the numbering starts from zero. 658 final String lineBefore = getLines()[lineNo - 2]; 659 result = CommonUtil.isBlank(lineBefore); 660 } 661 return result; 662 } 663 664 /** 665 * Check if token is comment, which starting in beginning of line. 666 * @param comment comment token for check. 667 * @return true, if token is comment, which starting in beginning of line. 668 */ 669 private boolean isCommentInBeginningOfLine(DetailAST comment) { 670 // [comment.getLineNo() - 1] is the number of the previous line as the numbering starts 671 // from zero. 672 boolean result = false; 673 if (comment != null) { 674 final String lineWithComment = getLines()[comment.getLineNo() - 1].trim(); 675 result = lineWithComment.startsWith("//") || lineWithComment.startsWith("/*"); 676 } 677 return result; 678 } 679 680 /** 681 * Check if token is preceded by javadoc comment. 682 * @param token token for check. 683 * @return true, if token is preceded by javadoc comment. 684 */ 685 private static boolean isPrecededByJavadoc(DetailAST token) { 686 boolean result = false; 687 final DetailAST previous = token.getPreviousSibling(); 688 if (previous.getType() == TokenTypes.BLOCK_COMMENT_BEGIN 689 && JavadocUtil.isJavadocComment(previous.getFirstChild().getText())) { 690 result = true; 691 } 692 return result; 693 } 694 695 /** 696 * Check if token is a comment. 697 * @param ast ast node 698 * @return true, if given ast is comment. 699 */ 700 private static boolean isComment(DetailAST ast) { 701 return ast.getType() == TokenTypes.SINGLE_LINE_COMMENT 702 || ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN; 703 } 704 705 /** 706 * If variable definition is a type field. 707 * @param variableDef variable definition. 708 * @return true variable definition is a type field. 709 */ 710 private static boolean isTypeField(DetailAST variableDef) { 711 final int parentType = variableDef.getParent().getParent().getType(); 712 return parentType == TokenTypes.CLASS_DEF; 713 } 714 715}