1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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 pattern for file names. */
47      private final String filePattern;
48  
49      /** The regexp to match check names against. */
50      private final Pattern checkRegexp;
51  
52      /** The pattern for check class names. */
53      private final String checkPattern;
54  
55      /** The regexp to match message names against. */
56      private final Pattern messageRegexp;
57  
58      /** The pattern for message names. */
59      private final String messagePattern;
60  
61      /** Module id filter. */
62      private final String moduleId;
63  
64      /** Line number filter. */
65      private final CsvFilterElement lineFilter;
66  
67      /** CSV for line number filter. */
68      private final String linesCsv;
69  
70      /** Column number filter. */
71      private final CsvFilterElement columnFilter;
72  
73      /** CSV for column number filter. */
74      private final String columnsCsv;
75  
76      /**
77       * Constructs a {@code SuppressFilterElement} for a
78       * file name pattern.
79       *
80       * @param files   regular expression for names of filtered files.
81       * @param checks  regular expression for filtered check classes.
82       * @param message regular expression for messages.
83       * @param modId   the id
84       * @param lines   lines CSV values and ranges for line number filtering.
85       * @param columns columns CSV values and ranges for column number filtering.
86       */
87      public SuppressFilterElement(String files, String checks,
88                             String message, String modId, String lines, String columns) {
89          filePattern = files;
90          if (files == null) {
91              fileRegexp = null;
92          }
93          else {
94              fileRegexp = Pattern.compile(files);
95          }
96          checkPattern = checks;
97          if (checks == null) {
98              checkRegexp = null;
99          }
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     @Override
128     public boolean accept(AuditEvent event) {
129         return !isFileNameAndModuleNameMatching(event)
130                 || !isMessageNameMatching(event)
131                 || !isLineAndColumnMatching(event);
132     }
133 
134     /**
135      * Is matching by file name, module id, and Check name.
136      * @param event event
137      * @return true if it is matching
138      */
139     private boolean isFileNameAndModuleNameMatching(AuditEvent event) {
140         return event.getFileName() != null
141                 && (fileRegexp == null || fileRegexp.matcher(event.getFileName()).find())
142                 && event.getLocalizedMessage() != null
143                 && (moduleId == null || moduleId.equals(event.getModuleId()))
144                 && (checkRegexp == null || checkRegexp.matcher(event.getSourceName()).find());
145     }
146 
147     /**
148      * Is matching by message.
149      * @param event event
150      * @return true if it is matching or not set.
151      */
152     private boolean isMessageNameMatching(AuditEvent event) {
153         return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find();
154     }
155 
156     /**
157      * Whether line and column match.
158      * @param event event to process.
159      * @return true if line and column are matching or not set.
160      */
161     private boolean isLineAndColumnMatching(AuditEvent event) {
162         return lineFilter == null && columnFilter == null
163                 || lineFilter != null && lineFilter.accept(event.getLine())
164                 || columnFilter != null && columnFilter.accept(event.getColumn());
165     }
166 
167     @Override
168     public int hashCode() {
169         return Objects.hash(filePattern, checkPattern, messagePattern, moduleId, linesCsv,
170                 columnsCsv);
171     }
172 
173     @Override
174     public boolean equals(Object other) {
175         if (this == other) {
176             return true;
177         }
178         if (other == null || getClass() != other.getClass()) {
179             return false;
180         }
181         final SuppressFilterElement suppressElement = (SuppressFilterElement) other;
182         return Objects.equals(filePattern, suppressElement.filePattern)
183                 && Objects.equals(checkPattern, suppressElement.checkPattern)
184                 && Objects.equals(messagePattern, suppressElement.messagePattern)
185                 && Objects.equals(moduleId, suppressElement.moduleId)
186                 && Objects.equals(linesCsv, suppressElement.linesCsv)
187                 && Objects.equals(columnsCsv, suppressElement.columnsCsv);
188     }
189 
190 }