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 }