001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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.naming; 021 022import java.util.Arrays; 023import java.util.HashSet; 024import java.util.LinkedList; 025import java.util.List; 026import java.util.Set; 027import java.util.stream.Collectors; 028 029import com.puppycrawl.tools.checkstyle.StatelessCheck; 030import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 031import com.puppycrawl.tools.checkstyle.api.DetailAST; 032import com.puppycrawl.tools.checkstyle.api.TokenTypes; 033import com.puppycrawl.tools.checkstyle.utils.CheckUtil; 034import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 035 036/** 037 * <p> 038 * Validates abbreviations (consecutive capital letters) length in 039 * identifier name, it also allows to enforce camel case naming. Please read more at 040 * <a href="https://checkstyle.org/styleguides/google-java-style-20180523/javaguide.html#s5.3-camel-case"> 041 * Google Style Guide</a> to get to know how to avoid long abbreviations in names. 042 * </p> 043 * <p> 044 * {@code allowedAbbreviationLength} specifies how many consecutive capital letters are 045 * allowed in the identifier. 046 * A value of <i>3</i> indicates that up to 4 consecutive capital letters are allowed, 047 * one after the other, before a violation is printed. The identifier 'MyTEST' would be 048 * allowed, but 'MyTESTS' would not be. 049 * A value of <i>0</i> indicates that only 1 consecutive capital letter is allowed. This 050 * is what should be used to enforce strict camel casing. The identifier 'MyTest' would 051 * be allowed, but 'MyTEst' would not be. 052 * </p> 053 * <p> 054 * {@code ignoreFinal}, {@code ignoreStatic}, and {@code ignoreStaticFinal} 055 * control whether variables with the respective modifiers are to be ignored. 056 * Note that a variable that is both static and final will always be considered under 057 * {@code ignoreStaticFinal} only, regardless of the values of {@code ignoreFinal} 058 * and {@code ignoreStatic}. So for example if {@code ignoreStatic} is true but 059 * {@code ignoreStaticFinal} is false, then static final variables will not be ignored. 060 * </p> 061 * <ul> 062 * <li> 063 * Property {@code allowedAbbreviationLength} - Indicate the number of consecutive capital 064 * letters allowed in targeted identifiers (abbreviations in the classes, interfaces, variables 065 * and methods names, ... ). 066 * Type is {@code int}. 067 * Default value is {@code 3}. 068 * </li> 069 * <li> 070 * Property {@code allowedAbbreviations} - Specify list of abbreviations that must be skipped for 071 * checking. Abbreviations should be separated by comma. 072 * Type is {@code java.lang.String[]}. 073 * Default value is {@code {}}. 074 * </li> 075 * <li> 076 * Property {@code ignoreFinal} - Allow to skip variables with {@code final} modifier. 077 * Type is {@code boolean}. 078 * Default value is {@code true}. 079 * </li> 080 * <li> 081 * Property {@code ignoreStatic} - Allow to skip variables with {@code static} modifier. 082 * Type is {@code boolean}. 083 * Default value is {@code true}. 084 * </li> 085 * <li> 086 * Property {@code ignoreStaticFinal} - Allow to skip variables with both {@code static} and 087 * {@code final} modifiers. 088 * Type is {@code boolean}. 089 * Default value is {@code true}. 090 * </li> 091 * <li> 092 * Property {@code ignoreOverriddenMethods} - Allow to ignore methods tagged with {@code @Override} 093 * annotation (that usually mean inherited name). 094 * Type is {@code boolean}. 095 * Default value is {@code true}. 096 * </li> 097 * <li> 098 * Property {@code tokens} - tokens to check 099 * Type is {@code int[]}. 100 * Default value is: 101 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 102 * CLASS_DEF</a>, 103 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 104 * INTERFACE_DEF</a>, 105 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 106 * ENUM_DEF</a>, 107 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF"> 108 * ANNOTATION_DEF</a>, 109 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_FIELD_DEF"> 110 * ANNOTATION_FIELD_DEF</a>, 111 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PARAMETER_DEF"> 112 * PARAMETER_DEF</a>, 113 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF"> 114 * VARIABLE_DEF</a>, 115 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 116 * METHOD_DEF</a>, 117 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PATTERN_VARIABLE_DEF"> 118 * PATTERN_VARIABLE_DEF</a>. 119 * </li> 120 * </ul> 121 * <p> 122 * To configure the check: 123 * </p> 124 * <pre> 125 * <module name="AbbreviationAsWordInName"/> 126 * </pre> 127 * <p> 128 * Example: 129 * </p> 130 * <pre> 131 * public class MyClass extends SuperClass { // OK, camel case 132 * int CURRENT_COUNTER; // violation, at most 4 consecutive capital letters allowed 133 * static int GLOBAL_COUNTER; // OK, static is ignored 134 * final Set<String> stringsFOUND = new HashSet<>(); // OK, final is ignored 135 * 136 * @Override 137 * void printCOUNTER() { // OK, overridden method is ignored 138 * System.out.println(CURRENT_COUNTER); // OK, only definitions are checked 139 * } 140 * 141 * void incrementCOUNTER() { // violation, at most 4 consecutive capital letters allowed 142 * CURRENT_COUNTER++; // OK, only definitions are checked 143 * } 144 * 145 * static void incrementGLOBAL() { // violation, static method is not ignored 146 * GLOBAL_COUNTER++; // OK, only definitions are checked 147 * } 148 * 149 * } 150 * </pre> 151 * <p> 152 * To configure to include static variables and methods tagged with 153 * {@code @Override} annotation. 154 * </p> 155 * <p>Configuration:</p> 156 * <pre> 157 * <module name="AbbreviationAsWordInName"> 158 * <property name="ignoreStatic" value="false"/> 159 * <property name="ignoreOverriddenMethods" value="false"/> 160 * </module> 161 * </pre> 162 * <p>Example:</p> 163 * <pre> 164 * public class MyClass extends SuperClass { // OK, camel case 165 * int CURRENT_COUNTER; // violation, at most 4 consecutive capital letters allowed 166 * static int GLOBAL_COUNTER; // violation, static is not ignored 167 * final Set<String> stringsFOUND = new HashSet<>(); // OK, final is ignored 168 * 169 * @Override 170 * void printCOUNTER() { // violation, overridden method is not ignored 171 * System.out.println(CURRENT_COUNTER); // OK, only definitions are checked 172 * } 173 * 174 * void incrementCOUNTER() { // violation, at most 4 consecutive capital letters allowed 175 * CURRENT_COUNTER++; // OK, only definitions are checked 176 * } 177 * 178 * static void incrementGLOBAL() { // violation, at most 4 consecutive capital letters allowed 179 * GLOBAL_COUNTER++; // OK, only definitions are checked 180 * } 181 * 182 * } 183 * </pre> 184 * <p> 185 * To configure to check all variables and identifiers 186 * (including ones with the static modifier) and enforce 187 * no abbreviations (essentially camel case) except for 188 * words like 'XML' and 'URL'. 189 * </p> 190 * <p>Configuration:</p> 191 * <pre> 192 * <module name="AbbreviationAsWordInName"> 193 * <property name="tokens" value="VARIABLE_DEF,CLASS_DEF"/> 194 * <property name="ignoreStatic" value="false"/> 195 * <property name="allowedAbbreviationLength" value="0"/> 196 * <property name="allowedAbbreviations" value="XML,URL"/> 197 * </module> 198 * </pre> 199 * <p>Example:</p> 200 * <pre> 201 * public class MyClass { // OK 202 * int firstNum; // OK 203 * int secondNUM; // violation, it allowed only 1 consecutive capital letter 204 * static int thirdNum; // OK, the static modifier would be checked 205 * static int fourthNUm; // violation, the static modifier would be checked, 206 * // and only 1 consecutive capital letter is allowed 207 * String firstXML; // OK, XML abbreviation is allowed 208 * String firstURL; // OK, URL abbreviation is allowed 209 * final int TOTAL = 5; // OK, final is ignored 210 * static final int LIMIT = 10; // OK, static final is ignored 211 * } 212 * </pre> 213 * <p> 214 * To configure to check variables, excluding fields with 215 * the static modifier, and allow abbreviations up to 2 216 * consecutive capital letters ignoring the longer word 'CSV'. 217 * </p> 218 * <p>Configuration:</p> 219 * <pre> 220 * <module name="AbbreviationAsWordInName"> 221 * <property name="tokens" value="VARIABLE_DEF"/> 222 * <property name="ignoreStatic" value="true"/> 223 * <property name="allowedAbbreviationLength" value="1"/> 224 * <property name="allowedAbbreviations" value="CSV"/> 225 * </module> 226 * </pre> 227 * <p>Example:</p> 228 * <pre> 229 * public class MyClass { // OK, ignore checking the class name 230 * int firstNum; // OK, abbreviation "N" is of allowed length 1 231 * int secondNUm; // OK 232 * int secondMYNum; // violation, found "MYN" but only 233 * // 2 consecutive capital letters are allowed 234 * int thirdNUM; // violation, found "NUM" but it is allowed 235 * // only 2 consecutive capital letters 236 * static int fourthNUM; // OK, variables with static modifier 237 * // would be ignored 238 * String firstCSV; // OK, CSV abbreviation is allowed 239 * String firstXML; // violation, XML abbreviation is not allowed 240 * final int TOTAL = 5; // OK, final is ignored 241 * static final int LIMIT = 10; // OK, static final is ignored 242 * } 243 * </pre> 244 * <p> 245 * To configure to check variables, enforcing no abbreviations 246 * except for variables that are both static and final. 247 * </p> 248 * <p>Configuration:</p> 249 * <pre> 250 * <module name="AbbreviationAsWordInName"> 251 * <property name="tokens" value="VARIABLE_DEF"/> 252 * <property name="ignoreFinal" value="false"/> 253 * <property name="ignoreStatic" value="false"/> 254 * <property name="ignoreStaticFinal" value="true"/> 255 * <property name="allowedAbbreviationLength" value="0"/> 256 * </module> 257 * </pre> 258 * <p>Example:</p> 259 * <pre> 260 * public class MyClass { 261 * public int counterXYZ = 1; // violation 262 * public final int customerID = 2; // violation 263 * public static int nextID = 3; // violation 264 * public static final int MAX_ALLOWED = 4; // OK, ignored 265 * } 266 * </pre> 267 * <p> 268 * To configure to check variables, enforcing no abbreviations 269 * and ignoring static (but non-final) variables only. 270 * </p> 271 * <p>Configuration:</p> 272 * <pre> 273 * <module name="AbbreviationAsWordInName"> 274 * <property name="tokens" value="VARIABLE_DEF"/> 275 * <property name="ignoreFinal" value="false"/> 276 * <property name="ignoreStatic" value="true"/> 277 * <property name="ignoreStaticFinal" value="false"/> 278 * <property name="allowedAbbreviationLength" value="0"/> 279 * </module> 280 * </pre> 281 * <p>Example:</p> 282 * <pre> 283 * public class MyClass { 284 * public int counterXYZ = 1; // violation 285 * public final int customerID = 2; // violation 286 * public static int nextID = 3; // OK, ignored 287 * public static final int MAX_ALLOWED = 4; // violation 288 * } 289 * </pre> 290 * <p> 291 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 292 * </p> 293 * <p> 294 * Violation Message Keys: 295 * </p> 296 * <ul> 297 * <li> 298 * {@code abbreviation.as.word} 299 * </li> 300 * </ul> 301 * 302 * @since 5.8 303 */ 304@StatelessCheck 305public class AbbreviationAsWordInNameCheck extends AbstractCheck { 306 307 /** 308 * Warning message key. 309 */ 310 public static final String MSG_KEY = "abbreviation.as.word"; 311 312 /** 313 * The default value of "allowedAbbreviationLength" option. 314 */ 315 private static final int DEFAULT_ALLOWED_ABBREVIATIONS_LENGTH = 3; 316 317 /** 318 * Indicate the number of consecutive capital letters allowed in 319 * targeted identifiers (abbreviations in the classes, interfaces, variables 320 * and methods names, ... ). 321 */ 322 private int allowedAbbreviationLength = 323 DEFAULT_ALLOWED_ABBREVIATIONS_LENGTH; 324 325 /** 326 * Specify list of abbreviations that must be skipped for checking. Abbreviations 327 * should be separated by comma. 328 */ 329 private Set<String> allowedAbbreviations = new HashSet<>(); 330 331 /** Allow to skip variables with {@code final} modifier. */ 332 private boolean ignoreFinal = true; 333 334 /** Allow to skip variables with {@code static} modifier. */ 335 private boolean ignoreStatic = true; 336 337 /** Allow to skip variables with both {@code static} and {@code final} modifiers. */ 338 private boolean ignoreStaticFinal = true; 339 340 /** 341 * Allow to ignore methods tagged with {@code @Override} annotation (that 342 * usually mean inherited name). 343 */ 344 private boolean ignoreOverriddenMethods = true; 345 346 /** 347 * Setter to allow to skip variables with {@code final} modifier. 348 * 349 * @param ignoreFinal 350 * Defines if ignore variables with 'final' modifier or not. 351 */ 352 public void setIgnoreFinal(boolean ignoreFinal) { 353 this.ignoreFinal = ignoreFinal; 354 } 355 356 /** 357 * Setter to allow to skip variables with {@code static} modifier. 358 * 359 * @param ignoreStatic 360 * Defines if ignore variables with 'static' modifier or not. 361 */ 362 public void setIgnoreStatic(boolean ignoreStatic) { 363 this.ignoreStatic = ignoreStatic; 364 } 365 366 /** 367 * Setter to allow to skip variables with both {@code static} and {@code final} modifiers. 368 * 369 * @param ignoreStaticFinal 370 * Defines if ignore variables with both 'static' and 'final' modifiers or not. 371 */ 372 public void setIgnoreStaticFinal(boolean ignoreStaticFinal) { 373 this.ignoreStaticFinal = ignoreStaticFinal; 374 } 375 376 /** 377 * Setter to allow to ignore methods tagged with {@code @Override} 378 * annotation (that usually mean inherited name). 379 * 380 * @param ignoreOverriddenMethods 381 * Defines if ignore methods with "@Override" annotation or not. 382 */ 383 public void setIgnoreOverriddenMethods(boolean ignoreOverriddenMethods) { 384 this.ignoreOverriddenMethods = ignoreOverriddenMethods; 385 } 386 387 /** 388 * Setter to indicate the number of consecutive capital letters allowed 389 * in targeted identifiers (abbreviations in the classes, interfaces, 390 * variables and methods names, ... ). 391 * 392 * @param allowedAbbreviationLength amount of allowed capital letters in 393 * abbreviation. 394 */ 395 public void setAllowedAbbreviationLength(int allowedAbbreviationLength) { 396 this.allowedAbbreviationLength = allowedAbbreviationLength; 397 } 398 399 /** 400 * Setter to specify list of abbreviations that must be skipped for checking. 401 * Abbreviations should be separated by comma. 402 * 403 * @param allowedAbbreviations an string of abbreviations that must be 404 * skipped from checking, each abbreviation separated by comma. 405 */ 406 public void setAllowedAbbreviations(String... allowedAbbreviations) { 407 if (allowedAbbreviations != null) { 408 this.allowedAbbreviations = 409 Arrays.stream(allowedAbbreviations).collect(Collectors.toSet()); 410 } 411 } 412 413 @Override 414 public int[] getDefaultTokens() { 415 return new int[] { 416 TokenTypes.CLASS_DEF, 417 TokenTypes.INTERFACE_DEF, 418 TokenTypes.ENUM_DEF, 419 TokenTypes.ANNOTATION_DEF, 420 TokenTypes.ANNOTATION_FIELD_DEF, 421 TokenTypes.PARAMETER_DEF, 422 TokenTypes.VARIABLE_DEF, 423 TokenTypes.METHOD_DEF, 424 TokenTypes.PATTERN_VARIABLE_DEF, 425 426 }; 427 } 428 429 @Override 430 public int[] getAcceptableTokens() { 431 return new int[] { 432 TokenTypes.CLASS_DEF, 433 TokenTypes.INTERFACE_DEF, 434 TokenTypes.ENUM_DEF, 435 TokenTypes.ANNOTATION_DEF, 436 TokenTypes.ANNOTATION_FIELD_DEF, 437 TokenTypes.PARAMETER_DEF, 438 TokenTypes.VARIABLE_DEF, 439 TokenTypes.METHOD_DEF, 440 TokenTypes.ENUM_CONSTANT_DEF, 441 TokenTypes.PATTERN_VARIABLE_DEF, 442 443 }; 444 } 445 446 @Override 447 public int[] getRequiredTokens() { 448 return CommonUtil.EMPTY_INT_ARRAY; 449 } 450 451 @Override 452 public void visitToken(DetailAST ast) { 453 if (!isIgnoreSituation(ast)) { 454 final DetailAST nameAst = ast.findFirstToken(TokenTypes.IDENT); 455 final String typeName = nameAst.getText(); 456 457 final String abbr = getDisallowedAbbreviation(typeName); 458 if (abbr != null) { 459 log(nameAst, MSG_KEY, typeName, allowedAbbreviationLength + 1); 460 } 461 } 462 } 463 464 /** 465 * Checks if it is an ignore situation. 466 * 467 * @param ast input DetailAST node. 468 * @return true if it is an ignore situation found for given input DetailAST 469 * node. 470 */ 471 private boolean isIgnoreSituation(DetailAST ast) { 472 final DetailAST modifiers = ast.getFirstChild(); 473 474 final boolean result; 475 if (ast.getType() == TokenTypes.VARIABLE_DEF) { 476 if (isInterfaceDeclaration(ast)) { 477 // field declarations in interface are static/final 478 result = ignoreStaticFinal; 479 } 480 else { 481 result = hasIgnoredModifiers(modifiers); 482 } 483 } 484 else if (ast.getType() == TokenTypes.METHOD_DEF) { 485 result = ignoreOverriddenMethods && hasOverrideAnnotation(modifiers); 486 } 487 else { 488 result = CheckUtil.isReceiverParameter(ast); 489 } 490 return result; 491 } 492 493 /** 494 * Checks if a variable is to be ignored based on its modifiers. 495 * 496 * @param modifiers modifiers of the variable to be checked 497 * @return true if there is a modifier to be ignored 498 */ 499 private boolean hasIgnoredModifiers(DetailAST modifiers) { 500 final boolean isStatic = modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null; 501 final boolean isFinal = modifiers.findFirstToken(TokenTypes.FINAL) != null; 502 final boolean result; 503 if (isStatic && isFinal) { 504 result = ignoreStaticFinal; 505 } 506 else { 507 result = ignoreStatic && isStatic || ignoreFinal && isFinal; 508 } 509 return result; 510 } 511 512 /** 513 * Check that variable definition in interface or @interface definition. 514 * 515 * @param variableDefAst variable definition. 516 * @return true if variable definition(variableDefAst) is in interface 517 * or @interface definition. 518 */ 519 private static boolean isInterfaceDeclaration(DetailAST variableDefAst) { 520 boolean result = false; 521 final DetailAST astBlock = variableDefAst.getParent(); 522 final DetailAST astParent2 = astBlock.getParent(); 523 524 if (astParent2.getType() == TokenTypes.INTERFACE_DEF 525 || astParent2.getType() == TokenTypes.ANNOTATION_DEF) { 526 result = true; 527 } 528 return result; 529 } 530 531 /** 532 * Checks that the method has "@Override" annotation. 533 * 534 * @param methodModifiersAST 535 * A DetailAST nod is related to the given method modifiers 536 * (MODIFIERS type). 537 * @return true if method has "@Override" annotation. 538 */ 539 private static boolean hasOverrideAnnotation(DetailAST methodModifiersAST) { 540 boolean result = false; 541 for (DetailAST child : getChildren(methodModifiersAST)) { 542 final DetailAST annotationIdent = child.findFirstToken(TokenTypes.IDENT); 543 544 if (annotationIdent != null && "Override".equals(annotationIdent.getText())) { 545 result = true; 546 break; 547 } 548 } 549 return result; 550 } 551 552 /** 553 * Gets the disallowed abbreviation contained in given String. 554 * 555 * @param str 556 * the given String. 557 * @return the disallowed abbreviation contained in given String as a 558 * separate String. 559 */ 560 private String getDisallowedAbbreviation(String str) { 561 int beginIndex = 0; 562 boolean abbrStarted = false; 563 String result = null; 564 565 for (int index = 0; index < str.length(); index++) { 566 final char symbol = str.charAt(index); 567 568 if (Character.isUpperCase(symbol)) { 569 if (!abbrStarted) { 570 abbrStarted = true; 571 beginIndex = index; 572 } 573 } 574 else if (abbrStarted) { 575 abbrStarted = false; 576 577 final int endIndex = index - 1; 578 result = getAbbreviationIfIllegal(str, beginIndex, endIndex); 579 if (result != null) { 580 break; 581 } 582 beginIndex = -1; 583 } 584 } 585 // if abbreviation at the end of name (example: scaleX) 586 if (abbrStarted) { 587 final int endIndex = str.length() - 1; 588 result = getAbbreviationIfIllegal(str, beginIndex, endIndex); 589 } 590 return result; 591 } 592 593 /** 594 * Get Abbreviation if it is illegal, where {@code beginIndex} and {@code endIndex} are 595 * inclusive indexes of a sequence of consecutive upper-case characters. 596 * 597 * @param str name 598 * @param beginIndex begin index 599 * @param endIndex end index 600 * @return the abbreviation if it is bigger than required and not in the 601 * ignore list, otherwise {@code null} 602 */ 603 private String getAbbreviationIfIllegal(String str, int beginIndex, int endIndex) { 604 String result = null; 605 final int abbrLength = endIndex - beginIndex; 606 if (abbrLength > allowedAbbreviationLength) { 607 final String abbr = getAbbreviation(str, beginIndex, endIndex); 608 if (!allowedAbbreviations.contains(abbr)) { 609 result = abbr; 610 } 611 } 612 return result; 613 } 614 615 /** 616 * Gets the abbreviation, where {@code beginIndex} and {@code endIndex} are 617 * inclusive indexes of a sequence of consecutive upper-case characters. 618 * <p> 619 * The character at {@code endIndex} is only included in the abbreviation if 620 * it is the last character in the string; otherwise it is usually the first 621 * capital in the next word. 622 * </p> 623 * <p> 624 * For example, {@code getAbbreviation("getXMLParser", 3, 6)} returns "XML" 625 * (not "XMLP"), and so does {@code getAbbreviation("parseXML", 5, 7)}. 626 * </p> 627 * 628 * @param str name 629 * @param beginIndex begin index 630 * @param endIndex end index 631 * @return the specified abbreviation 632 */ 633 private static String getAbbreviation(String str, int beginIndex, int endIndex) { 634 final String result; 635 if (endIndex == str.length() - 1) { 636 result = str.substring(beginIndex); 637 } 638 else { 639 result = str.substring(beginIndex, endIndex); 640 } 641 return result; 642 } 643 644 /** 645 * Gets all the children which are one level below on the current DetailAST 646 * parent node. 647 * 648 * @param node 649 * Current parent node. 650 * @return The list of children one level below on the current parent node. 651 */ 652 private static List<DetailAST> getChildren(final DetailAST node) { 653 final List<DetailAST> result = new LinkedList<>(); 654 DetailAST curNode = node.getFirstChild(); 655 while (curNode != null) { 656 result.add(curNode); 657 curNode = curNode.getNextSibling(); 658 } 659 return result; 660 } 661 662}