1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2026 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. If unmatched, all Unix path separators (/)
52 * are converted to Windows separators (\) and retried.
53 * </li>
54 * <li>
55 * {@code checks} - a <a href="https://checkstyle.org/property-types.html#Pattern">
56 * Pattern</a> matched against the name of the check associated with an audit event.
57 * Optional as long as {@code id} or {@code message} is specified.
58 * </li>
59 * <li>
60 * {@code message} - a <a href="https://checkstyle.org/property-types.html#Pattern">
61 * Pattern</a> matched against the message of the check associated with an audit event.
62 * Optional as long as {@code checks} or {@code id} is specified.
63 * </li>
64 * <li>
65 * {@code id} - a <a href="https://checkstyle.org/property-types.html#String">String</a>
66 * matched against the <a href="https://checkstyle.org/config.html#Id">check id</a>
67 * associated with an audit event.
68 * Optional as long as {@code checks} or {@code message} is specified.
69 * </li>
70 * <li>
71 * {@code lines} - a comma-separated list of values, where each value is an
72 * <a href="https://checkstyle.org/property-types.html#int">int</a>
73 * or a range of integers denoted by integer-integer.
74 * It is optional.
75 * </li>
76 * <li>
77 * {@code columns} - a comma-separated list of values, where each value is an
78 * <a href="https://checkstyle.org/property-types.html#int">int</a>
79 * or a range of integers denoted by integer-integer.
80 * It is optional.
81 * </li>
82 * </ul>
83 *
84 * <p>
85 * Each audit event is checked against each {@code suppress} element.
86 * It is suppressed if all specified attributes match against the audit event.
87 * </p>
88 *
89 * <p>
90 * ATTENTION: filtering by message is dependent on runtime locale.
91 * If project is running in different languages it is better to avoid filtering by message.
92 * </p>
93 *
94 * <p>
95 * You can download template of empty suppression filter
96 * <a href="https://checkstyle.org/files/suppressions_none.xml">here</a>.
97 * </p>
98 *
99 * <p>
100 * Location of the file defined in {@code file} property is checked in the following order:
101 * </p>
102 * <ol>
103 * <li>
104 * as a filesystem location
105 * </li>
106 * <li>
107 * if no file found, and the location starts with either {@code http://} or {@code https://},
108 * then it is interpreted as a URL
109 * </li>
110 * <li>
111 * if no file found, then passed to the {@code ClassLoader.getResource()} method.
112 * </li>
113 * </ol>
114 *
115 * <p>
116 * SuppressionFilter can suppress Checks that have Treewalker or Checker as parent module.
117 * </p>
118 *
119 * @since 3.2
120 */
121 public class SuppressionFilter
122 extends AbstractAutomaticBean
123 implements Filter, ExternalResourceHolder {
124
125 /** Specify the location of the <em>suppressions XML document</em> file. */
126 private String file;
127 /**
128 * Control what to do when the file is not existing. If {@code optional} is
129 * set to {@code false} the file must exist, or else it ends with error.
130 * On the other hand if optional is {@code true} and file is not found,
131 * the filter accept all audit events.
132 */
133 private boolean optional;
134 /** Set of individual suppresses. */
135 private FilterSet filters = new FilterSet();
136
137 /**
138 * Creates a new {@code SuppressionFilter} instance.
139 */
140 public SuppressionFilter() {
141 // no code by default
142 }
143
144 /**
145 * Setter to specify the location of the <em>suppressions XML document</em> file.
146 *
147 * @param fileName name of the suppressions file.
148 * @since 3.2
149 */
150 public void setFile(String fileName) {
151 file = fileName;
152 }
153
154 /**
155 * Setter to control what to do when the file is not existing.
156 * If {@code optional} is set to {@code false} the file must exist, or else
157 * it ends with error. On the other hand if optional is {@code true}
158 * and file is not found, the filter accept all audit events.
159 *
160 * @param optional tells if config file existence is optional.
161 * @since 6.15
162 */
163 public void setOptional(boolean optional) {
164 this.optional = optional;
165 }
166
167 @Override
168 public boolean accept(AuditEvent event) {
169 return filters.accept(event);
170 }
171
172 @Override
173 protected void finishLocalSetup() throws CheckstyleException {
174 if (file != null) {
175 if (optional) {
176 if (FilterUtil.isFileExists(file)) {
177 filters = SuppressionsLoader.loadSuppressions(file);
178 }
179 }
180 else {
181 filters = SuppressionsLoader.loadSuppressions(file);
182 }
183 }
184 }
185
186 @Override
187 public Set<String> getExternalResourceLocations() {
188 return UnmodifiableCollectionUtil.singleton(file);
189 }
190
191 }