1 /////////////////////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules. 3 // Copyright (C) 2001-2024 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.Collections; 23 import java.util.HashSet; 24 import java.util.Objects; 25 import java.util.Set; 26 27 import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean; 28 import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; 29 import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; 30 import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 31 import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; 32 import com.puppycrawl.tools.checkstyle.utils.FilterUtil; 33 34 /** 35 * <p> 36 * Filter {@code SuppressionXpathFilter} works as 37 * <a href="https://checkstyle.org/filters/suppressionfilter.html#SuppressionFilter"> 38 * SuppressionFilter</a>. 39 * Additionally, filter processes {@code suppress-xpath} elements, 40 * which contains xpath-expressions. Xpath-expressions are queries for 41 * suppressed nodes inside the AST tree. 42 * </p> 43 * <p> 44 * Currently, filter does not support the following checks: 45 * </p> 46 * <ul id="IncompatibleChecks"> 47 * <li> 48 * NoCodeInFile (reason is that AST is not generated for a file not containing code) 49 * </li> 50 * <li> 51 * Regexp (reason is at 52 * <a href="https://github.com/checkstyle/checkstyle/issues/7759#issuecomment-605525287"> #7759</a>) 53 * </li> 54 * <li> 55 * RegexpSinglelineJava (reason is at 56 * <a href="https://github.com/checkstyle/checkstyle/issues/7759#issuecomment-605525287"> #7759</a>) 57 * </li> 58 * </ul> 59 * <p> 60 * Also, the filter does not support suppressions inside javadoc reported by Javadoc checks: 61 * </p> 62 * <ul id="JavadocChecks"> 63 * <li> 64 * AtclauseOrder 65 * </li> 66 * <li> 67 * JavadocBlockTagLocation 68 * </li> 69 * <li> 70 * JavadocMethod 71 * </li> 72 * <li> 73 * JavadocMissingLeadingAsterisk 74 * </li> 75 * <li> 76 * JavadocMissingWhitespaceAfterAsterisk 77 * </li> 78 * <li> 79 * JavadocParagraph 80 * </li> 81 * <li> 82 * JavadocStyle 83 * </li> 84 * <li> 85 * JavadocTagContinuationIndentation 86 * </li> 87 * <li> 88 * JavadocType 89 * </li> 90 * <li> 91 * MissingDeprecated 92 * </li> 93 * <li> 94 * NonEmptyAtclauseDescription 95 * </li> 96 * <li> 97 * RequireEmptyLineBeforeBlockTagGroup 98 * </li> 99 * <li> 100 * SingleLineJavadoc 101 * </li> 102 * <li> 103 * SummaryJavadoc 104 * </li> 105 * <li> 106 * WriteTag 107 * </li> 108 * </ul> 109 * <p> 110 * Note, that support for these Checks will be available after resolving issue 111 * <a href="https://github.com/checkstyle/checkstyle/issues/5770">#5770</a>. 112 * </p> 113 * <p> 114 * Currently, filter supports the following xpath axes: 115 * </p> 116 * <ul> 117 * <li> 118 * ancestor 119 * </li> 120 * <li> 121 * ancestor-or-self 122 * </li> 123 * <li> 124 * attribute 125 * </li> 126 * <li> 127 * child 128 * </li> 129 * <li> 130 * descendant 131 * </li> 132 * <li> 133 * descendant-or-self 134 * </li> 135 * <li> 136 * following 137 * </li> 138 * <li> 139 * following-sibling 140 * </li> 141 * <li> 142 * parent 143 * </li> 144 * <li> 145 * preceding 146 * </li> 147 * <li> 148 * preceding-sibling 149 * </li> 150 * <li> 151 * self 152 * </li> 153 * </ul> 154 * <p> 155 * You can use the command line helper tool to generate xpath suppressions based on your 156 * configuration file and input files. See <a href="https://checkstyle.org/cmdline.html">here</a> 157 * for more details. 158 * </p> 159 * <p> 160 * The suppression file location is checked in following order: 161 * </p> 162 * <ol> 163 * <li> 164 * as a filesystem location 165 * </li> 166 * <li> 167 * if no file found, and the location starts with either {@code http://} or {@code https://}, 168 * then it is interpreted as a URL 169 * </li> 170 * <li> 171 * if no file found, then passed to the {@code ClassLoader.getResource()} method. 172 * </li> 173 * </ol> 174 * <p> 175 * SuppressionXpathFilter can suppress Checks that have Treewalker as parent module. 176 * </p> 177 * <ul> 178 * <li> 179 * Property {@code file} - Specify the location of the <em>suppressions XML document</em> file. 180 * Type is {@code java.lang.String}. 181 * Default value is {@code null}. 182 * </li> 183 * <li> 184 * Property {@code optional} - Control what to do when the file is not existing. 185 * If optional is set to false the file must exist, or else it ends with error. 186 * On the other hand if optional is true and file is not found, the filter accepts all audit events. 187 * Type is {@code boolean}. 188 * Default value is {@code false}. 189 * </li> 190 * </ul> 191 * <p> 192 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 193 * </p> 194 * 195 * @since 8.6 196 */ 197 public class SuppressionXpathFilter extends AbstractAutomaticBean implements 198 TreeWalkerFilter, ExternalResourceHolder { 199 200 /** Set of individual xpath suppresses. */ 201 private final Set<TreeWalkerFilter> filters = new HashSet<>(); 202 203 /** Specify the location of the <em>suppressions XML document</em> file. */ 204 private String file; 205 /** 206 * Control what to do when the file is not existing. 207 * If optional is set to false the file must exist, or else it ends with error. 208 * On the other hand if optional is true and file is not found, 209 * the filter accepts all audit events. 210 */ 211 private boolean optional; 212 213 /** 214 * Setter to specify the location of the <em>suppressions XML document</em> file. 215 * 216 * @param fileName name of the suppressions file. 217 * @since 8.6 218 */ 219 public void setFile(String fileName) { 220 file = fileName; 221 } 222 223 /** 224 * Setter to control what to do when the file is not existing. 225 * If optional is set to false the file must exist, or else it ends with error. 226 * On the other hand if optional is true and file is not found, 227 * the filter accepts all audit events. 228 * 229 * @param optional tells if config file existence is optional. 230 * @since 8.6 231 */ 232 public void setOptional(boolean optional) { 233 this.optional = optional; 234 } 235 236 @Override 237 public boolean equals(Object obj) { 238 if (this == obj) { 239 return true; 240 } 241 if (obj == null || getClass() != obj.getClass()) { 242 return false; 243 } 244 final SuppressionXpathFilter suppressionXpathFilter = (SuppressionXpathFilter) obj; 245 return Objects.equals(filters, suppressionXpathFilter.filters); 246 } 247 248 @Override 249 public int hashCode() { 250 return Objects.hash(filters); 251 } 252 253 @Override 254 public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { 255 boolean result = true; 256 for (TreeWalkerFilter filter : filters) { 257 if (!filter.accept(treeWalkerAuditEvent)) { 258 result = false; 259 break; 260 } 261 } 262 return result; 263 } 264 265 @Override 266 public Set<String> getExternalResourceLocations() { 267 return Collections.singleton(file); 268 } 269 270 @Override 271 protected void finishLocalSetup() throws CheckstyleException { 272 if (file != null) { 273 if (optional) { 274 if (FilterUtil.isFileExists(file)) { 275 filters.addAll(SuppressionsLoader.loadXpathSuppressions(file)); 276 } 277 } 278 else { 279 filters.addAll(SuppressionsLoader.loadXpathSuppressions(file)); 280 } 281 } 282 } 283 284 }