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.regex.Pattern; 023 024import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; 025import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; 026import com.puppycrawl.tools.checkstyle.api.AutomaticBean; 027 028/** 029 * <p> 030 * Filter {@code SuppressionXpathSingleFilter} suppresses audit events for Checks 031 * violations in the specified file, class, checks, message, module id, and xpath. 032 * </p> 033 * <p> 034 * Rationale: To allow users use suppressions configured in the same config with 035 * other modules. SuppressionFilter and SuppressionXpathFilter are require separate file. 036 * </p> 037 * <p> 038 * Advice: If checkstyle configuration is used for several projects, single suppressions 039 * on common files/folders is better to put in checkstyle configuration as common rule. 040 * All suppression that are for specific file names is better to keep in project 041 * specific config file. 042 * </p> 043 * <p> 044 * Attention: This filter only supports single suppression, and will need multiple 045 * instances if users wants to suppress multiple violations. 046 * </p> 047 * <ul> 048 * <li> 049 * Property {@code files} - Define a Regular Expression matched against the file 050 * name associated with an audit event. 051 * Default value is {@code null}. 052 * </li> 053 * <li> 054 * Property {@code checks} - Define a Regular Expression matched against the name 055 * of the check associated with an audit event. 056 * Default value is {@code null}. 057 * </li> 058 * <li> 059 * Property {@code message} - Define a Regular Expression matched against the message 060 * of the check associated with an audit event. 061 * Default value is {@code null}. 062 * </li> 063 * <li> 064 * Property {@code id} - Define a string matched against the ID of the check 065 * associated with an audit event. 066 * Default value is {@code null}. 067 * </li> 068 * <li> 069 * Property {@code query} - Define a string xpath query. 070 * Default value is {@code null}. 071 * </li> 072 * </ul> 073 * <p> 074 * To configure to suppress the MethodName check for all methods with 075 * name MyMethod inside FileOne and FileTwo files: 076 * </p> 077 * <pre> 078 * <module name="SuppressionXpathSingleFilter"> 079 * <property name="files" value="File(One|Two)\.java"/> 080 * <property name="checks" value="MethodName"/> 081 * <property name="query" value="(/CLASS_DEF[@text='FileOne']/OBJBLOCK/ 082 * METHOD_DEF[@text='MyMethod']/IDENT)| 083 * (/CLASS_DEF[@text='FileTwo']/OBJBLOCK/METHOD_DEF[@text='MyMethod']/IDENT)"/> 084 * </module> 085 * </pre> 086 * <p> 087 * Code example: 088 * </p> 089 * <pre> 090 * public class FileOne { 091 * public void MyMethod() {} // OK 092 * } 093 * 094 * public class FileTwo { 095 * public void MyMethod() {} // OK 096 * } 097 * 098 * public class FileThree { 099 * public void MyMethod() {} // violation, name 'MyMethod' 100 * // must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 101 * } 102 * </pre> 103 * <p> 104 * To suppress MethodName check for method names matched pattern 'MyMethod[0-9]': 105 * </p> 106 * <pre> 107 * <module name="SuppressionXpathSingleFilter"> 108 * <property name="checks" value="MethodName"/> 109 * <property name="message" value="MyMethod[0-9]"/> 110 * </module> 111 * </pre> 112 * <p> 113 * Code Example: 114 * </p> 115 * <pre> 116 * public class FileOne { 117 * public void MyMethod1() {} // OK 118 * public void MyMethod2() {} // OK 119 * public void MyMethodA() {} // violation, name 'MyMethodA' must 120 * // match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 121 * } 122 * </pre> 123 * <p> 124 * To suppress checks being specified by id property: 125 * </p> 126 * <pre> 127 * <module name="MethodName"> 128 * <property name="id" value="MethodName1"/> 129 * <property name="format" value="^[a-z](_?[a-zA-Z0-9]+)*$"/> 130 * <module/> 131 * <module name="SuppressionXpathSingleFilter"> 132 * <property name="files" value="FileOne.java"/> 133 * <property name="id" value="MethodName1"/> 134 * <module/> 135 * </pre> 136 * <p> 137 * Code example: 138 * </p> 139 * <pre> 140 * public class FileOne { 141 * public void MyMethod() {} // OK 142 * } 143 * public class FileTwo { 144 * public void MyMethod() {} // violation, name 'MyMethod' must 145 * //match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 146 * } 147 * </pre> 148 * <p> 149 * To suppress checks for all package definitions: 150 * </p> 151 * <pre> 152 * <module name="SuppressionXpathSingleFilter> 153 * <property name="checks" value="PackageName"/> 154 * <property name="query" query="/PACKAGE_DEF[@text='File']/IDENT"/> 155 * </module> 156 * </pre> 157 * <p> 158 * Code example: 159 * </p> 160 * <pre> 161 * package File; // OK 162 * 163 * public class FileOne {} 164 * </pre> 165 * <p> 166 * To suppress RedundantModifier check for interface definitions: 167 * </p> 168 * <pre> 169 * <module name="SuppressionXpathSingleFilter"> 170 * <property name="checks" value="RedundantModifier"/> 171 * <property name="query" value="/INTERFACE_DEF//*"/> 172 * <module/> 173 * </pre> 174 * <p> 175 * Code Example: 176 * </p> 177 * <pre> 178 * public interface TestClass { 179 * public static final int CONSTANT1 = 1; // OK 180 * } 181 * </pre> 182 * <p> 183 * To suppress checks in the FileOne file by non-query: 184 * </p> 185 * <pre> 186 * <module name="SuppressionXpathSingleFilter"> 187 * <property name="files" value="FileOne.java"/> 188 * <property name="checks" value="MyMethod"/> 189 * </module> 190 * </pre> 191 * <p> 192 * Code example: 193 * </p> 194 * <pre> 195 * public class FileOne { 196 * public void MyMethod() {} // OK 197 * } 198 * 199 * public class FileTwo { 200 * public void MyMethod() {} // violation, name 'MyMethod' 201 * // must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 202 * } 203 * </pre> 204 * <p> 205 * Suppress checks for elements which are either class definitions, either method definitions: 206 * </p> 207 * <pre> 208 * <module name="SuppressionXpathSingleFilter"> 209 * <property name="checks" value=".*"/> 210 * <property name="query" 211 * value="(/CLASS_DEF[@text='FileOne'])| 212 * (/CLASS_DEF[@text='FileOne']/OBJBLOCK/METHOD_DEF[@text='MyMethod']/IDENT)"/> 213 * </module> 214 * </pre> 215 * <p> 216 * Code example: 217 * </p> 218 * <pre> 219 * abstract class FileOne { // OK 220 * public void MyMethod() {} // OK 221 * } 222 * 223 * abstract class FileTwo { // violation of the AbstractClassName check, 224 * // it should match the pattern "^Abstract.+$" 225 * public void MyMethod() {} // violation, name 'MyMethod' 226 * // must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 227 * } 228 * </pre> 229 * <p> 230 * Suppress checks for MyMethod1 or MyMethod2 methods: 231 * </p> 232 * <pre> 233 * <module name="SuppressionXpathSingleFilter"> 234 * <property name="checks" value="MethodName"/> 235 * <property name="query" value="/CLASS_DEF[@text='FileOne']/OBJBLOCK/ 236 * METHOD_DEF[@text='MyMethod1' or @text='MyMethod2']/IDENT"/> 237 * </module> 238 * </pre> 239 * <p> 240 * Code example: 241 * </p> 242 * <pre> 243 * public class FileOne { 244 * public void MyMethod1() {} // OK 245 * public void MyMethod2() {} // OK 246 * public void MyMethod3() {} // violation, name 'MyMethod3' must 247 * // match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 248 * } 249 * </pre> 250 * <p> 251 * Suppress checks for variable testVariable inside testMethod method inside TestClass class: 252 * </p> 253 * <pre> 254 * <module name="SuppressionXpathSingleFilter"> 255 * <property name="checks" value="LocalFinalVariableName"/> 256 * <property name="query" value="/CLASS_DEF[@text='TestClass']/OBJBLOCK 257 * /METHOD_DEF[@text='testMethod']/SLIST 258 * /VARIABLE_DEF[@text='testVariable1']/IDENT"/> 259 * </module> 260 * </pre> 261 * <p> 262 * Code Example: 263 * </p> 264 * <pre> 265 * public class TestClass { 266 * public void testMethod() { 267 * final int testVariable1 = 10; // OK 268 * final int testVariable2 = 10; // violation of the LocalFinalVariableName check, 269 * // name 'testVariable2' must match pattern '^[A-Z][A-Z0-9]*$' 270 * } 271 * } 272 * </pre> 273 * <p> 274 * In the following sample, violations for LeftCurly check will be suppressed 275 * for classes with name Main or for methods with name calculate. 276 * </p> 277 * <pre> 278 * <module name="SuppressionXpathSingleFilter"> 279 * <property name="checks" value="LeftCurly"/> 280 * <property name="query" value="/CLASS_DEF[@text='TestClass']/OBJBLOCK 281 * /METHOD_DEF[@text='testMethod1']/SLIST*"/> 282 * </module> 283 * </pre> 284 * <p> 285 * Code Example: 286 * </p> 287 * <pre> 288 * public class TestClass { 289 * public void testMethod1() 290 * { // OK 291 * } 292 * 293 * public void testMethod2() 294 * { // violation, '{' should be on the previous line 295 * } 296 * } 297 * </pre> 298 * <p> 299 * The following example demonstrates how to suppress RequireThis violations for 300 * variable age inside changeAge method. 301 * </p> 302 * <pre> 303 * <module name="SuppressionXpathSingleFilter"> 304 * <property name="checks" value="RequireThis"/> 305 * <property name="query" value="/CLASS_DEF[@text='InputTest'] 306 * //METHOD_DEF[@text='changeAge']//ASSIGN[@text='age']/IDENT"/> 307 * </module> 308 * </pre> 309 * <p> 310 * Code Example: 311 * </p> 312 * <pre> 313 * public class InputTest { 314 * private int age = 23; 315 * 316 * public void changeAge() { 317 * age = 24; // violation will be suppressed 318 * } 319 * } 320 * </pre> 321 * <p> 322 * Suppress {@code IllegalThrows} violations only for methods with name 323 * <i>throwsMethod</i> and only for {@code RuntimeException} exceptions. 324 * Double colon is used for axis iterations. In the following example 325 * {@code ancestor} axis is used to iterate all ancestor nodes of the current 326 * node with type {@code METHOD_DEF} and name <i>throwsMethod</i>. 327 * Please read more about xpath axes at 328 * <a href="https://www.w3schools.com/xml/xpath_axes.asp">W3Schools Xpath Axes</a>. 329 * </p> 330 * <pre> 331 * <module name="SuppressionXpathSingleFilter"> 332 * <property name="checks" value="IllegalThrows"/> 333 * <property name="query" value="//LITERAL_THROWS/IDENT[ 334 * ..[@text='RuntimeException'] and ./ancestor::METHOD_DEF[@text='throwsMethod']]"/> 335 * </module> 336 * </pre> 337 * <p> 338 * Code Example: 339 * </p> 340 * <pre> 341 * public class InputTest { 342 * public void throwsMethod() throws RuntimeException { // violation will be suppressed 343 * } 344 * 345 * public void sampleMethod() throws RuntimeException { // will throw violation here 346 * } 347 * } 348 * </pre> 349 * <p> 350 * The following sample demonstrates how to suppress all violations for method 351 * itself and all descendants. {@code descendant-or-self} axis iterates through 352 * current node and all children nodes at any level. Keyword {@code node()} 353 * selects node elements. Please read more about xpath syntax at 354 * <a href="https://www.w3schools.com/xml/xpath_syntax.asp">W3Schools Xpath Syntax</a>. 355 * </p> 356 * <pre> 357 * <module name="SuppressionXpathSingleFilter"> 358 * <property name="checks" value=".*"/> 359 * <property name="query" value="//METHOD_DEF[@text='TestMethod1'] 360 * /descendant-or-self::node()"/> 361 * </module> 362 * </pre> 363 * <p> 364 * Code Example: 365 * </p> 366 * <pre> 367 * public class TestClass { 368 * public void TestMethod1() { // OK 369 * final int num = 10; // OK 370 * } 371 * 372 * public void TestMethod2() { // violation of the MethodName check, 373 * // name 'TestMethod2' must match pattern '^[a-z](_?[a-zA-Z0-9]+)*$' 374 * final int num = 10; // violation of the LocalFinalVariableName check, 375 * // name 'num' must match pattern '^[A-Z][A-Z0-9]*$' 376 * } 377 * } 378 * </pre> 379 * <p> 380 * The following example is an example of what checks would be suppressed while 381 * building Spring projects with checkstyle plugin. Please find more information at: 382 * <a href="https://github.com/spring-io/spring-javaformat">spring-javaformat</a> 383 * </p> 384 * <pre> 385 * <module name="SuppressionXpathSingleFilter"> 386 * <property name="files" value="[\\/]src[\\/]test[\\/]java[\\/]"/> 387 * <property name="checks" value="Javadoc*"/> 388 * </module> 389 * <module name="SuppressionXpathSingleFilter"> 390 * <property name="files" value=".*Tests\.java"> 391 * <property name="checks" value="Javadoc*"> 392 * </module> 393 * <module name="SuppressionXpathSingleFilter"> 394 * <property name="files" value="generated-sources"> 395 * <property name="checks" value="[a-zA-Z0-9]*"> 396 * </module> 397 * </pre> 398 * 399 * @since 8.18 400 */ 401public class SuppressionXpathSingleFilter extends AutomaticBean implements 402 TreeWalkerFilter { 403 /** 404 * XpathFilterElement instance. 405 */ 406 private XpathFilterElement xpathFilter; 407 /** 408 * Define a Regular Expression matched against the file name associated with an audit event. 409 */ 410 private Pattern files; 411 /** 412 * Define a Regular Expression matched against the name of the check associated 413 * with an audit event. 414 */ 415 private Pattern checks; 416 /** 417 * Define a Regular Expression matched against the message of the check 418 * associated with an audit event. 419 */ 420 private Pattern message; 421 /** 422 * Define a string matched against the ID of the check associated with an audit event. 423 */ 424 private String id; 425 /** 426 * Define a string xpath query. 427 */ 428 private String query; 429 430 /** 431 * Setter to define a Regular Expression matched against the file name 432 * associated with an audit event. 433 * 434 * @param files the name of the file 435 */ 436 public void setFiles(String files) { 437 if (files == null) { 438 this.files = null; 439 } 440 else { 441 this.files = Pattern.compile(files); 442 } 443 } 444 445 /** 446 * Setter to define a Regular Expression matched against the name of the check 447 * associated with an audit event. 448 * 449 * @param checks the name of the check 450 */ 451 public void setChecks(String checks) { 452 if (checks == null) { 453 this.checks = null; 454 } 455 else { 456 this.checks = Pattern.compile(checks); 457 } 458 } 459 460 /** 461 * Setter to define a Regular Expression matched against the message of 462 * the check associated with an audit event. 463 * 464 * @param message the message of the check 465 */ 466 public void setMessage(String message) { 467 if (message == null) { 468 this.message = null; 469 } 470 else { 471 this.message = Pattern.compile(message); 472 } 473 } 474 475 /** 476 * Setter to define a string matched against the ID of the check associated 477 * with an audit event. 478 * 479 * @param id the ID of the check 480 */ 481 public void setId(String id) { 482 this.id = id; 483 } 484 485 /** 486 * Setter to define a string xpath query. 487 * @param query the xpath query 488 */ 489 public void setQuery(String query) { 490 this.query = query; 491 } 492 493 @Override 494 protected void finishLocalSetup() { 495 xpathFilter = new XpathFilterElement(files, checks, message, id, query); 496 } 497 498 @Override 499 public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { 500 return xpathFilter.accept(treeWalkerAuditEvent); 501 } 502 503}