001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2024 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 regexp to match check names against. */ 047 private final Pattern checkRegexp; 048 049 /** The regexp to match message names against. */ 050 private final Pattern messageRegexp; 051 052 /** Module id filter. */ 053 private final String moduleId; 054 055 /** Line number filter. */ 056 private final CsvFilterElement lineFilter; 057 058 /** CSV for line number filter. */ 059 private final String linesCsv; 060 061 /** Column number filter. */ 062 private final CsvFilterElement columnFilter; 063 064 /** CSV for column number filter. */ 065 private final String columnsCsv; 066 067 /** 068 * Constructs a {@code SuppressFilterElement} for a 069 * file name pattern. 070 * 071 * @param files regular expression for names of filtered files. 072 * @param checks regular expression for filtered check classes. 073 * @param message regular expression for messages. 074 * @param modId the id 075 * @param lines lines CSV values and ranges for line number filtering. 076 * @param columns columns CSV values and ranges for column number filtering. 077 */ 078 public SuppressFilterElement(String files, String checks, 079 String message, String modId, String lines, String columns) { 080 if (files == null) { 081 fileRegexp = null; 082 } 083 else { 084 fileRegexp = Pattern.compile(files); 085 } 086 if (checks == null) { 087 checkRegexp = null; 088 } 089 else { 090 checkRegexp = Pattern.compile(checks); 091 } 092 if (message == null) { 093 messageRegexp = null; 094 } 095 else { 096 messageRegexp = Pattern.compile(message); 097 } 098 moduleId = modId; 099 linesCsv = lines; 100 if (lines == null) { 101 lineFilter = null; 102 } 103 else { 104 lineFilter = new CsvFilterElement(lines); 105 } 106 columnsCsv = columns; 107 if (columns == null) { 108 columnFilter = null; 109 } 110 else { 111 columnFilter = new CsvFilterElement(columns); 112 } 113 } 114 115 /** 116 * Creates a {@code SuppressFilterElement} instance. 117 * 118 * @param files regular expression for filtered file names 119 * @param checks regular expression for filtered check classes 120 * @param message regular expression for messages. 121 * @param moduleId the module id 122 * @param lines CSV for lines 123 * @param columns CSV for columns 124 */ 125 public SuppressFilterElement(Pattern files, Pattern checks, Pattern message, String moduleId, 126 String lines, String columns) { 127 fileRegexp = files; 128 checkRegexp = checks; 129 messageRegexp = message; 130 this.moduleId = moduleId; 131 if (lines == null) { 132 linesCsv = null; 133 lineFilter = null; 134 } 135 else { 136 linesCsv = lines; 137 lineFilter = new CsvFilterElement(lines); 138 } 139 if (columns == null) { 140 columnsCsv = null; 141 columnFilter = null; 142 } 143 else { 144 columnsCsv = columns; 145 columnFilter = new CsvFilterElement(columns); 146 } 147 } 148 149 @Override 150 public boolean accept(AuditEvent event) { 151 return !isFileNameAndModuleNameMatching(event) 152 || !isMessageNameMatching(event) 153 || !isLineAndColumnMatching(event); 154 } 155 156 /** 157 * Is matching by file name, module id, and Check name. 158 * 159 * @param event event 160 * @return true if it is matching 161 */ 162 private boolean isFileNameAndModuleNameMatching(AuditEvent event) { 163 return event.getFileName() != null 164 && (fileRegexp == null || fileRegexp.matcher(event.getFileName()).find()) 165 && event.getViolation() != null 166 && (moduleId == null || moduleId.equals(event.getModuleId())) 167 && (checkRegexp == null || checkRegexp.matcher(event.getSourceName()).find()); 168 } 169 170 /** 171 * Is matching by message. 172 * 173 * @param event event 174 * @return true if it is matching or not set. 175 */ 176 private boolean isMessageNameMatching(AuditEvent event) { 177 return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find(); 178 } 179 180 /** 181 * Whether line and column match. 182 * 183 * @param event event to process. 184 * @return true if line and column are matching or not set. 185 */ 186 private boolean isLineAndColumnMatching(AuditEvent event) { 187 return lineFilter == null && columnFilter == null 188 || lineFilter != null && lineFilter.accept(event.getLine()) 189 || columnFilter != null && columnFilter.accept(event.getColumn()); 190 } 191 192 @Override 193 public int hashCode() { 194 return Objects.hash(getPatternSafely(fileRegexp), getPatternSafely(checkRegexp), 195 getPatternSafely(messageRegexp), moduleId, linesCsv, columnsCsv); 196 } 197 198 @Override 199 public boolean equals(Object other) { 200 if (this == other) { 201 return true; 202 } 203 if (other == null || getClass() != other.getClass()) { 204 return false; 205 } 206 final SuppressFilterElement suppressElement = (SuppressFilterElement) other; 207 return Objects.equals(getPatternSafely(fileRegexp), 208 getPatternSafely(suppressElement.fileRegexp)) 209 && Objects.equals(getPatternSafely(checkRegexp), 210 getPatternSafely(suppressElement.checkRegexp)) 211 && Objects.equals(getPatternSafely(messageRegexp), 212 getPatternSafely(suppressElement.messageRegexp)) 213 && Objects.equals(moduleId, suppressElement.moduleId) 214 && Objects.equals(linesCsv, suppressElement.linesCsv) 215 && Objects.equals(columnsCsv, suppressElement.columnsCsv); 216 } 217 218 /** 219 * Util method to get pattern String value from Pattern object safely, return null if 220 * pattern object is null. 221 * 222 * @param pattern pattern object 223 * @return value of pattern or null 224 */ 225 private static String getPatternSafely(Pattern pattern) { 226 String result = null; 227 if (pattern != null) { 228 result = pattern.pattern(); 229 } 230 return result; 231 } 232}