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.filters; 021 022import java.util.Collections; 023import java.util.HashSet; 024import java.util.Objects; 025import java.util.Set; 026 027import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; 028import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; 029import com.puppycrawl.tools.checkstyle.api.AutomaticBean; 030import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 031import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; 032import com.puppycrawl.tools.checkstyle.utils.FilterUtil; 033 034/** 035 * <p> 036 * Filter {@code SuppressionXpathFilter} works as 037 * <a href="https://checkstyle.org/config_filters.html#SuppressionFilter">SuppressionFilter</a>. 038 * Additionally, filter processes {@code suppress-xpath} elements, 039 * which contains xpath-expressions. Xpath-expressions are queries for 040 * suppressed nodes inside the AST tree. 041 * </p> 042 * <p> 043 * Currently, filter does not support the following checks: 044 * </p> 045 * <ul id="SuppressionXpathFilter_IncompatibleChecks"> 046 * <li> 047 * AnnotationLocation 048 * </li> 049 * <li> 050 * AnnotationOnSameLine 051 * </li> 052 * <li> 053 * AnnotationUseStyle 054 * </li> 055 * <li> 056 * ArrayTrailingComma 057 * </li> 058 * <li> 059 * AvoidEscapedUnicodeCharacters 060 * </li> 061 * <li> 062 * AvoidStarImport 063 * </li> 064 * <li> 065 * AvoidStaticImport 066 * </li> 067 * <li> 068 * CommentsIndentation 069 * </li> 070 * <li> 071 * CustomImportOrder 072 * </li> 073 * <li> 074 * EmptyCatchBlock 075 * </li> 076 * <li> 077 * EmptyLineSeparator 078 * </li> 079 * <li> 080 * FinalClass 081 * </li> 082 * <li> 083 * IllegalCatch 084 * </li> 085 * <li> 086 * ImportOrder 087 * </li> 088 * <li> 089 * Indentation 090 * </li> 091 * <li> 092 * InterfaceIsType 093 * </li> 094 * <li> 095 * InterfaceMemberImpliedModifier 096 * </li> 097 * <li> 098 * InvalidJavadocPosition 099 * </li> 100 * <li> 101 * JavadocContentLocation 102 * </li> 103 * <li> 104 * JavadocMethod 105 * </li> 106 * <li> 107 * JavadocStyle 108 * </li> 109 * <li> 110 * JavadocType 111 * </li> 112 * <li> 113 * LambdaParameterName 114 * </li> 115 * <li> 116 * MethodCount 117 * </li> 118 * <li> 119 * MissingCtor 120 * </li> 121 * <li> 122 * MissingJavadocMethod 123 * </li> 124 * <li> 125 * MissingJavadocPackage 126 * </li> 127 * <li> 128 * MissingJavadocType 129 * </li> 130 * <li> 131 * MissingOverride 132 * </li> 133 * <li> 134 * MissingSwitchDefault 135 * </li> 136 * <li> 137 * NeedBraces 138 * </li> 139 * <li> 140 * NoClone 141 * </li> 142 * <li> 143 * NoFinalizer 144 * </li> 145 * <li> 146 * NoLineWrap 147 * </li> 148 * <li> 149 * OneTopLevelClass 150 * </li> 151 * <li> 152 * OuterTypeFilename 153 * </li> 154 * <li> 155 * OverloadMethodsDeclarationOrder 156 * </li> 157 * <li> 158 * PackageAnnotation 159 * </li> 160 * <li> 161 * PackageDeclaration 162 * </li> 163 * <li> 164 * Regexp 165 * </li> 166 * <li> 167 * RegexpSinglelineJava 168 * </li> 169 * <li> 170 * SuppressWarningsHolder 171 * </li> 172 * <li> 173 * TodoComment 174 * </li> 175 * <li> 176 * TrailingComment 177 * </li> 178 * <li> 179 * UncommentedMain 180 * </li> 181 * <li> 182 * UnnecessaryParentheses 183 * </li> 184 * <li> 185 * VariableDeclarationUsageDistance 186 * </li> 187 * <li> 188 * WriteTag 189 * </li> 190 * </ul> 191 * <p> 192 * Also, the filter does not support Javadoc checks: 193 * </p> 194 * <ul id="SuppressionXpathFilter_JavadocChecks"> 195 * <li> 196 * AtclauseOrder 197 * </li> 198 * <li> 199 * JavadocBlockTagLocation 200 * </li> 201 * <li> 202 * JavadocParagraph 203 * </li> 204 * <li> 205 * JavadocTagContinuationIndentation 206 * </li> 207 * <li> 208 * MissingDeprecated 209 * </li> 210 * <li> 211 * NonEmptyAtclauseDescription 212 * </li> 213 * <li> 214 * SingleLineJavadoc 215 * </li> 216 * <li> 217 * SummaryJavadoc 218 * </li> 219 * </ul> 220 * <p> 221 * Note, that support for these Checks will be available after resolving issues 222 * <a href="https://github.com/checkstyle/checkstyle/issues/5770">#5770</a> and 223 * <a href="https://github.com/checkstyle/checkstyle/issues/5777">#5777</a>. 224 * </p> 225 * <p> 226 * Currently, filter supports the following xpath axes: 227 * </p> 228 * <ul> 229 * <li> 230 * ancestor 231 * </li> 232 * <li> 233 * ancestor-or-self 234 * </li> 235 * <li> 236 * attribute 237 * </li> 238 * <li> 239 * child 240 * </li> 241 * <li> 242 * descendant 243 * </li> 244 * <li> 245 * descendant-or-self 246 * </li> 247 * <li> 248 * following 249 * </li> 250 * <li> 251 * following-sibling 252 * </li> 253 * <li> 254 * parent 255 * </li> 256 * <li> 257 * preceding 258 * </li> 259 * <li> 260 * preceding-sibling 261 * </li> 262 * <li> 263 * self 264 * </li> 265 * </ul> 266 * <p> 267 * You can use the command line helper tool to generate xpath suppressions based on your 268 * configuration file and input files. See <a href="https://checkstyle.org/cmdline.html">here</a> 269 * for more details. 270 * </p> 271 * <p> 272 * The suppression file location is checked in following order: 273 * </p> 274 * <ol> 275 * <li> 276 * as a filesystem location 277 * </li> 278 * <li> 279 * if no file found, and the location starts with either {@code http://} or {@code https://}, 280 * then it is interpreted as a URL 281 * </li> 282 * <li> 283 * if no file found, then passed to the {@code ClassLoader.getResource()} method. 284 * </li> 285 * </ol> 286 * <ul> 287 * <li> 288 * Property {@code file} - Specify the location of the <em>suppressions XML document</em> file. 289 * Default value is {@code null}. 290 * </li> 291 * <li> 292 * Property {@code optional} - Control what to do when the file is not existing. 293 * If optional is set to false the file must exist, or else it ends with error. 294 * On the other hand if optional is true and file is not found, the filter accepts all audit events. 295 * Default value is {@code false}. 296 * </li> 297 * </ul> 298 * <p> 299 * For example, the following configuration fragment directs the Checker to use a 300 * {@code SuppressionXpathFilter} with suppressions file {@code config/suppressions.xml}: 301 * </p> 302 * <pre> 303 * <module name="SuppressionXpathFilter"> 304 * <property name="file" value="config/suppressions.xml"/> 305 * <property name="optional" value="false"/> 306 * </module> 307 * </pre> 308 * <p> 309 * A <a href="https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd"><em> 310 * suppressions XML document</em></a> 311 * contains a set of {@code suppress} and {@code suppress-xpath} elements, 312 * where each {@code suppress-xpath} element can have the following attributes: 313 * </p> 314 * <ul> 315 * <li> 316 * {@code files} - a <a href="https://checkstyle.org/property_types.html#regexp">Regular Expression</a> 317 * matched against the file name associated with an audit event. It is optional. 318 * </li> 319 * <li> 320 * {@code checks} - a <a href="https://checkstyle.org/property_types.html#regexp">Regular Expression</a> 321 * matched against the name of the check associated with an audit event. 322 * Optional as long as {@code id} or {@code message} is specified. 323 * </li> 324 * <li> 325 * {@code message} - a <a href="https://checkstyle.org/property_types.html#regexp">Regular Expression</a> 326 * matched against the message of the check associated with an audit event. 327 * Optional as long as {@code checks} or {@code id} is specified. 328 * </li> 329 * <li> 330 * {@code id} - a <a href="https://checkstyle.org/property_types.html#string">string</a> matched against 331 * the ID of the check associated with an audit event. 332 * Optional as long as {@code checks} or {@code message} is specified. 333 * </li> 334 * <li> 335 * {@code query} - a <a href="https://checkstyle.org/property_types.html#string">string</a> xpath query. It is optional. 336 * </li> 337 * </ul> 338 * <p> 339 * Each audit event is checked against each {@code suppress} and {@code suppress-xpath} element. 340 * It is suppressed if all specified attributes match against the audit event. 341 * </p> 342 * <p> 343 * ATTENTION: filtering by message is dependant on runtime locale. 344 * If project is running in different languages it is better to avoid filtering by message. 345 * </p> 346 * <p> 347 * The following suppressions XML document directs a {@code SuppressionXpathFilter} to reject 348 * {@code CyclomaticComplexity} violations for all methods with name <i>sayHelloWorld</i> inside 349 * <i>FileOne</i> and <i>FileTwo</i> files: 350 * </p> 351 * <p> 352 * Currently, xpath queries support one type of attribute {@code @text}. {@code @text} - 353 * addresses to the text value of the node. For example: variable name, annotation name, 354 * text content and etc. Only the following token types support {@code @text} attribute: 355 * {@code TokenTypes.IDENT}, {@code TokenTypes.STRING_LITERAL}, {@code TokenTypes.CHAR_LITERAL}, 356 * {@code TokenTypes.NUM_LONG}, {@code TokenTypes.NUM_INT}, {@code TokenTypes.NUM_DOUBLE}, 357 * {@code TokenTypes.NUM_FLOAT}. 358 * These token types were selected because only their text values are different 359 * in content from token type and represent text value from file and can be used 360 * in xpath queries for more accurate results. Other token types always have constant values. 361 * </p> 362 * <pre> 363 * <?xml version="1.0"?> 364 * 365 * <!DOCTYPE suppressions PUBLIC 366 * "-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2//EN" 367 * "https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd"> 368 * 369 * <suppressions> 370 * <suppress-xpath checks="CyclomaticComplexity" 371 * files="FileOne.java,FileTwo.java" 372 * query="//METHOD_DEF[./IDENT[@text='sayHelloWorld']]"/> 373 * </suppressions> 374 * </pre> 375 * <p> 376 * Suppress checks for package definitions: 377 * </p> 378 * <pre> 379 * <suppress-xpath checks=".*" query="/PACKAGE_DEF"/> 380 * </pre> 381 * <p> 382 * Suppress checks for parent element of the first variable definition: 383 * </p> 384 * <pre> 385 * <suppress-xpath checks=".*" query="(//VARIABLE_DEF)[1]/.."/> 386 * </pre> 387 * <p> 388 * Suppress checks for elements which are either class definitions, either method definitions. 389 * </p> 390 * <pre> 391 * <suppress-xpath checks=".*" query="//CLASS_DEF | //METHOD_DEF"/> 392 * </pre> 393 * <p> 394 * Suppress checks for certain methods: 395 * </p> 396 * <pre> 397 * <suppress-xpath checks=".*" query="//METHOD_DEF[./IDENT[@text='getSomeVar' 398 * or @text='setSomeVar']]"/> 399 * </pre> 400 * <p> 401 * Suppress checks for variable <i>testVariable</i> inside <i>testMethod</i> 402 * method inside <i>TestClass</i> class. 403 * </p> 404 * <pre> 405 * <suppress-xpath checks=".*" query="/CLASS_DEF[@text='TestClass'] 406 * //METHOD_DEF[./IDENT[@text='testMethod']] 407 * //VARIABLE_DEF[./IDENT[@text='testVariable']]"/> 408 * </pre> 409 * <p> 410 * In the following sample, violations for {@code LeftCurly} check will be suppressed 411 * for classes with name <i>Main</i> or for methods with name <i>calculate</i>. 412 * </p> 413 * <pre> 414 * <suppress-xpath checks="LeftCurly" query="/CLASS_DEF[./IDENT[@text='Main']]//* 415 * | //METHOD_DEF[./IDENT[@text='calculate']]/*"/> 416 * </pre> 417 * <p> 418 * The following example demonstrates how to suppress {@code RequireThis} violations 419 * for variable <i>age</i> inside <i>changeAge</i> method. 420 * </p> 421 * <pre> 422 * <suppress-xpath checks="RequireThis" 423 * query="/CLASS_DEF[./IDENT[@text='InputTest']] 424 * //METHOD_DEF[./IDENT[@text='changeAge']]//ASSIGN/IDENT[@text='age']"/> 425 * </pre> 426 * <pre> 427 * public class InputTest { 428 * private int age = 23; 429 * 430 * public void changeAge() { 431 * age = 24; //violation will be suppressed 432 * } 433 * } 434 * </pre> 435 * <p> 436 * Suppress {@code IllegalThrows} violations only for methods with name <i>throwsMethod</i> 437 * and only for {@code RuntimeException} exceptions. Double colon is used for axis iterations. 438 * In the following example {@code ancestor} axis is used to iterate all ancestor nodes 439 * of the current node with type {@code METHOD_DEF} and name <i>throwsMethod</i>. 440 * Please read more about xpath axes at <a href="https://www.w3schools.com/xml/xpath_axes.asp"> 441 * W3Schools Xpath Axes</a>. 442 * </p> 443 * <pre> 444 * <suppress-xpath checks="IllegalThrows" query="//LITERAL_THROWS 445 * /IDENT[@text='RuntimeException' and 446 * ./ancestor::METHOD_DEF[./IDENT[@text='throwsMethod']]]"/> 447 * </pre> 448 * <pre> 449 * public class InputTest { 450 * public void throwsMethod() throws RuntimeException { // violation will be suppressed 451 * } 452 * 453 * public void sampleMethod() throws RuntimeException { // will throw violation here 454 * } 455 * } 456 * </pre> 457 * <p> 458 * The following sample demonstrates how to suppress all violations for method 459 * itself and all descendants. {@code descendant-or-self} axis iterates through 460 * current node and all children nodes at any level. Keyword {@code node()} 461 * selects node elements. Please read more about xpath syntax at 462 * <a href="https://www.w3schools.com/xml/xpath_syntax.asp">W3Schools Xpath Syntax</a>. 463 * </p> 464 * <pre> 465 * <suppress-xpath checks=".*" query="//METHOD_DEF[./IDENT[@text='legacyMethod']] 466 * /descendant-or-self::node()"/> 467 * </pre> 468 * <p> 469 * Some elements can be suppressed in different ways. For example, to suppress 470 * violation on variable {@code wordCount} in following code: 471 * </p> 472 * <pre> 473 * public class InputTest { 474 * private int wordCount = 11; 475 * } 476 * </pre> 477 * <p> 478 * You need to look at AST of such code by our CLI tool: 479 * </p> 480 * <pre> 481 * $ java -jar checkstyle-X.XX-all.jar -t InputTest.java 482 * CLASS_DEF -> CLASS_DEF [1:0] 483 * |--MODIFIERS -> MODIFIERS [1:0] 484 * | `--LITERAL_PUBLIC -> public [1:0] 485 * |--LITERAL_CLASS -> class [1:7] 486 * |--IDENT -> InputTest [1:13] 487 * `--OBJBLOCK -> OBJBLOCK [1:23] 488 * |--LCURLY -> { [1:23] 489 * |--VARIABLE_DEF -> VARIABLE_DEF [2:4] 490 * | |--MODIFIERS -> MODIFIERS [2:4] 491 * | | `--LITERAL_PRIVATE -> private [2:4] 492 * | |--TYPE -> TYPE [2:12] 493 * | | `--LITERAL_INT -> int [2:12] 494 * | |--IDENT -> wordCount [2:16] 495 * | |--ASSIGN -> = [2:26] 496 * | | `--EXPR -> EXPR [2:28] 497 * | | `--NUM_INT -> 11 [2:28] 498 * | `--SEMI -> ; [2:30] 499 * `--RCURLY -> } [3:0] 500 * </pre> 501 * <p> 502 * The easiest way is to suppress by variable name. As you can see {@code VARIABLE_DEF} 503 * node refers to variable declaration statement and has child node with token type 504 * {@code IDENT} which is used for storing class, method, variable names. 505 * </p> 506 * <p> 507 * The following example demonstrates how variable can be queried by its name: 508 * </p> 509 * <pre> 510 * <suppress-xpath checks="." query="//VARIABLE_DEF[ 511 * ./IDENT[@text='wordCount']]"/> 512 * </pre> 513 * <p> 514 * Another way is to suppress by variable value. Again, if you look at the printed 515 * AST tree above, you will notice that one of the grandchildren of {@code VARIABLE_DEF} 516 * node is responsible for storing variable value -{@code NUM_INT} with value <b>11</b>. 517 * </p> 518 * <p> 519 * The following example demonstrates how variable can be queried by its value, 520 * same approach applies to {@code String, char, float, double, int, long} data types: 521 * </p> 522 * <pre> 523 * <suppress-xpath checks="." query="//VARIABLE_DEF[.//NUM_INT[@text=11]]"/> 524 * </pre> 525 * <p> 526 * Next example is about suppressing method with certain annotation by its name and element value. 527 * </p> 528 * <pre> 529 * public class InputTest { 530 * @Generated("first") // should not be suppressed 531 * public void test1() { 532 * } 533 * 534 * @Generated("second") // should be suppressed 535 * public void test2() { 536 * } 537 * } 538 * </pre> 539 * <p> 540 * First of all we need to look at AST tree printed by our CLI tool: 541 * </p> 542 * <pre> 543 * $ java -jar checkstyle-X.XX-all.jar -t InputTest.java 544 * CLASS_DEF -> CLASS_DEF [1:0] 545 * |--MODIFIERS -> MODIFIERS [1:0] 546 * | `--LITERAL_PUBLIC -> public [1:0] 547 * |--LITERAL_CLASS -> class [1:7] 548 * |--IDENT -> InputTest [1:13] 549 * `--OBJBLOCK -> OBJBLOCK [1:23] 550 * |--LCURLY -> { [1:23] 551 * |--METHOD_DEF -> METHOD_DEF [2:4] 552 * | |--MODIFIERS -> MODIFIERS [2:4] 553 * | | |--ANNOTATION -> ANNOTATION [2:4] 554 * | | | |--AT -> @ [2:4] 555 * | | | |--IDENT -> Generated [2:5] 556 * | | | |--LPAREN -> ( [2:14] 557 * | | | |--EXPR -> EXPR [2:15] 558 * | | | | `--STRING_LITERAL -> "first" [2:15] 559 * | | | `--RPAREN -> ) [2:22] 560 * | | `--LITERAL_PUBLIC -> public [3:4] 561 * | |--TYPE -> TYPE [3:11] 562 * | | `--LITERAL_VOID -> void [3:11] 563 * | |--IDENT -> test1 [3:16] 564 * | |--LPAREN -> ( [3:21] 565 * | |--PARAMETERS -> PARAMETERS [3:22] 566 * | |--RPAREN -> ) [3:22] 567 * | `--SLIST -> { [3:24] 568 * | `--RCURLY -> } [4:4] 569 * |--METHOD_DEF -> METHOD_DEF [6:4] 570 * | |--MODIFIERS -> MODIFIERS [6:4] 571 * | | |--ANNOTATION -> ANNOTATION [6:4] 572 * | | | |--AT -> @ [6:4] 573 * | | | |--IDENT -> Generated [6:5] 574 * | | | |--LPAREN -> ( [6:14] 575 * | | | |--EXPR -> EXPR [6:15] 576 * | | | | `--STRING_LITERAL -> "second" [6:15] 577 * | | | `--RPAREN -> ) [6:23] 578 * | | `--LITERAL_PUBLIC -> public [7:4] 579 * | |--TYPE -> TYPE [7:11] 580 * | | `--LITERAL_VOID -> void [7:11] 581 * | |--IDENT -> test2 [7:16] 582 * | |--LPAREN -> ( [7:21] 583 * | |--PARAMETERS -> PARAMETERS [7:22] 584 * | |--RPAREN -> ) [7:22] 585 * | `--SLIST -> { [7:24] 586 * | `--RCURLY -> } [8:4] 587 * `--RCURLY -> } [9:0] 588 * </pre> 589 * <p> 590 * AST node {@code ANNOTATION -> ANNOTATION [6:4]} has direct child 591 * {@code IDENT -> Generated [6:5]}, therefore can be queried by {@code IDENT} value: 592 * </p> 593 * <pre> 594 * <suppress-xpath checks="." query="//METHOD_DEF[ 595 * .//ANNOTATION/IDENT[@text='Generated']]"/> 596 * </pre> 597 * <p> 598 * The problem with query above that it will suppress violations for all methods 599 * with annotation {@code @Generated}. In order to suppress methods with 600 * {@code @Generated("second")} annotations only, you need to look at AST tree again. 601 * Value of the {@code ANNOTATION} node is stored inside sub-node with token type 602 * {@code STRING_LITERAL}. Use the following query to suppress methods with 603 * {@code @Generated("second")} annotation: 604 * </p> 605 * <pre> 606 * <suppress-xpath checks="." query="//METHOD_DEF[.//ANNOTATION[ 607 * ./IDENT[@text='Generated'] and ./EXPR/STRING_LITERAL[@text='second']]]"/> 608 * </pre> 609 * 610 * @since 8.6 611 * @noinspection NonFinalFieldReferenceInEquals, NonFinalFieldReferencedInHashCode 612 */ 613public class SuppressionXpathFilter extends AutomaticBean implements 614 TreeWalkerFilter, ExternalResourceHolder { 615 616 /** Specify the location of the <em>suppressions XML document</em> file. */ 617 private String file; 618 /** 619 * Control what to do when the file is not existing. 620 * If optional is set to false the file must exist, or else it ends with error. 621 * On the other hand if optional is true and file is not found, 622 * the filter accepts all audit events. 623 */ 624 private boolean optional; 625 /** Set of individual xpath suppresses. */ 626 private Set<TreeWalkerFilter> filters = new HashSet<>(); 627 628 /** 629 * Setter to specify the location of the <em>suppressions XML document</em> file. 630 * @param fileName name of the suppressions file. 631 */ 632 public void setFile(String fileName) { 633 file = fileName; 634 } 635 636 /** 637 * Setter to control what to do when the file is not existing. 638 * If optional is set to false the file must exist, or else it ends with error. 639 * On the other hand if optional is true and file is not found, 640 * the filter accepts all audit events. 641 * @param optional tells if config file existence is optional. 642 */ 643 public void setOptional(boolean optional) { 644 this.optional = optional; 645 } 646 647 @Override 648 public boolean equals(Object obj) { 649 if (this == obj) { 650 return true; 651 } 652 if (obj == null || getClass() != obj.getClass()) { 653 return false; 654 } 655 final SuppressionXpathFilter suppressionXpathFilter = (SuppressionXpathFilter) obj; 656 return Objects.equals(filters, suppressionXpathFilter.filters); 657 } 658 659 @Override 660 public int hashCode() { 661 return Objects.hash(filters); 662 } 663 664 @Override 665 public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { 666 boolean result = true; 667 for (TreeWalkerFilter filter : filters) { 668 if (!filter.accept(treeWalkerAuditEvent)) { 669 result = false; 670 break; 671 } 672 } 673 return result; 674 } 675 676 @Override 677 public Set<String> getExternalResourceLocations() { 678 return Collections.singleton(file); 679 } 680 681 @Override 682 protected void finishLocalSetup() throws CheckstyleException { 683 if (file != null) { 684 if (optional) { 685 if (FilterUtil.isFileExists(file)) { 686 filters = SuppressionsLoader.loadXpathSuppressions(file); 687 } 688 else { 689 filters = new HashSet<>(); 690 } 691 } 692 else { 693 filters = SuppressionsLoader.loadXpathSuppressions(file); 694 } 695 } 696 } 697 698}