001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2025 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.Collections; 023import java.util.HashSet; 024import java.util.Objects; 025import java.util.Set; 026 027import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean; 028import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; 029import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; 030import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 031import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; 032import com.puppycrawl.tools.checkstyle.utils.FilterUtil; 033 034/** 035 * <div> 036 * Filter {@code SuppressionXpathFilter} works as 037 * <a href="https://checkstyle.org/filters/suppressionfilter.html"> 038 * SuppressionFilter</a>. 039 * Additionally, filter processes {@code suppress-xpath} elements, 040 * which contains xpath-expressions. Xpath-expressions are queries for 041 * suppressed nodes inside the AST tree. 042 * </div> 043 * 044 * <p> 045 * Currently, filter does not support the following checks: 046 * </p> 047 * <ul id="IncompatibleChecks"> 048 * <li> 049 * NoCodeInFile (reason is that AST is not generated for a file not containing code) 050 * </li> 051 * <li> 052 * Regexp (reason is at 053 * <a href="https://github.com/checkstyle/checkstyle/issues/7759#issuecomment-605525287"> #7759</a>) 054 * </li> 055 * <li> 056 * RegexpSinglelineJava (reason is at 057 * <a href="https://github.com/checkstyle/checkstyle/issues/7759#issuecomment-605525287"> #7759</a>) 058 * </li> 059 * </ul> 060 * 061 * <p> 062 * Also, the filter does not support suppressions inside javadoc reported by Javadoc checks: 063 * </p> 064 * <ul id="JavadocChecks"> 065 * <li> 066 * AtclauseOrder 067 * </li> 068 * <li> 069 * JavadocBlockTagLocation 070 * </li> 071 * <li> 072 * JavadocMethod 073 * </li> 074 * <li> 075 * JavadocMissingLeadingAsterisk 076 * </li> 077 * <li> 078 * JavadocMissingWhitespaceAfterAsterisk 079 * </li> 080 * <li> 081 * JavadocParagraph 082 * </li> 083 * <li> 084 * JavadocStyle 085 * </li> 086 * <li> 087 * JavadocTagContinuationIndentation 088 * </li> 089 * <li> 090 * JavadocType 091 * </li> 092 * <li> 093 * MissingDeprecated 094 * </li> 095 * <li> 096 * NonEmptyAtclauseDescription 097 * </li> 098 * <li> 099 * RequireEmptyLineBeforeBlockTagGroup 100 * </li> 101 * <li> 102 * SingleLineJavadoc 103 * </li> 104 * <li> 105 * SummaryJavadoc 106 * </li> 107 * <li> 108 * WriteTag 109 * </li> 110 * </ul> 111 * 112 * <p> 113 * Note, that support for these Checks will be available after resolving issue 114 * <a href="https://github.com/checkstyle/checkstyle/issues/5770">#5770</a>. 115 * </p> 116 * 117 * <p> 118 * Currently, filter supports the following xpath axes: 119 * </p> 120 * <ul> 121 * <li> 122 * ancestor 123 * </li> 124 * <li> 125 * ancestor-or-self 126 * </li> 127 * <li> 128 * attribute 129 * </li> 130 * <li> 131 * child 132 * </li> 133 * <li> 134 * descendant 135 * </li> 136 * <li> 137 * descendant-or-self 138 * </li> 139 * <li> 140 * following 141 * </li> 142 * <li> 143 * following-sibling 144 * </li> 145 * <li> 146 * parent 147 * </li> 148 * <li> 149 * preceding 150 * </li> 151 * <li> 152 * preceding-sibling 153 * </li> 154 * <li> 155 * self 156 * </li> 157 * </ul> 158 * 159 * <p> 160 * You can use the command line helper tool to generate xpath suppressions based on your 161 * configuration file and input files. See <a href="https://checkstyle.org/cmdline.html">here</a> 162 * for more details. 163 * </p> 164 * 165 * <p> 166 * Notes: 167 * The suppression file location is checked in following order: 168 * </p> 169 * <ol> 170 * <li> 171 * as a filesystem location 172 * </li> 173 * <li> 174 * if no file found, and the location starts with either {@code http://} or {@code https://}, 175 * then it is interpreted as a URL 176 * </li> 177 * <li> 178 * if no file found, then passed to the {@code ClassLoader.getResource()} method. 179 * </li> 180 * </ol> 181 * 182 * <p> 183 * SuppressionXpathFilter can suppress Checks that have Treewalker as parent module. 184 * </p> 185 * 186 * <p> 187 * A <a href="/dtds/suppressions_1_2_xpath_experimental.dtd"><em>suppressions XML 188 * document</em></a> contains a set 189 * of {@code suppress} and {@code suppress-xpath} elements, where 190 * each {@code suppress-xpath} element can have the 191 * following attributes: 192 * </p> 193 * <ul> 194 * <li> 195 * {@code files} - 196 * a <a href="../property_types.html#Pattern">Pattern</a> 197 * matched against the file name associated with an audit 198 * event. It is optional. 199 * </li> 200 * <li> 201 * {@code checks} - 202 * a <a href="../property_types.html#Pattern">Pattern</a> 203 * matched against the name of the check associated with an audit 204 * event. Optional as long as {@code id} or {@code message} is specified. 205 * </li> 206 * <li> 207 * {@code message} - 208 * a <a href="../property_types.html#Pattern">Pattern</a> 209 * matched against the message of the check associated with an audit 210 * event. Optional as long as {@code checks} or {@code id} is specified. 211 * </li> 212 * <li> 213 * {@code id} - 214 * a <a href="../property_types.html#String">String</a> 215 * matched against the ID of the check associated with an audit 216 * event. Optional as long as {@code checks} or {@code message} is specified. 217 * </li> 218 * <li> 219 * {@code query} - 220 * a <a href="../property_types.html#String">String</a> 221 * xpath query. It is optional. 222 * </li> 223 * </ul> 224 * 225 * <p> 226 * Each audit event is checked against 227 * each {@code suppress} and {@code suppress-xpath} element. It is 228 * suppressed if all specified attributes match against the audit 229 * event. 230 * </p> 231 * 232 * <p> 233 * ATTENTION: filtering by message is dependent on runtime locale. If project is running 234 * in different languages it is better to avoid filtering by message. 235 * </p> 236 * 237 * <ul> 238 * <li> 239 * Property {@code file} - Specify the location of the <em>suppressions XML document</em> file. 240 * Type is {@code java.lang.String}. 241 * Default value is {@code null}. 242 * </li> 243 * <li> 244 * Property {@code optional} - Control what to do when the file is not existing. 245 * If optional is set to false the file must exist, or else it ends with error. 246 * On the other hand if optional is true and file is not found, the filter accepts all audit events. 247 * Type is {@code boolean}. 248 * Default value is {@code false}. 249 * </li> 250 * </ul> 251 * 252 * <p> 253 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 254 * </p> 255 * 256 * @since 8.6 257 */ 258public class SuppressionXpathFilter extends AbstractAutomaticBean implements 259 TreeWalkerFilter, ExternalResourceHolder { 260 261 /** Set of individual xpath suppresses. */ 262 private final Set<TreeWalkerFilter> filters = new HashSet<>(); 263 264 /** Specify the location of the <em>suppressions XML document</em> file. */ 265 private String file; 266 /** 267 * Control what to do when the file is not existing. 268 * If optional is set to false the file must exist, or else it ends with error. 269 * On the other hand if optional is true and file is not found, 270 * the filter accepts all audit events. 271 */ 272 private boolean optional; 273 274 /** 275 * Setter to specify the location of the <em>suppressions XML document</em> file. 276 * 277 * @param fileName name of the suppressions file. 278 * @since 8.6 279 */ 280 public void setFile(String fileName) { 281 file = fileName; 282 } 283 284 /** 285 * Setter to control what to do when the file is not existing. 286 * If optional is set to false the file must exist, or else it ends with error. 287 * On the other hand if optional is true and file is not found, 288 * the filter accepts all audit events. 289 * 290 * @param optional tells if config file existence is optional. 291 * @since 8.6 292 */ 293 public void setOptional(boolean optional) { 294 this.optional = optional; 295 } 296 297 @Override 298 public boolean equals(Object obj) { 299 if (this == obj) { 300 return true; 301 } 302 if (obj == null || getClass() != obj.getClass()) { 303 return false; 304 } 305 final SuppressionXpathFilter suppressionXpathFilter = (SuppressionXpathFilter) obj; 306 return Objects.equals(filters, suppressionXpathFilter.filters); 307 } 308 309 @Override 310 public int hashCode() { 311 return Objects.hash(filters); 312 } 313 314 @Override 315 public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { 316 boolean result = true; 317 for (TreeWalkerFilter filter : filters) { 318 if (!filter.accept(treeWalkerAuditEvent)) { 319 result = false; 320 break; 321 } 322 } 323 return result; 324 } 325 326 @Override 327 public Set<String> getExternalResourceLocations() { 328 return Collections.singleton(file); 329 } 330 331 @Override 332 protected void finishLocalSetup() throws CheckstyleException { 333 if (file != null) { 334 if (optional) { 335 if (FilterUtil.isFileExists(file)) { 336 filters.addAll(SuppressionsLoader.loadXpathSuppressions(file)); 337 } 338 } 339 else { 340 filters.addAll(SuppressionsLoader.loadXpathSuppressions(file)); 341 } 342 } 343 } 344 345}