View Javadoc
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.Objects;
23  import java.util.regex.Pattern;
24  
25  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
26  import com.puppycrawl.tools.checkstyle.api.Filter;
27  
28  /**
29   * This filter element is immutable and processes {@link AuditEvent}
30   * objects based on the criteria of file, check, module id, line, and
31   * column. It rejects an AuditEvent if the following match:
32   * <ul>
33   *   <li>the event's file name; and</li>
34   *   <li>the check name or the module identifier; and</li>
35   *   <li>(optionally) the event's line is in the filter's line CSV; and</li>
36   *   <li>(optionally) the check's columns is in the filter's column CSV.</li>
37   * </ul>
38   *
39   */
40  public class SuppressFilterElement
41      implements Filter {
42  
43      /** The regexp to match file names against. */
44      private final Pattern fileRegexp;
45  
46      /** The regexp to match check names against. */
47      private final Pattern checkRegexp;
48  
49      /** The regexp to match message names against. */
50      private final Pattern messageRegexp;
51  
52      /** Module id filter. */
53      private final String moduleId;
54  
55      /** Line number filter. */
56      private final CsvFilterElement lineFilter;
57  
58      /** CSV for line number filter. */
59      private final String linesCsv;
60  
61      /** Column number filter. */
62      private final CsvFilterElement columnFilter;
63  
64      /** CSV for column number filter. */
65      private final String columnsCsv;
66  
67      /**
68       * Constructs a {@code SuppressFilterElement} for a
69       * file name pattern.
70       *
71       * @param files   regular expression for names of filtered files.
72       * @param checks  regular expression for filtered check classes.
73       * @param message regular expression for messages.
74       * @param modId   the id
75       * @param lines   lines CSV values and ranges for line number filtering.
76       * @param columns columns CSV values and ranges for column number filtering.
77       */
78      public SuppressFilterElement(String files, String checks,
79                             String message, String modId, String lines, String columns) {
80          if (files == null) {
81              fileRegexp = null;
82          }
83          else {
84              fileRegexp = Pattern.compile(files);
85          }
86          if (checks == null) {
87              checkRegexp = null;
88          }
89          else {
90              checkRegexp = Pattern.compile(checks);
91          }
92          if (message == null) {
93              messageRegexp = null;
94          }
95          else {
96              messageRegexp = Pattern.compile(message);
97          }
98          moduleId = modId;
99          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 }