001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2022 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.Objects; 023import java.util.regex.Pattern; 024 025import com.puppycrawl.tools.checkstyle.api.AuditEvent; 026import com.puppycrawl.tools.checkstyle.api.Filter; 027 028/** 029 * This filter element is immutable and processes {@link AuditEvent} 030 * objects based on the criteria of file, check, module id, line, and 031 * column. It rejects an AuditEvent if the following match: 032 * <ul> 033 * <li>the event's file name; and</li> 034 * <li>the check name or the module identifier; and</li> 035 * <li>(optionally) the event's line is in the filter's line CSV; and</li> 036 * <li>(optionally) the check's columns is in the filter's column CSV.</li> 037 * </ul> 038 * 039 */ 040public class SuppressFilterElement 041 implements Filter { 042 043 /** The regexp to match file names against. */ 044 private final Pattern fileRegexp; 045 046 /** The pattern for file names. */ 047 private final String filePattern; 048 049 /** The regexp to match check names against. */ 050 private final Pattern checkRegexp; 051 052 /** The pattern for check class names. */ 053 private final String checkPattern; 054 055 /** The regexp to match message names against. */ 056 private final Pattern messageRegexp; 057 058 /** The pattern for message names. */ 059 private final String messagePattern; 060 061 /** Module id filter. */ 062 private final String moduleId; 063 064 /** Line number filter. */ 065 private final CsvFilterElement lineFilter; 066 067 /** CSV for line number filter. */ 068 private final String linesCsv; 069 070 /** Column number filter. */ 071 private final CsvFilterElement columnFilter; 072 073 /** CSV for column number filter. */ 074 private final String columnsCsv; 075 076 /** 077 * Constructs a {@code SuppressFilterElement} for a 078 * file name pattern. 079 * 080 * @param files regular expression for names of filtered files. 081 * @param checks regular expression for filtered check classes. 082 * @param message regular expression for messages. 083 * @param modId the id 084 * @param lines lines CSV values and ranges for line number filtering. 085 * @param columns columns CSV values and ranges for column number filtering. 086 */ 087 public SuppressFilterElement(String files, String checks, 088 String message, String modId, String lines, String columns) { 089 filePattern = files; 090 if (files == null) { 091 fileRegexp = null; 092 } 093 else { 094 fileRegexp = Pattern.compile(files); 095 } 096 checkPattern = checks; 097 if (checks == null) { 098 checkRegexp = null; 099 } 100 else { 101 checkRegexp = Pattern.compile(checks); 102 } 103 messagePattern = message; 104 if (message == null) { 105 messageRegexp = null; 106 } 107 else { 108 messageRegexp = Pattern.compile(message); 109 } 110 moduleId = modId; 111 linesCsv = lines; 112 if (lines == null) { 113 lineFilter = null; 114 } 115 else { 116 lineFilter = new CsvFilterElement(lines); 117 } 118 columnsCsv = columns; 119 if (columns == null) { 120 columnFilter = null; 121 } 122 else { 123 columnFilter = new CsvFilterElement(columns); 124 } 125 } 126 127 /** 128 * Creates a {@code SuppressFilterElement} instance. 129 * 130 * @param files regular expression for filtered file names 131 * @param checks regular expression for filtered check classes 132 * @param message regular expression for messages. 133 * @param moduleId the module id 134 * @param lines CSV for lines 135 * @param columns CSV for columns 136 */ 137 public SuppressFilterElement(Pattern files, Pattern checks, Pattern message, String moduleId, 138 String lines, String columns) { 139 if (files == null) { 140 filePattern = null; 141 fileRegexp = null; 142 } 143 else { 144 filePattern = files.pattern(); 145 fileRegexp = files; 146 } 147 if (checks == null) { 148 checkPattern = null; 149 checkRegexp = null; 150 } 151 else { 152 checkPattern = checks.pattern(); 153 checkRegexp = checks; 154 } 155 if (message == null) { 156 messagePattern = null; 157 messageRegexp = null; 158 } 159 else { 160 messagePattern = message.pattern(); 161 messageRegexp = message; 162 } 163 this.moduleId = moduleId; 164 if (lines == null) { 165 linesCsv = null; 166 lineFilter = null; 167 } 168 else { 169 linesCsv = lines; 170 lineFilter = new CsvFilterElement(lines); 171 } 172 if (columns == null) { 173 columnsCsv = null; 174 columnFilter = null; 175 } 176 else { 177 columnsCsv = columns; 178 columnFilter = new CsvFilterElement(columns); 179 } 180 } 181 182 @Override 183 public boolean accept(AuditEvent event) { 184 return !isFileNameAndModuleNameMatching(event) 185 || !isMessageNameMatching(event) 186 || !isLineAndColumnMatching(event); 187 } 188 189 /** 190 * Is matching by file name, module id, and Check name. 191 * 192 * @param event event 193 * @return true if it is matching 194 */ 195 private boolean isFileNameAndModuleNameMatching(AuditEvent event) { 196 return event.getFileName() != null 197 && (fileRegexp == null || fileRegexp.matcher(event.getFileName()).find()) 198 && event.getViolation() != null 199 && (moduleId == null || moduleId.equals(event.getModuleId())) 200 && (checkRegexp == null || checkRegexp.matcher(event.getSourceName()).find()); 201 } 202 203 /** 204 * Is matching by message. 205 * 206 * @param event event 207 * @return true if it is matching or not set. 208 */ 209 private boolean isMessageNameMatching(AuditEvent event) { 210 return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find(); 211 } 212 213 /** 214 * Whether line and column match. 215 * 216 * @param event event to process. 217 * @return true if line and column are matching or not set. 218 */ 219 private boolean isLineAndColumnMatching(AuditEvent event) { 220 return lineFilter == null && columnFilter == null 221 || lineFilter != null && lineFilter.accept(event.getLine()) 222 || columnFilter != null && columnFilter.accept(event.getColumn()); 223 } 224 225 @Override 226 public int hashCode() { 227 return Objects.hash(filePattern, checkPattern, messagePattern, moduleId, linesCsv, 228 columnsCsv); 229 } 230 231 @Override 232 public boolean equals(Object other) { 233 if (this == other) { 234 return true; 235 } 236 if (other == null || getClass() != other.getClass()) { 237 return false; 238 } 239 final SuppressFilterElement suppressElement = (SuppressFilterElement) other; 240 return Objects.equals(filePattern, suppressElement.filePattern) 241 && Objects.equals(checkPattern, suppressElement.checkPattern) 242 && Objects.equals(messagePattern, suppressElement.messagePattern) 243 && Objects.equals(moduleId, suppressElement.moduleId) 244 && Objects.equals(linesCsv, suppressElement.linesCsv) 245 && Objects.equals(columnsCsv, suppressElement.columnsCsv); 246 } 247 248}