View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.filters;
21  
22  import java.util.Set;
23  
24  import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean;
25  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
26  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
27  import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
28  import com.puppycrawl.tools.checkstyle.api.Filter;
29  import com.puppycrawl.tools.checkstyle.api.FilterSet;
30  import com.puppycrawl.tools.checkstyle.utils.FilterUtil;
31  import com.puppycrawl.tools.checkstyle.utils.UnmodifiableCollectionUtil;
32  
33  /**
34   * <div>
35   * Filter {@code SuppressionFilter} rejects audit events for Check violations according to a
36   * <a href="https://checkstyle.org/dtds/suppressions_1_2.dtd">suppressions XML document</a>
37   * in a file. If there is no configured suppressions file or the optional is set to true and
38   * suppressions file was not found the Filter accepts all audit events.
39   * </div>
40   *
41   * <p>
42   * Notes:
43   * A <a href="https://checkstyle.org/dtds/suppressions_1_2.dtd">suppressions XML document</a>
44   * contains a set of {@code suppress} elements, where each {@code suppress}
45   * element can have the following attributes:
46   * </p>
47   * <ul>
48   * <li>
49   * {@code files} - a <a href="https://checkstyle.org/property_types.html#Pattern">
50   * Pattern</a> matched against the file name associated with an audit event.
51   * It is optional.
52   * </li>
53   * <li>
54   * {@code checks} - a <a href="https://checkstyle.org/property_types.html#Pattern">
55   * Pattern</a> matched against the name of the check associated with an audit event.
56   * Optional as long as {@code id} or {@code message} is specified.
57   * </li>
58   * <li>
59   * {@code message} - a <a href="https://checkstyle.org/property_types.html#Pattern">
60   * Pattern</a> matched against the message of the check associated with an audit event.
61   * Optional as long as {@code checks} or {@code id} is specified.
62   * </li>
63   * <li>
64   * {@code id} - a <a href="https://checkstyle.org/property_types.html#String">String</a>
65   * matched against the <a href="https://checkstyle.org/config.html#Id">check id</a>
66   * associated with an audit event.
67   * Optional as long as {@code checks} or {@code message} is specified.
68   * </li>
69   * <li>
70   * {@code lines} - a comma-separated list of values, where each value is an
71   * <a href="https://checkstyle.org/property_types.html#int">int</a>
72   * or a range of integers denoted by integer-integer.
73   * It is optional.
74   * </li>
75   * <li>
76   * {@code columns} - a comma-separated list of values, where each value is an
77   * <a href="https://checkstyle.org/property_types.html#int">int</a>
78   * or a range of integers denoted by integer-integer.
79   * It is optional.
80   * </li>
81   * </ul>
82   *
83   * <p>
84   * Each audit event is checked against each {@code suppress} element.
85   * It is suppressed if all specified attributes match against the audit event.
86   * </p>
87   *
88   * <p>
89   * ATTENTION: filtering by message is dependent on runtime locale.
90   * If project is running in different languages it is better to avoid filtering by message.
91   * </p>
92   *
93   * <p>
94   * You can download template of empty suppression filter
95   * <a href="https://checkstyle.org/files/suppressions_none.xml">here</a>.
96   * </p>
97   *
98   * <p>
99   * Location of the file defined in {@code file} property is checked in the following order:
100  * </p>
101  * <ol>
102  * <li>
103  * as a filesystem location
104  * </li>
105  * <li>
106  * if no file found, and the location starts with either {@code http://} or {@code https://},
107  * then it is interpreted as a URL
108  * </li>
109  * <li>
110  * if no file found, then passed to the {@code ClassLoader.getResource()} method.
111  * </li>
112  * </ol>
113  *
114  * <p>
115  * SuppressionFilter can suppress Checks that have Treewalker or Checker as parent module.
116  * </p>
117  *
118  * @since 3.2
119  */
120 public class SuppressionFilter
121         extends AbstractAutomaticBean
122         implements Filter, ExternalResourceHolder {
123 
124     /** Specify the location of the <em>suppressions XML document</em> file. */
125     private String file;
126     /**
127      * Control what to do when the file is not existing. If {@code optional} is
128      * set to {@code false} the file must exist, or else it ends with error.
129      * On the other hand if optional is {@code true} and file is not found,
130      * the filter accept all audit events.
131      */
132     private boolean optional;
133     /** Set of individual suppresses. */
134     private FilterSet filters = new FilterSet();
135 
136     /**
137      * Setter to specify the location of the <em>suppressions XML document</em> file.
138      *
139      * @param fileName name of the suppressions file.
140      * @since 3.2
141      */
142     public void setFile(String fileName) {
143         file = fileName;
144     }
145 
146     /**
147      * Setter to control what to do when the file is not existing.
148      * If {@code optional} is set to {@code false} the file must exist, or else
149      * it ends with error. On the other hand if optional is {@code true}
150      * and file is not found, the filter accept all audit events.
151      *
152      * @param optional tells if config file existence is optional.
153      * @since 6.15
154      */
155     public void setOptional(boolean optional) {
156         this.optional = optional;
157     }
158 
159     @Override
160     public boolean accept(AuditEvent event) {
161         return filters.accept(event);
162     }
163 
164     @Override
165     protected void finishLocalSetup() throws CheckstyleException {
166         if (file != null) {
167             if (optional) {
168                 if (FilterUtil.isFileExists(file)) {
169                     filters = SuppressionsLoader.loadSuppressions(file);
170                 }
171             }
172             else {
173                 filters = SuppressionsLoader.loadSuppressions(file);
174             }
175         }
176     }
177 
178     @Override
179     public Set<String> getExternalResourceLocations() {
180         return UnmodifiableCollectionUtil.singleton(file);
181     }
182 
183 }