001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2019 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.checks.regexp;
021
022import java.io.File;
023
024import com.puppycrawl.tools.checkstyle.StatelessCheck;
025import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
026import com.puppycrawl.tools.checkstyle.api.FileText;
027
028/**
029 * <p>
030 * A check for detecting single lines that match a supplied regular expression.
031 * Works with any file type.
032 * </p>
033 * <p>
034 * Rationale: This check can be used to prototype checks and to find common bad
035 * practice such as calling {@code ex.printStacktrace()},
036 * {@code System.out.println()}, {@code System.exit()}, etc.
037 * </p>
038 * <ul>
039 * <li>
040 * Property {@code format} - Specify the format of the regular expression to match.
041 * Default value is {@code "$."}.
042 * </li>
043 * <li>
044 * Property {@code message} - Specify the message which is used to notify about
045 * violations, if empty then default (hard-coded) message is used.
046 * Default value is {@code null}.
047 * </li>
048 * <li>
049 * Property {@code ignoreCase} - Control whether to ignore case when searching.
050 * Default value is {@code false}.
051 * </li>
052 * <li>
053 * Property {@code minimum} - Specify the minimum number of matches required in each file.
054 * Default value is {@code 0}.
055 * </li>
056 * <li>
057 * Property {@code maximum} - Specify the maximum number of matches required in each file.
058 * Default value is {@code 0}.
059 * </li>
060 * <li>
061 * Property {@code fileExtensions} - Specify the file type extension of files to process.
062 * Default value is {@code all files}.
063 * </li>
064 * </ul>
065 * <p>
066 * To configure the check to find trailing whitespace at the end of a line:
067 * </p>
068 * <pre>
069 * &lt;module name="RegexpSingleline"&gt;
070 *   &lt;!-- \s matches whitespace character, $ matches end of line. --&gt;
071 *   &lt;property name="format" value="\s+$"/&gt;
072 * &lt;/module&gt;
073 * </pre>
074 * <p>
075 * To configure the check to find trailing whitespace at the end of a line,
076 * with some <i>slack</i> of allowing two occurrences per file:
077 * </p>
078 * <pre>
079 * &lt;module name="RegexpSingleline"&gt;
080 *   &lt;property name="format" value="\s+$"/&gt;
081 *   &lt;!-- next line not required as 0 is the default --&gt;
082 *   &lt;property name="minimum" value="0"/&gt;
083 *   &lt;property name="maximum" value="2"/&gt;
084 * &lt;/module&gt;
085 * </pre>
086 * <p>
087 * An example of how to configure the check to make sure a copyright statement
088 * is included in the file:
089 * </p>
090 * <pre>
091 * &lt;module name="RegexpSingleline"&gt;
092 *   &lt;property name="format" value="This file is copyrighted"/&gt;
093 *   &lt;property name="minimum" value="1"/&gt;
094 *   &lt;!--  Need to specify a maximum, so 10 times is more than enough. --&gt;
095 *   &lt;property name="maximum" value="10"/&gt;
096 * &lt;/module&gt;
097 * </pre>
098 *
099 * @since 5.0
100 */
101@StatelessCheck
102public class RegexpSinglelineCheck extends AbstractFileSetCheck {
103
104    /** Specify the format of the regular expression to match. */
105    private String format = "$.";
106    /**
107     * Specify the message which is used to notify about violations,
108     * if empty then default (hard-coded) message is used.
109     */
110    private String message;
111    /** Specify the minimum number of matches required in each file. */
112    private int minimum;
113    /** Specify the maximum number of matches required in each file. */
114    private int maximum;
115    /** Control whether to ignore case when searching. */
116    private boolean ignoreCase;
117
118    /** The detector to use. */
119    private SinglelineDetector detector;
120
121    @Override
122    public void beginProcessing(String charset) {
123        final DetectorOptions options = DetectorOptions.newBuilder()
124            .reporter(this)
125            .compileFlags(0)
126            .format(format)
127            .message(message)
128            .minimum(minimum)
129            .maximum(maximum)
130            .ignoreCase(ignoreCase)
131            .build();
132        detector = new SinglelineDetector(options);
133    }
134
135    @Override
136    protected void processFiltered(File file, FileText fileText) {
137        detector.processLines(fileText);
138    }
139
140    /**
141     * Setter to specify the format of the regular expression to match.
142     *
143     * @param format the format of the regular expression to match.
144     */
145    public void setFormat(String format) {
146        this.format = format;
147    }
148
149    /**
150     * Setter to specify the message which is used to notify about violations,
151     * if empty then default (hard-coded) message is used.
152     *
153     * @param message the message to report for a match.
154     */
155    public void setMessage(String message) {
156        this.message = message;
157    }
158
159    /**
160     * Setter to specify the minimum number of matches required in each file.
161     *
162     * @param minimum the minimum number of matches required in each file.
163     */
164    public void setMinimum(int minimum) {
165        this.minimum = minimum;
166    }
167
168    /**
169     * Setter to specify the maximum number of matches required in each file.
170     *
171     * @param maximum the maximum number of matches required in each file.
172     */
173    public void setMaximum(int maximum) {
174        this.maximum = maximum;
175    }
176
177    /**
178     * Setter to control whether to ignore case when searching.
179     *
180     * @param ignoreCase whether to ignore case when searching.
181     */
182    public void setIgnoreCase(boolean ignoreCase) {
183        this.ignoreCase = ignoreCase;
184    }
185
186}