001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2025 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.coding; 021 022import java.util.BitSet; 023import java.util.Collections; 024import java.util.HashSet; 025import java.util.Set; 026import java.util.regex.Pattern; 027 028import com.puppycrawl.tools.checkstyle.FileStatefulCheck; 029import com.puppycrawl.tools.checkstyle.PropertyType; 030import com.puppycrawl.tools.checkstyle.XdocsPropertyType; 031import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 032import com.puppycrawl.tools.checkstyle.api.DetailAST; 033import com.puppycrawl.tools.checkstyle.api.FullIdent; 034import com.puppycrawl.tools.checkstyle.api.TokenTypes; 035import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil; 036import com.puppycrawl.tools.checkstyle.utils.TokenUtil; 037 038/** 039 * <div> 040 * Checks that particular classes or interfaces are never used. 041 * </div> 042 * 043 * <p> 044 * Rationale: Helps reduce coupling on concrete classes. 045 * </p> 046 * 047 * <p> 048 * For additional restriction of type usage see also: 049 * <a href="https://checkstyle.org/checks/coding/illegalinstantiation.html#IllegalInstantiation"> 050 * IllegalInstantiation</a>, 051 * <a href="https://checkstyle.org/checks/imports/illegalimport.html#IllegalImport"> 052 * IllegalImport</a> 053 * </p> 054 * 055 * <p> 056 * It is possible to set illegal class names via short or 057 * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7">canonical</a> 058 * name. Specifying illegal type invokes analyzing imports and Check puts violations at 059 * corresponding declarations (of variables, methods or parameters). 060 * This helps to avoid ambiguous cases, e.g.: {@code java.awt.List} was set as 061 * illegal class name, then, code like: 062 * </p> 063 * <pre> 064 * import java.util.List; 065 * ... 066 * List list; //No violation here 067 * </pre> 068 * 069 * <p> 070 * will be ok. 071 * </p> 072 * 073 * <p> 074 * In most cases it's justified to put following classes to <b>illegalClassNames</b>: 075 * </p> 076 * <ul> 077 * <li>GregorianCalendar</li> 078 * <li>Hashtable</li> 079 * <li>ArrayList</li> 080 * <li>LinkedList</li> 081 * <li>Vector</li> 082 * </ul> 083 * 084 * <p> 085 * as methods that are differ from interface methods are rarely used, so in most cases user will 086 * benefit from checking for them. 087 * </p> 088 * <ul> 089 * <li> 090 * Property {@code ignoredMethodNames} - Specify methods that should not be checked. 091 * Type is {@code java.lang.String[]}. 092 * Default value is {@code getEnvironment, getInitialContext}. 093 * </li> 094 * <li> 095 * Property {@code illegalAbstractClassNameFormat} - Specify RegExp for illegal abstract class 096 * names. 097 * Type is {@code java.util.regex.Pattern}. 098 * Default value is {@code "^(.*[.])?Abstract.*$"}. 099 * </li> 100 * <li> 101 * Property {@code illegalClassNames} - Specify classes that should not be used 102 * as types in variable declarations, return values or parameters. 103 * Type is {@code java.lang.String[]}. 104 * Default value is {@code HashMap, HashSet, LinkedHashMap, LinkedHashSet, TreeMap, 105 * TreeSet, java.util.HashMap, java.util.HashSet, java.util.LinkedHashMap, 106 * java.util.LinkedHashSet, java.util.TreeMap, java.util.TreeSet}. 107 * </li> 108 * <li> 109 * Property {@code legalAbstractClassNames} - Define abstract classes that may be used as types. 110 * Type is {@code java.lang.String[]}. 111 * Default value is {@code ""}. 112 * </li> 113 * <li> 114 * Property {@code memberModifiers} - Control whether to check only methods and fields with any 115 * of the specified modifiers. 116 * This property does not affect method calls nor method references nor record components. 117 * Type is {@code java.lang.String[]}. 118 * Validation type is {@code tokenTypesSet}. 119 * Default value is {@code ""}. 120 * </li> 121 * <li> 122 * Property {@code validateAbstractClassNames} - Control whether to validate abstract class names. 123 * Type is {@code boolean}. 124 * Default value is {@code false}. 125 * </li> 126 * <li> 127 * Property {@code tokens} - tokens to check 128 * Type is {@code java.lang.String[]}. 129 * Validation type is {@code tokenSet}. 130 * Default value is: 131 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_FIELD_DEF"> 132 * ANNOTATION_FIELD_DEF</a>, 133 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 134 * CLASS_DEF</a>, 135 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 136 * INTERFACE_DEF</a>, 137 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_CALL"> 138 * METHOD_CALL</a>, 139 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 140 * METHOD_DEF</a>, 141 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_REF"> 142 * METHOD_REF</a>, 143 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PARAMETER_DEF"> 144 * PARAMETER_DEF</a>, 145 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF"> 146 * VARIABLE_DEF</a>, 147 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PATTERN_VARIABLE_DEF"> 148 * PATTERN_VARIABLE_DEF</a>, 149 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF"> 150 * RECORD_DEF</a>, 151 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_COMPONENT_DEF"> 152 * RECORD_COMPONENT_DEF</a>, 153 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_PATTERN_DEF"> 154 * RECORD_PATTERN_DEF</a>. 155 * </li> 156 * </ul> 157 * 158 * <p> 159 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 160 * </p> 161 * 162 * <p> 163 * Violation Message Keys: 164 * </p> 165 * <ul> 166 * <li> 167 * {@code illegal.type} 168 * </li> 169 * </ul> 170 * 171 * @since 3.2 172 * 173 */ 174@FileStatefulCheck 175public final class IllegalTypeCheck extends AbstractCheck { 176 177 /** 178 * A key is pointing to the warning message text in "messages.properties" 179 * file. 180 */ 181 public static final String MSG_KEY = "illegal.type"; 182 183 /** Types illegal by default. */ 184 private static final String[] DEFAULT_ILLEGAL_TYPES = { 185 "HashSet", 186 "HashMap", 187 "LinkedHashMap", 188 "LinkedHashSet", 189 "TreeSet", 190 "TreeMap", 191 "java.util.HashSet", 192 "java.util.HashMap", 193 "java.util.LinkedHashMap", 194 "java.util.LinkedHashSet", 195 "java.util.TreeSet", 196 "java.util.TreeMap", 197 }; 198 199 /** Default ignored method names. */ 200 private static final String[] DEFAULT_IGNORED_METHOD_NAMES = { 201 "getInitialContext", 202 "getEnvironment", 203 }; 204 205 /** 206 * Specify classes that should not be used as types in variable declarations, 207 * return values or parameters. 208 */ 209 private final Set<String> illegalClassNames = new HashSet<>(); 210 /** Illegal short classes. */ 211 private final Set<String> illegalShortClassNames = new HashSet<>(); 212 /** Define abstract classes that may be used as types. */ 213 private final Set<String> legalAbstractClassNames = new HashSet<>(); 214 /** Specify methods that should not be checked. */ 215 private final Set<String> ignoredMethodNames = new HashSet<>(); 216 /** 217 * Control whether to check only methods and fields with any of the specified modifiers. 218 * This property does not affect method calls nor method references nor record components. 219 */ 220 @XdocsPropertyType(PropertyType.TOKEN_ARRAY) 221 private BitSet memberModifiers = new BitSet(); 222 223 /** Specify RegExp for illegal abstract class names. */ 224 private Pattern illegalAbstractClassNameFormat = Pattern.compile("^(.*[.])?Abstract.*$"); 225 226 /** 227 * Control whether to validate abstract class names. 228 */ 229 private boolean validateAbstractClassNames; 230 231 /** Creates new instance of the check. */ 232 public IllegalTypeCheck() { 233 setIllegalClassNames(DEFAULT_ILLEGAL_TYPES); 234 setIgnoredMethodNames(DEFAULT_IGNORED_METHOD_NAMES); 235 } 236 237 /** 238 * Setter to specify RegExp for illegal abstract class names. 239 * 240 * @param pattern a pattern. 241 * @since 3.2 242 */ 243 public void setIllegalAbstractClassNameFormat(Pattern pattern) { 244 illegalAbstractClassNameFormat = pattern; 245 } 246 247 /** 248 * Setter to control whether to validate abstract class names. 249 * 250 * @param validateAbstractClassNames whether abstract class names must be ignored. 251 * @since 6.10 252 */ 253 public void setValidateAbstractClassNames(boolean validateAbstractClassNames) { 254 this.validateAbstractClassNames = validateAbstractClassNames; 255 } 256 257 @Override 258 public int[] getDefaultTokens() { 259 return getAcceptableTokens(); 260 } 261 262 @Override 263 public int[] getAcceptableTokens() { 264 return new int[] { 265 TokenTypes.ANNOTATION_FIELD_DEF, 266 TokenTypes.CLASS_DEF, 267 TokenTypes.IMPORT, 268 TokenTypes.INTERFACE_DEF, 269 TokenTypes.METHOD_CALL, 270 TokenTypes.METHOD_DEF, 271 TokenTypes.METHOD_REF, 272 TokenTypes.PARAMETER_DEF, 273 TokenTypes.VARIABLE_DEF, 274 TokenTypes.PATTERN_VARIABLE_DEF, 275 TokenTypes.RECORD_DEF, 276 TokenTypes.RECORD_COMPONENT_DEF, 277 TokenTypes.RECORD_PATTERN_DEF, 278 }; 279 } 280 281 @Override 282 public void beginTree(DetailAST rootAST) { 283 illegalShortClassNames.clear(); 284 illegalShortClassNames.addAll(illegalClassNames); 285 } 286 287 @Override 288 public int[] getRequiredTokens() { 289 return new int[] {TokenTypes.IMPORT}; 290 } 291 292 @Override 293 public void visitToken(DetailAST ast) { 294 switch (ast.getType()) { 295 case TokenTypes.CLASS_DEF: 296 case TokenTypes.INTERFACE_DEF: 297 case TokenTypes.RECORD_DEF: 298 visitTypeDef(ast); 299 break; 300 case TokenTypes.METHOD_CALL: 301 case TokenTypes.METHOD_REF: 302 visitMethodCallOrRef(ast); 303 break; 304 case TokenTypes.METHOD_DEF: 305 visitMethodDef(ast); 306 break; 307 case TokenTypes.VARIABLE_DEF: 308 case TokenTypes.ANNOTATION_FIELD_DEF: 309 case TokenTypes.PATTERN_VARIABLE_DEF: 310 visitVariableDef(ast); 311 break; 312 case TokenTypes.RECORD_COMPONENT_DEF: 313 case TokenTypes.RECORD_PATTERN_DEF: 314 checkClassName(ast); 315 break; 316 case TokenTypes.PARAMETER_DEF: 317 visitParameterDef(ast); 318 break; 319 case TokenTypes.IMPORT: 320 visitImport(ast); 321 break; 322 default: 323 throw new IllegalStateException(ast.toString()); 324 } 325 } 326 327 /** 328 * Checks if current method's return type or variable's type is verifiable 329 * according to <b>memberModifiers</b> option. 330 * 331 * @param methodOrVariableDef METHOD_DEF or VARIABLE_DEF ast node. 332 * @return true if member is verifiable according to <b>memberModifiers</b> option. 333 */ 334 private boolean isVerifiable(DetailAST methodOrVariableDef) { 335 boolean result = true; 336 if (!memberModifiers.isEmpty()) { 337 final DetailAST modifiersAst = methodOrVariableDef 338 .findFirstToken(TokenTypes.MODIFIERS); 339 result = isContainVerifiableType(modifiersAst); 340 } 341 return result; 342 } 343 344 /** 345 * Checks is modifiers contain verifiable type. 346 * 347 * @param modifiers 348 * parent node for all modifiers 349 * @return true if method or variable can be verified 350 */ 351 private boolean isContainVerifiableType(DetailAST modifiers) { 352 boolean result = false; 353 for (DetailAST modifier = modifiers.getFirstChild(); modifier != null; 354 modifier = modifier.getNextSibling()) { 355 if (memberModifiers.get(modifier.getType())) { 356 result = true; 357 break; 358 } 359 } 360 return result; 361 } 362 363 /** 364 * Checks the super type and implemented interfaces of a given type. 365 * 366 * @param typeDef class or interface for check. 367 */ 368 private void visitTypeDef(DetailAST typeDef) { 369 if (isVerifiable(typeDef)) { 370 checkTypeParameters(typeDef); 371 final DetailAST extendsClause = typeDef.findFirstToken(TokenTypes.EXTENDS_CLAUSE); 372 if (extendsClause != null) { 373 checkBaseTypes(extendsClause); 374 } 375 final DetailAST implementsClause = typeDef.findFirstToken(TokenTypes.IMPLEMENTS_CLAUSE); 376 if (implementsClause != null) { 377 checkBaseTypes(implementsClause); 378 } 379 } 380 } 381 382 /** 383 * Checks return type of a given method. 384 * 385 * @param methodDef method for check. 386 */ 387 private void visitMethodDef(DetailAST methodDef) { 388 if (isCheckedMethod(methodDef)) { 389 checkClassName(methodDef); 390 } 391 } 392 393 /** 394 * Checks type of parameters. 395 * 396 * @param parameterDef parameter list for check. 397 */ 398 private void visitParameterDef(DetailAST parameterDef) { 399 final DetailAST grandParentAST = parameterDef.getParent().getParent(); 400 401 if (grandParentAST.getType() == TokenTypes.METHOD_DEF && isCheckedMethod(grandParentAST)) { 402 checkClassName(parameterDef); 403 } 404 } 405 406 /** 407 * Checks type of given variable. 408 * 409 * @param variableDef variable to check. 410 */ 411 private void visitVariableDef(DetailAST variableDef) { 412 if (isVerifiable(variableDef)) { 413 checkClassName(variableDef); 414 } 415 } 416 417 /** 418 * Checks the type arguments of given method call/reference. 419 * 420 * @param methodCallOrRef method call/reference to check. 421 */ 422 private void visitMethodCallOrRef(DetailAST methodCallOrRef) { 423 checkTypeArguments(methodCallOrRef); 424 } 425 426 /** 427 * Checks imported type (as static and star imports are not supported by Check, 428 * only type is in the consideration).<br> 429 * If this type is illegal due to Check's options - puts violation on it. 430 * 431 * @param importAst {@link TokenTypes#IMPORT Import} 432 */ 433 private void visitImport(DetailAST importAst) { 434 if (!isStarImport(importAst)) { 435 final String canonicalName = getImportedTypeCanonicalName(importAst); 436 extendIllegalClassNamesWithShortName(canonicalName); 437 } 438 } 439 440 /** 441 * Checks if current import is star import. E.g.: 442 * 443 * <p> 444 * {@code 445 * import java.util.*; 446 * } 447 * </p> 448 * 449 * @param importAst {@link TokenTypes#IMPORT Import} 450 * @return true if it is star import 451 */ 452 private static boolean isStarImport(DetailAST importAst) { 453 boolean result = false; 454 DetailAST toVisit = importAst; 455 while (toVisit != null) { 456 toVisit = getNextSubTreeNode(toVisit, importAst); 457 if (toVisit != null && toVisit.getType() == TokenTypes.STAR) { 458 result = true; 459 break; 460 } 461 } 462 return result; 463 } 464 465 /** 466 * Checks type and type arguments/parameters of given method, parameter, variable or 467 * method call/reference. 468 * 469 * @param ast node to check. 470 */ 471 private void checkClassName(DetailAST ast) { 472 final DetailAST type = ast.findFirstToken(TokenTypes.TYPE); 473 checkType(type); 474 checkTypeParameters(ast); 475 } 476 477 /** 478 * Checks the identifier of the given type. 479 * 480 * @param type node to check. 481 */ 482 private void checkIdent(DetailAST type) { 483 final FullIdent ident = FullIdent.createFullIdent(type); 484 if (isMatchingClassName(ident.getText())) { 485 log(ident.getDetailAst(), MSG_KEY, ident.getText()); 486 } 487 } 488 489 /** 490 * Checks the {@code extends} or {@code implements} statement. 491 * 492 * @param clause DetailAST for either {@link TokenTypes#EXTENDS_CLAUSE} or 493 * {@link TokenTypes#IMPLEMENTS_CLAUSE} 494 */ 495 private void checkBaseTypes(DetailAST clause) { 496 DetailAST child = clause.getFirstChild(); 497 while (child != null) { 498 if (child.getType() == TokenTypes.IDENT) { 499 checkIdent(child); 500 } 501 else { 502 TokenUtil.forEachChild(child, TokenTypes.TYPE_ARGUMENT, this::checkType); 503 } 504 child = child.getNextSibling(); 505 } 506 } 507 508 /** 509 * Checks the given type, its arguments and parameters. 510 * 511 * @param type node to check. 512 */ 513 private void checkType(DetailAST type) { 514 checkIdent(type.getFirstChild()); 515 checkTypeArguments(type); 516 checkTypeBounds(type); 517 } 518 519 /** 520 * Checks the upper and lower bounds for the given type. 521 * 522 * @param type node to check. 523 */ 524 private void checkTypeBounds(DetailAST type) { 525 final DetailAST upperBounds = type.findFirstToken(TokenTypes.TYPE_UPPER_BOUNDS); 526 if (upperBounds != null) { 527 checkType(upperBounds); 528 } 529 final DetailAST lowerBounds = type.findFirstToken(TokenTypes.TYPE_LOWER_BOUNDS); 530 if (lowerBounds != null) { 531 checkType(lowerBounds); 532 } 533 } 534 535 /** 536 * Checks the type parameters of the node. 537 * 538 * @param node node to check. 539 */ 540 private void checkTypeParameters(final DetailAST node) { 541 final DetailAST typeParameters = node.findFirstToken(TokenTypes.TYPE_PARAMETERS); 542 if (typeParameters != null) { 543 TokenUtil.forEachChild(typeParameters, TokenTypes.TYPE_PARAMETER, this::checkType); 544 } 545 } 546 547 /** 548 * Checks the type arguments of the node. 549 * 550 * @param node node to check. 551 */ 552 private void checkTypeArguments(final DetailAST node) { 553 DetailAST typeArguments = node.findFirstToken(TokenTypes.TYPE_ARGUMENTS); 554 if (typeArguments == null) { 555 typeArguments = node.getFirstChild().findFirstToken(TokenTypes.TYPE_ARGUMENTS); 556 } 557 558 if (typeArguments != null) { 559 TokenUtil.forEachChild(typeArguments, TokenTypes.TYPE_ARGUMENT, this::checkType); 560 } 561 } 562 563 /** 564 * Returns true if given class name is one of illegal classes or else false. 565 * 566 * @param className class name to check. 567 * @return true if given class name is one of illegal classes 568 * or if it matches to abstract class names pattern. 569 */ 570 private boolean isMatchingClassName(String className) { 571 final String shortName = className.substring(className.lastIndexOf('.') + 1); 572 return illegalClassNames.contains(className) 573 || illegalShortClassNames.contains(shortName) 574 || validateAbstractClassNames 575 && !legalAbstractClassNames.contains(className) 576 && illegalAbstractClassNameFormat.matcher(className).find(); 577 } 578 579 /** 580 * Extends illegal class names set via imported short type name. 581 * 582 * @param canonicalName 583 * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.7"> 584 * Canonical</a> name of imported type. 585 */ 586 private void extendIllegalClassNamesWithShortName(String canonicalName) { 587 if (illegalClassNames.contains(canonicalName)) { 588 final String shortName = canonicalName 589 .substring(canonicalName.lastIndexOf('.') + 1); 590 illegalShortClassNames.add(shortName); 591 } 592 } 593 594 /** 595 * Gets imported type's 596 * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.7"> 597 * canonical name</a>. 598 * 599 * @param importAst {@link TokenTypes#IMPORT Import} 600 * @return Imported canonical type's name. 601 */ 602 private static String getImportedTypeCanonicalName(DetailAST importAst) { 603 final StringBuilder canonicalNameBuilder = new StringBuilder(256); 604 DetailAST toVisit = importAst; 605 while (toVisit != null) { 606 toVisit = getNextSubTreeNode(toVisit, importAst); 607 if (toVisit != null && toVisit.getType() == TokenTypes.IDENT) { 608 if (canonicalNameBuilder.length() > 0) { 609 canonicalNameBuilder.append('.'); 610 } 611 canonicalNameBuilder.append(toVisit.getText()); 612 } 613 } 614 return canonicalNameBuilder.toString(); 615 } 616 617 /** 618 * Gets the next node of a syntactical tree (child of a current node or 619 * sibling of a current node, or sibling of a parent of a current node). 620 * 621 * @param currentNodeAst Current node in considering 622 * @param subTreeRootAst SubTree root 623 * @return Current node after bypassing, if current node reached the root of a subtree 624 * method returns null 625 */ 626 private static DetailAST 627 getNextSubTreeNode(DetailAST currentNodeAst, DetailAST subTreeRootAst) { 628 DetailAST currentNode = currentNodeAst; 629 DetailAST toVisitAst = currentNode.getFirstChild(); 630 while (toVisitAst == null) { 631 toVisitAst = currentNode.getNextSibling(); 632 if (currentNode.getParent().equals(subTreeRootAst)) { 633 break; 634 } 635 currentNode = currentNode.getParent(); 636 } 637 return toVisitAst; 638 } 639 640 /** 641 * Returns true if method has to be checked or false. 642 * 643 * @param ast method def to check. 644 * @return true if we should check this method. 645 */ 646 private boolean isCheckedMethod(DetailAST ast) { 647 final String methodName = 648 ast.findFirstToken(TokenTypes.IDENT).getText(); 649 return isVerifiable(ast) && !ignoredMethodNames.contains(methodName) 650 && !AnnotationUtil.hasOverrideAnnotation(ast); 651 } 652 653 /** 654 * Setter to specify classes that should not be used as types in variable declarations, 655 * return values or parameters. 656 * 657 * @param classNames array of illegal variable types 658 * @noinspection WeakerAccess 659 * @noinspectionreason WeakerAccess - we avoid 'protected' when possible 660 * @since 3.2 661 */ 662 public void setIllegalClassNames(String... classNames) { 663 illegalClassNames.clear(); 664 Collections.addAll(illegalClassNames, classNames); 665 } 666 667 /** 668 * Setter to specify methods that should not be checked. 669 * 670 * @param methodNames array of ignored method names 671 * @noinspection WeakerAccess 672 * @noinspectionreason WeakerAccess - we avoid 'protected' when possible 673 * @since 3.2 674 */ 675 public void setIgnoredMethodNames(String... methodNames) { 676 ignoredMethodNames.clear(); 677 Collections.addAll(ignoredMethodNames, methodNames); 678 } 679 680 /** 681 * Setter to define abstract classes that may be used as types. 682 * 683 * @param classNames array of legal abstract class names 684 * @noinspection WeakerAccess 685 * @noinspectionreason WeakerAccess - we avoid 'protected' when possible 686 * @since 4.2 687 */ 688 public void setLegalAbstractClassNames(String... classNames) { 689 Collections.addAll(legalAbstractClassNames, classNames); 690 } 691 692 /** 693 * Setter to control whether to check only methods and fields with any of 694 * the specified modifiers. 695 * This property does not affect method calls nor method references nor record components. 696 * 697 * @param modifiers String contains modifiers. 698 * @since 6.3 699 */ 700 public void setMemberModifiers(String modifiers) { 701 memberModifiers = TokenUtil.asBitSet(modifiers.split(",")); 702 } 703 704}