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