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