001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2026 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    /** Which capturing group to use for violation reporting. */
056    private int reportGroup;
057
058    /** Default constructor.*/
059    private DetectorOptions() {
060    }
061
062    /**
063     * Returns new Builder object.
064     *
065     * @return Builder object.
066     */
067    public static Builder newBuilder() {
068        return new DetectorOptions().new Builder();
069    }
070
071    /**
072     * Format of the regular expression.
073     *
074     * @return format of the regular expression.
075     */
076    public String getFormat() {
077        return format;
078    }
079
080    /**
081     * The violation reporter to use.
082     *
083     * @return the violation reporter to use.
084     */
085    public AbstractViolationReporter getReporter() {
086        return reporter;
087    }
088
089    /**
090     * The message to report violations with.
091     *
092     * @return the message to report violations with.
093     */
094    public String getMessage() {
095        return message;
096    }
097
098    /**
099     * The minimum number of allowed detections.
100     *
101     * @return the minimum number of allowed detections.
102     */
103    public int getMinimum() {
104        return minimum;
105    }
106
107    /**
108     * The maximum number of allowed detections.
109     *
110     * @return the maximum number of allowed detections.
111     */
112    public int getMaximum() {
113        return maximum;
114    }
115
116    /**
117     * The suppressor to use.
118     *
119     * @return the suppressor to use.
120     */
121    public MatchSuppressor getSuppressor() {
122        return suppressor;
123    }
124
125    /**
126     * The pattern to use when matching.
127     *
128     * @return the pattern to use when matching.
129     */
130    public Pattern getPattern() {
131        return pattern;
132    }
133
134    /**
135     * Which capturing group to use for violation reporting.
136     *
137     * @return the capturing group to use for violation reporting.
138     */
139    public int getReportGroup() {
140        return reportGroup;
141    }
142
143    /** Class which implements Builder pattern to build DetectorOptions instance. */
144    public final class Builder {
145
146        /**
147         * Specifies the violation reporter and returns Builder object.
148         *
149         * @param val for reporting violations.
150         * @return Builder object.
151         * @noinspection ReturnOfInnerClass
152         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
153         */
154        public Builder reporter(AbstractViolationReporter val) {
155            reporter = val;
156            return this;
157        }
158
159        /**
160         * Specifies which capturing group to use for violation reporting.
161         *
162         * @param val the capturing group to use.
163         * @return Builder object.
164         * @noinspection ReturnOfInnerClass
165         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
166         */
167        public Builder reportGroup(int val) {
168            reportGroup = val;
169            return this;
170        }
171
172        /**
173         * Specifies the compile-flags to compile a regular expression with
174         * and returns Builder object.
175         *
176         * @param val the format to use when matching lines.
177         * @return Builder object.
178         * @noinspection ReturnOfInnerClass
179         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
180         */
181        public Builder compileFlags(int val) {
182            compileFlags = val;
183            return this;
184        }
185
186        /**
187         * Specifies the format to use when matching lines and returns Builder object.
188         *
189         * @param val the format to use when matching lines.
190         * @return Builder object.
191         * @noinspection ReturnOfInnerClass
192         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
193         */
194        public Builder format(String val) {
195            format = val;
196            return this;
197        }
198
199        /**
200         * Specifies message to use when reporting a match and returns Builder object.
201         *
202         * @param val message to use when reporting a match.
203         * @return Builder object.
204         * @noinspection ReturnOfInnerClass
205         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
206         */
207        public Builder message(String val) {
208            message = val;
209            return this;
210        }
211
212        /**
213         * Specifies the minimum allowed number of detections and returns Builder object.
214         *
215         * @param val the minimum allowed number of detections.
216         * @return Builder object.
217         * @noinspection ReturnOfInnerClass
218         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
219         */
220        public Builder minimum(int val) {
221            minimum = val;
222            return this;
223        }
224
225        /**
226         * Specifies the maximum allowed number of detections and returns Builder object.
227         *
228         * @param val the maximum allowed number of detections.
229         * @return Builder object.
230         * @noinspection ReturnOfInnerClass
231         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
232         */
233        public Builder maximum(int val) {
234            maximum = val;
235            return this;
236        }
237
238        /**
239         * Specifies whether to ignore case when matching and returns Builder object.
240         *
241         * @param val whether to ignore case when matching.
242         * @return Builder object.
243         * @noinspection ReturnOfInnerClass, BooleanParameter
244         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
245         * @noinspectionreason BooleanParameter - check fields are boolean
246         */
247        public Builder ignoreCase(boolean val) {
248            ignoreCase = val;
249            return this;
250        }
251
252        /**
253         * Specifies the suppressor to use and returns Builder object.
254         *
255         * @param val the suppressor to use.
256         * @return current instance
257         * @noinspection ReturnOfInnerClass
258         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
259         */
260        public Builder suppressor(MatchSuppressor val) {
261            suppressor = val;
262            return this;
263        }
264
265        /**
266         * Returns new DetectorOptions instance.
267         *
268         * @return DetectorOptions instance.
269         */
270        public DetectorOptions build() {
271            message = Optional.ofNullable(message).orElse("");
272            suppressor = Optional.ofNullable(suppressor).orElse(NeverSuppress.INSTANCE);
273            pattern = Optional.ofNullable(format).map(this::createPattern).orElse(null);
274
275            reportGroup = Math.max(0, reportGroup);
276
277            return DetectorOptions.this;
278        }
279
280        /**
281         * Creates pattern to use by DetectorOptions instance.
282         *
283         * @param formatValue the format to use.
284         * @return Pattern object.
285         */
286        private Pattern createPattern(String formatValue) {
287            int options = compileFlags;
288            if (ignoreCase) {
289                options |= Pattern.CASE_INSENSITIVE;
290            }
291            return Pattern.compile(formatValue, options);
292        }
293
294    }
295
296}