001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
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////////////////////////////////////////////////////////////////////////////////
019package com.puppycrawl.tools.checkstyle.filters;
020
021import com.puppycrawl.tools.checkstyle.api.AuditEvent;
022import com.puppycrawl.tools.checkstyle.api.Filter;
023import com.puppycrawl.tools.checkstyle.api.Utils;
024import java.util.regex.Pattern;
025import java.util.regex.PatternSyntaxException;
026
027/**
028 * This filter processes {@link com.puppycrawl.tools.checkstyle.api.AuditEvent}
029 * objects based on the criteria of file, check, module id, line, and
030 * column. It rejects an AuditEvent if the following match:
031 * <ul>
032 *   <li>the event's file name; and</li>
033 *   <li>the check name or the module identifier; and</li>
034 *   <li>(optionally) the event's line is in the filter's line CSV; and</li>
035 *   <li>(optionally) the check's columns is in the filter's column CSV.</li>
036 * </ul>
037 *
038 * @author Rick Giles
039 */
040public class SuppressElement
041    implements Filter
042{
043    /** hash function multiplicand */
044    private static final int HASH_MULT = 29;
045
046    /** the regexp to match file names against */
047    private final Pattern mFileRegexp;
048
049    /** the pattern for file names*/
050    private final String mFilePattern;
051
052    /** the regexp to match check names against */
053    private Pattern mCheckRegexp;
054
055    /** the pattern for check class names*/
056    private String mCheckPattern;
057
058    /** module id filter. */
059    private String mModuleId;
060
061    /** line number filter */
062    private CSVFilter mLineFilter;
063
064    /** CSV for line number filter */
065    private String mLinesCSV;
066
067    /** column number filter */
068    private CSVFilter mColumnFilter;
069
070    /** CSV for column number filter */
071    private String mColumnsCSV;
072
073    /**
074     * Constructs a <code>SuppressElement</code> for a
075     * file name pattern. Must either call {@link #setColumns(String)} or
076     * {@link #setModuleId(String)} before using this object.
077     * @param aFiles regular expression for names of filtered files.
078     * @throws PatternSyntaxException if there is an error.
079     */
080    public SuppressElement(String aFiles)
081        throws PatternSyntaxException
082    {
083        mFilePattern = aFiles;
084        mFileRegexp = Utils.getPattern(aFiles);
085    }
086
087    /**
088     * Set the check class pattern.
089     * @param aChecks regular expression for filtered check classes.
090     */
091    public void setChecks(final String aChecks)
092    {
093        mCheckPattern = aChecks;
094        mCheckRegexp = Utils.getPattern(aChecks);
095    }
096
097    /**
098     * Set the module id for filtering. Cannot be null.
099     * @param aModuleId the id
100     */
101    public void setModuleId(final String aModuleId)
102    {
103        mModuleId = aModuleId;
104    }
105    /**
106     * Sets the CSV values and ranges for line number filtering.
107     * E.g. "1,7-15,18".
108     * @param aLines CSV values and ranges for line number filtering.
109     */
110    public void setLines(String aLines)
111    {
112        mLinesCSV = aLines;
113        if (aLines != null) {
114            mLineFilter = new CSVFilter(aLines);
115        }
116        else {
117            mLineFilter = null;
118        }
119    }
120
121    /**
122     * Sets the CSV values and ranges for column number filtering.
123     *  E.g. "1,7-15,18".
124     * @param aColumns CSV values and ranges for column number filtering.
125     */
126    public void setColumns(String aColumns)
127    {
128        mColumnsCSV = aColumns;
129        if (aColumns != null) {
130            mColumnFilter = new CSVFilter(aColumns);
131        }
132        else {
133            mColumnFilter = null;
134        }
135    }
136
137    /** {@inheritDoc} */
138    public boolean accept(AuditEvent aEvent)
139    {
140        // file and check match?
141        if ((aEvent.getFileName() == null)
142                || !mFileRegexp.matcher(aEvent.getFileName()).find()
143                || (aEvent.getLocalizedMessage() == null)
144                || ((mModuleId != null) && !mModuleId.equals(aEvent
145                        .getModuleId()))
146                || ((mCheckRegexp != null) && !mCheckRegexp.matcher(
147                        aEvent.getSourceName()).find()))
148        {
149            return true;
150        }
151
152        // reject if no line/column matching
153        if ((mLineFilter == null) && (mColumnFilter == null)) {
154            return false;
155        }
156
157        if (mLineFilter != null && mLineFilter.accept(aEvent.getLine())) {
158            return false;
159        }
160
161        if (mColumnFilter != null && mColumnFilter.accept(aEvent.getColumn())) {
162            return false;
163        }
164        return true;
165    }
166
167    @Override
168    public String toString()
169    {
170        return "SuppressElement[files=" + mFilePattern + ",checks="
171            + mCheckPattern + ",lines=" + mLinesCSV + ",columns="
172            + mColumnsCSV + "]";
173    }
174
175    @Override
176    public int hashCode()
177    {
178        int result = HASH_MULT * mFilePattern.hashCode();
179        if (mCheckPattern != null) {
180            result = HASH_MULT * result + mCheckPattern.hashCode();
181        }
182        if (mModuleId != null) {
183            result = HASH_MULT * result + mModuleId.hashCode();
184        }
185        if (mLinesCSV != null) {
186            result = HASH_MULT * result + mLinesCSV.hashCode();
187        }
188        if (mColumnsCSV != null) {
189            result = HASH_MULT * result + mColumnsCSV.hashCode();
190        }
191        return result;
192    }
193
194    @Override
195    public boolean equals(Object aObject)
196    {
197        if (aObject instanceof SuppressElement) {
198            final SuppressElement other = (SuppressElement) aObject;
199
200            // same file pattern?
201            if (!this.mFilePattern.equals(other.mFilePattern)) {
202                return false;
203            }
204
205            // same check pattern?
206            if (mCheckPattern != null) {
207                if (!mCheckPattern.equals(other.mCheckPattern)) {
208                    return false;
209                }
210            }
211            else if (other.mCheckPattern != null) {
212                return false;
213            }
214
215            // same module id?
216            if (mModuleId != null) {
217                if (!mModuleId.equals(other.mModuleId)) {
218                    return false;
219                }
220            }
221            else if (other.mModuleId != null) {
222                return false;
223            }
224
225            // same line number filter?
226            if (mLineFilter != null) {
227                if (!mLineFilter.equals(other.mLineFilter)) {
228                    return false;
229                }
230            }
231            else if (other.mLineFilter != null) {
232                return false;
233            }
234
235            // same column number filter?
236            if (mColumnFilter != null) {
237                if (!mColumnFilter.equals(other.mColumnFilter)) {
238                    return false;
239                }
240            }
241            else if (other.mColumnFilter != null) {
242                return false;
243            }
244
245            // everything is the same
246            return true;
247        }
248        return false;
249    }
250}