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 com.puppycrawl.tools.checkstyle.StatelessCheck;
023import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
024import com.puppycrawl.tools.checkstyle.api.DetailAST;
025import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
026
027/**
028 * <p>
029 * A check for detecting single lines that match a supplied
030 * regular expression in Java files.
031 * </p>
032 * <p>
033 * This class is variation on
034 * <a href="https://checkstyle.org/config_regexp.html#RegexpSingleline">RegexpSingleline</a>
035 * for detecting single lines that match a supplied regular expression in Java files.
036 * It supports suppressing matches in Java comments.
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 ignoreComments} - Control whether to ignore text in comments when searching.
062 * Default value is {@code false}.
063 * </li>
064 * </ul>
065 * <p>
066 * To configure the check for calls to {@code System.out.println}, except in comments:
067 * </p>
068 * <pre>
069 * &lt;module name="RegexpSinglelineJava"&gt;
070 *   &lt;!-- . matches any character, so we need to
071 *        escape it and use \. to match dots. --&gt;
072 *   &lt;property name="format" value="System\.out\.println"/&gt;
073 *   &lt;property name="ignoreComments" value="true"/&gt;
074 * &lt;/module&gt;
075 * </pre>
076 * <p>
077 * To configure the check to find case-insensitive occurrences of "debug":
078 * </p>
079 * <pre>
080 * &lt;module name="RegexpSinglelineJava"&gt;
081 *   &lt;property name="format" value="debug"/&gt;
082 *   &lt;property name="ignoreCase" value="true"/&gt;
083 * &lt;/module&gt;
084 * </pre>
085 *
086 * @since 6.0
087 */
088@StatelessCheck
089public class RegexpSinglelineJavaCheck extends AbstractCheck {
090
091    /** Specify the format of the regular expression to match. */
092    private String format = "$.";
093    /**
094     * Specify the message which is used to notify about violations,
095     * if empty then default (hard-coded) message is used.
096     */
097    private String message;
098    /** Specify the minimum number of matches required in each file. */
099    private int minimum;
100    /** Specify the maximum number of matches required in each file. */
101    private int maximum;
102    /** Control whether to ignore case when searching. */
103    private boolean ignoreCase;
104    /** Control whether to ignore text in comments when searching. */
105    private boolean ignoreComments;
106
107    @Override
108    public int[] getDefaultTokens() {
109        return getRequiredTokens();
110    }
111
112    @Override
113    public int[] getAcceptableTokens() {
114        return getRequiredTokens();
115    }
116
117    @Override
118    public int[] getRequiredTokens() {
119        return CommonUtil.EMPTY_INT_ARRAY;
120    }
121
122    @Override
123    public void beginTree(DetailAST rootAST) {
124        MatchSuppressor suppressor = null;
125        if (ignoreComments) {
126            suppressor = new CommentSuppressor(getFileContents());
127        }
128
129        final DetectorOptions options = DetectorOptions.newBuilder()
130            .reporter(this)
131            .compileFlags(0)
132            .suppressor(suppressor)
133            .format(format)
134            .message(message)
135            .minimum(minimum)
136            .maximum(maximum)
137            .ignoreCase(ignoreCase)
138            .build();
139        final SinglelineDetector detector = new SinglelineDetector(options);
140        detector.processLines(getFileContents().getText());
141    }
142
143    /**
144     * Setter to specify the format of the regular expression to match.
145     *
146     * @param format the format of the regular expression to match.
147     */
148    public void setFormat(String format) {
149        this.format = format;
150    }
151
152    /**
153     * Setter to specify the message which is used to notify about violations,
154     * if empty then default (hard-coded) message is used.
155     *
156     * @param message the message to report for a match.
157     */
158    public void setMessage(String message) {
159        this.message = message;
160    }
161
162    /**
163     * Setter to specify the minimum number of matches required in each file.
164     *
165     * @param minimum the minimum number of matches required in each file.
166     */
167    public void setMinimum(int minimum) {
168        this.minimum = minimum;
169    }
170
171    /**
172     * Setter to specify the maximum number of matches required in each file.
173     *
174     * @param maximum the maximum number of matches required in each file.
175     */
176    public void setMaximum(int maximum) {
177        this.maximum = maximum;
178    }
179
180    /**
181     * Setter to control whether to ignore case when searching.
182     *
183     * @param ignoreCase whether to ignore case when searching.
184     */
185    public void setIgnoreCase(boolean ignoreCase) {
186        this.ignoreCase = ignoreCase;
187    }
188
189    /**
190     * Setter to control whether to ignore text in comments when searching.
191     *
192     * @param ignore whether to ignore text in comments when searching.
193     */
194    public void setIgnoreComments(boolean ignore) {
195        ignoreComments = ignore;
196    }
197
198}