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