001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2020 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.util.Optional;
023import java.util.regex.Pattern;
024
025import com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter;
026
027/**
028 * Options for a detector.
029 */
030public final class DetectorOptions {
031
032    /**
033     * Flags to compile a regular expression with.
034     * See {@link Pattern#flags()}.
035     */
036    private int compileFlags;
037    /** Used for reporting violations. */
038    private AbstractViolationReporter reporter;
039    /**
040     * Format of the regular expression to check for.
041     */
042    private String format;
043    /** The message to report on detection. If blank, then use the format. */
044    private String message = "";
045    /** Minimum number of times regular expression should occur in a file. */
046    private int minimum;
047    /** Maximum number of times regular expression should occur in a file. */
048    private int maximum;
049    /** Whether to ignore case when matching. */
050    private boolean ignoreCase;
051    /** Used to determine whether to suppress a detected match. */
052    private MatchSuppressor suppressor;
053    /** Pattern created from format. Lazily initialized. */
054    private Pattern pattern;
055
056    /** Default constructor.*/
057    private DetectorOptions() {
058    }
059
060    /**
061     * Returns new Builder object.
062     *
063     * @return Builder object.
064     */
065    public static Builder newBuilder() {
066        return new DetectorOptions().new Builder();
067    }
068
069    /**
070     * Format of the regular expression.
071     *
072     * @return format of the regular expression.
073     */
074    public String getFormat() {
075        return format;
076    }
077
078    /**
079     * The violation reporter to use.
080     *
081     * @return the violation reporter to use.
082     */
083    public AbstractViolationReporter getReporter() {
084        return reporter;
085    }
086
087    /**
088     * The message to report violations with.
089     *
090     * @return the message to report violations with.
091     */
092    public String getMessage() {
093        return message;
094    }
095
096    /**
097     * The minimum number of allowed detections.
098     *
099     * @return the minimum number of allowed detections.
100     */
101    public int getMinimum() {
102        return minimum;
103    }
104
105    /**
106     * The maximum number of allowed detections.
107     *
108     * @return the maximum number of allowed detections.
109     */
110    public int getMaximum() {
111        return maximum;
112    }
113
114    /**
115     * The suppressor to use.
116     *
117     * @return the suppressor to use.
118     */
119    public MatchSuppressor getSuppressor() {
120        return suppressor;
121    }
122
123    /**
124     * The pattern to use when matching.
125     *
126     * @return the pattern to use when matching.
127     */
128    public Pattern getPattern() {
129        return pattern;
130    }
131
132    /** Class which implements Builder pattern to build DetectorOptions instance. */
133    public final class Builder {
134
135        /**
136         * Specifies the violation reporter and returns Builder object.
137         *
138         * @param val for reporting violations.
139         * @return Builder object.
140         * @noinspection ReturnOfInnerClass
141         */
142        public Builder reporter(AbstractViolationReporter val) {
143            reporter = val;
144            return this;
145        }
146
147        /**
148         * Specifies the compile flags to compile a regular expression with
149         * and returns Builder object.
150         *
151         * @param val the format to use when matching lines.
152         * @return Builder object.
153         * @noinspection ReturnOfInnerClass
154         */
155        public Builder compileFlags(int val) {
156            compileFlags = val;
157            return this;
158        }
159
160        /**
161         * Specifies the format to use when matching lines and returns Builder object.
162         *
163         * @param val the format to use when matching lines.
164         * @return Builder object.
165         * @noinspection ReturnOfInnerClass
166         */
167        public Builder format(String val) {
168            format = val;
169            return this;
170        }
171
172        /**
173         * Specifies message to use when reporting a match and returns Builder object.
174         *
175         * @param val message to use when reporting a match.
176         * @return Builder object.
177         * @noinspection ReturnOfInnerClass
178         */
179        public Builder message(String val) {
180            message = val;
181            return this;
182        }
183
184        /**
185         * Specifies the minimum allowed number of detections and returns Builder object.
186         *
187         * @param val the minimum allowed number of detections.
188         * @return Builder object.
189         * @noinspection ReturnOfInnerClass
190         */
191        public Builder minimum(int val) {
192            minimum = val;
193            return this;
194        }
195
196        /**
197         * Specifies the maximum allowed number of detections and returns Builder object.
198         *
199         * @param val the maximum allowed number of detections.
200         * @return Builder object.
201         * @noinspection ReturnOfInnerClass
202         */
203        public Builder maximum(int val) {
204            maximum = val;
205            return this;
206        }
207
208        /**
209         * Specifies whether to ignore case when matching and returns Builder object.
210         *
211         * @param val whether to ignore case when matching.
212         * @return Builder object.
213         * @noinspection ReturnOfInnerClass, BooleanParameter
214         */
215        public Builder ignoreCase(boolean val) {
216            ignoreCase = val;
217            return this;
218        }
219
220        /**
221         * Specifies the suppressor to use and returns Builder object.
222         *
223         * @param val the suppressor to use.
224         * @return current instance
225         * @noinspection ReturnOfInnerClass
226         */
227        public Builder suppressor(MatchSuppressor val) {
228            suppressor = val;
229            return this;
230        }
231
232        /**
233         * Returns new DetectorOptions instance.
234         *
235         * @return DetectorOptions instance.
236         */
237        public DetectorOptions build() {
238            message = Optional.ofNullable(message).orElse("");
239            suppressor = Optional.ofNullable(suppressor).orElse(NeverSuppress.INSTANCE);
240            pattern = Optional.ofNullable(format).map(this::createPattern).orElse(null);
241            return DetectorOptions.this;
242        }
243
244        /**
245         * Creates pattern to use by DetectorOptions instance.
246         *
247         * @param formatValue the format to use.
248         * @return Pattern object.
249         */
250        private Pattern createPattern(String formatValue) {
251            int options = compileFlags;
252            if (ignoreCase) {
253                options |= Pattern.CASE_INSENSITIVE;
254            }
255            return Pattern.compile(formatValue, options);
256        }
257
258    }
259
260}