001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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.Set; 024 025import com.puppycrawl.tools.checkstyle.api.AuditEvent; 026import com.puppycrawl.tools.checkstyle.api.AutomaticBean; 027import com.puppycrawl.tools.checkstyle.api.CheckstyleException; 028import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; 029import com.puppycrawl.tools.checkstyle.api.Filter; 030import com.puppycrawl.tools.checkstyle.api.FilterSet; 031import com.puppycrawl.tools.checkstyle.utils.FilterUtil; 032 033/** 034 * <p> 035 * Filter {@code SuppressionFilter} rejects audit events for Check violations according to a 036 * <a href="https://checkstyle.org/dtds/suppressions_1_2.dtd">suppressions XML document</a> 037 * in a file. If there is no configured suppressions file or the optional is set to true and 038 * suppressions file was not found the Filter accepts all audit events. 039 * </p> 040 * <p> 041 * A <a href="https://checkstyle.org/dtds/suppressions_1_2.dtd">suppressions XML document</a> 042 * contains a set of {@code suppress} elements, where each {@code suppress} 043 * element can have the following attributes: 044 * </p> 045 * <ul> 046 * <li> 047 * {@code files} - a <a href="https://checkstyle.org/property_types.html#Pattern"> 048 * Pattern</a> matched against the file name associated with an audit event. 049 * It is optional. 050 * </li> 051 * <li> 052 * {@code checks} - a <a href="https://checkstyle.org/property_types.html#Pattern"> 053 * Pattern</a> matched against the name of the check associated with an audit event. 054 * Optional as long as {@code id} or {@code message} is specified. 055 * </li> 056 * <li> 057 * {@code message} - a <a href="https://checkstyle.org/property_types.html#Pattern"> 058 * Pattern</a> matched against the message of the check associated with an audit event. 059 * Optional as long as {@code checks} or {@code id} is specified. 060 * </li> 061 * <li> 062 * {@code id} - a <a href="https://checkstyle.org/property_types.html#String">String</a> 063 * matched against the <a href="https://checkstyle.org/config.html#Id">check id</a> 064 * associated with an audit event. 065 * Optional as long as {@code checks} or {@code message} is specified. 066 * </li> 067 * <li> 068 * {@code lines} - a comma-separated list of values, where each value is an 069 * <a href="https://checkstyle.org/property_types.html#int">int</a> 070 * or a range of integers denoted by integer-integer. 071 * It is optional. 072 * </li> 073 * <li> 074 * {@code columns} - a comma-separated list of values, where each value is an 075 * <a href="https://checkstyle.org/property_types.html#int">int</a> 076 * or a range of integers denoted by integer-integer. 077 * It is optional. 078 * </li> 079 * </ul> 080 * <p> 081 * Each audit event is checked against each {@code suppress} element. 082 * It is suppressed if all specified attributes match against the audit event. 083 * </p> 084 * <p> 085 * ATTENTION: filtering by message is dependant on runtime locale. 086 * If project is running in different languages it is better to avoid filtering by message. 087 * </p> 088 * <p> 089 * You can download template of empty suppression filter 090 * <a href="https://checkstyle.org/files/suppressions_none.xml">here</a>. 091 * </p> 092 * <p> 093 * Location of the file defined in {@code file} property is checked in the following order: 094 * </p> 095 * <ol> 096 * <li> 097 * as a filesystem location 098 * </li> 099 * <li> 100 * if no file found, and the location starts with either {@code http://} or {@code https://}, 101 * then it is interpreted as a URL 102 * </li> 103 * <li> 104 * if no file found, then passed to the {@code ClassLoader.getResource()} method. 105 * </li> 106 * </ol> 107 * <p> 108 * SuppressionFilter can suppress Checks that have Treewalker or Checker as parent module. 109 * </p> 110 * <ul> 111 * <li> 112 * Property {@code file} - Specify the location of the <em>suppressions XML document</em> file. 113 * Type is {@code java.lang.String}. 114 * Default value is {@code null}. 115 * </li> 116 * <li> 117 * Property {@code optional} - Control what to do when the file is not existing. 118 * If {@code optional} is set to {@code false} the file must exist, or else it 119 * ends with error. On the other hand if optional is {@code true} and file is 120 * not found, the filter accept all audit events. 121 * Type is {@code boolean}. 122 * Default value is {@code false}. 123 * </li> 124 * </ul> 125 * <p> 126 * For example, the following configuration fragment directs the Checker to use 127 * a {@code SuppressionFilter} with suppressions file {@code config/suppressions.xml}: 128 * </p> 129 * <pre> 130 * <module name="SuppressionFilter"> 131 * <property name="file" value="config/suppressions.xml"/> 132 * <property name="optional" value="false"/> 133 * </module> 134 * </pre> 135 * <p> 136 * The following suppressions XML document directs a {@code SuppressionFilter} to 137 * reject {@code JavadocStyleCheck} violations for lines 82 and 108 to 122 of file 138 * {@code AbstractComplexityCheck.java}, and {@code MagicNumberCheck} violations for 139 * line 221 of file {@code JavadocStyleCheck.java}, and 140 * {@code 'Missing a Javadoc comment'} violations for all lines and files: 141 * </p> 142 * <pre> 143 * <?xml version="1.0"?> 144 * 145 * <!DOCTYPE suppressions PUBLIC 146 * "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" 147 * "https://checkstyle.org/dtds/suppressions_1_2.dtd"> 148 * 149 * <suppressions> 150 * <suppress checks="JavadocStyleCheck" 151 * files="AbstractComplexityCheck.java" 152 * lines="82,108-122"/> 153 * <suppress checks="MagicNumberCheck" 154 * files="JavadocStyleCheck.java" 155 * lines="221"/> 156 * <suppress message="Missing a Javadoc comment"/> 157 * </suppressions> 158 * </pre> 159 * <p> 160 * Suppress check by <a href="https://checkstyle.org/config.html#Id">module id</a> 161 * when config have two instances on the same check: 162 * </p> 163 * <pre> 164 * <suppress id="stringEqual" files="SomeTestCode.java"/> 165 * </pre> 166 * <p> 167 * Suppress all checks for hidden files and folders: 168 * </p> 169 * <pre> 170 * <suppress files="[/\\]\..+" checks=".*"/> 171 * </pre> 172 * <p> 173 * Suppress all checks for Maven-generated code: 174 * </p> 175 * <pre> 176 * <suppress files="[/\\]target[/\\]" checks=".*"/> 177 * </pre> 178 * <p> 179 * Suppress all checks for archives, classes and other binary files: 180 * </p> 181 * <pre> 182 * <suppress files=".+\.(?:jar|zip|war|class|tar|bin)$" checks=".*"/> 183 * </pre> 184 * <p> 185 * Suppress all checks for image files: 186 * </p> 187 * <pre> 188 * <suppress files=".+\.(?:png|gif|jpg|jpeg)$" checks=".*"/> 189 * </pre> 190 * <p> 191 * Suppress all checks for non-java files: 192 * </p> 193 * <pre> 194 * <suppress files=".+\.(?:txt|xml|csv|sh|thrift|html|sql|eot|ttf|woff|css|png)$" 195 * checks=".*"/> 196 * </pre> 197 * <p> 198 * Suppress all checks in generated sources: 199 * </p> 200 * <pre> 201 * <suppress checks=".*" files="com[\\/]mycompany[\\/]app[\\/]gen[\\/]"/> 202 * </pre> 203 * <p> 204 * Suppress FileLength check on integration tests in certain folder: 205 * </p> 206 * <pre> 207 * <suppress checks="FileLength" 208 * files="com[\\/]mycompany[\\/]app[\\/].*IT.java"/> 209 * </pre> 210 * <p> 211 * Suppress naming violations on variable named 'log' in all files: 212 * </p> 213 * <pre> 214 * <suppress message="Name 'log' must match pattern"/> 215 * </pre> 216 * <p> 217 * Parent is {@code com.puppycrawl.tools.checkstyle.Checker} 218 * </p> 219 * 220 * @since 3.2 221 */ 222public class SuppressionFilter extends AutomaticBean implements Filter, ExternalResourceHolder { 223 224 /** Specify the location of the <em>suppressions XML document</em> file. */ 225 private String file; 226 /** 227 * Control what to do when the file is not existing. If {@code optional} is 228 * set to {@code false} the file must exist, or else it ends with error. 229 * On the other hand if optional is {@code true} and file is not found, 230 * the filter accept all audit events. 231 */ 232 private boolean optional; 233 /** Set of individual suppresses. */ 234 private FilterSet filters = new FilterSet(); 235 236 /** 237 * Setter to specify the location of the <em>suppressions XML document</em> file. 238 * 239 * @param fileName name of the suppressions file. 240 */ 241 public void setFile(String fileName) { 242 file = fileName; 243 } 244 245 /** 246 * Setter to control what to do when the file is not existing. 247 * If {@code optional} is set to {@code false} the file must exist, or else 248 * it ends with error. On the other hand if optional is {@code true} 249 * and file is not found, the filter accept all audit events. 250 * 251 * @param optional tells if config file existence is optional. 252 */ 253 public void setOptional(boolean optional) { 254 this.optional = optional; 255 } 256 257 @Override 258 public boolean accept(AuditEvent event) { 259 return filters.accept(event); 260 } 261 262 @Override 263 protected void finishLocalSetup() throws CheckstyleException { 264 if (file != null) { 265 if (optional) { 266 if (FilterUtil.isFileExists(file)) { 267 filters = SuppressionsLoader.loadSuppressions(file); 268 } 269 else { 270 filters = new FilterSet(); 271 } 272 } 273 else { 274 filters = SuppressionsLoader.loadSuppressions(file); 275 } 276 } 277 } 278 279 @Override 280 public Set<String> getExternalResourceLocations() { 281 return Collections.singleton(file); 282 } 283 284}