001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2024 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         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
142         */
143        public Builder reporter(AbstractViolationReporter val) {
144            reporter = val;
145            return this;
146        }
147
148        /**
149         * Specifies the compile-flags to compile a regular expression with
150         * and returns Builder object.
151         *
152         * @param val the format to use when matching lines.
153         * @return Builder object.
154         * @noinspection ReturnOfInnerClass
155         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
156         */
157        public Builder compileFlags(int val) {
158            compileFlags = val;
159            return this;
160        }
161
162        /**
163         * Specifies the format to use when matching lines and returns Builder object.
164         *
165         * @param val the format to use when matching lines.
166         * @return Builder object.
167         * @noinspection ReturnOfInnerClass
168         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
169         */
170        public Builder format(String val) {
171            format = val;
172            return this;
173        }
174
175        /**
176         * Specifies message to use when reporting a match and returns Builder object.
177         *
178         * @param val message to use when reporting a match.
179         * @return Builder object.
180         * @noinspection ReturnOfInnerClass
181         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
182         */
183        public Builder message(String val) {
184            message = val;
185            return this;
186        }
187
188        /**
189         * Specifies the minimum allowed number of detections and returns Builder object.
190         *
191         * @param val the minimum allowed number of detections.
192         * @return Builder object.
193         * @noinspection ReturnOfInnerClass
194         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
195         */
196        public Builder minimum(int val) {
197            minimum = val;
198            return this;
199        }
200
201        /**
202         * Specifies the maximum allowed number of detections and returns Builder object.
203         *
204         * @param val the maximum allowed number of detections.
205         * @return Builder object.
206         * @noinspection ReturnOfInnerClass
207         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
208         */
209        public Builder maximum(int val) {
210            maximum = val;
211            return this;
212        }
213
214        /**
215         * Specifies whether to ignore case when matching and returns Builder object.
216         *
217         * @param val whether to ignore case when matching.
218         * @return Builder object.
219         * @noinspection ReturnOfInnerClass, BooleanParameter
220         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
221         * @noinspectionreason BooleanParameter - check fields are boolean
222         */
223        public Builder ignoreCase(boolean val) {
224            ignoreCase = val;
225            return this;
226        }
227
228        /**
229         * Specifies the suppressor to use and returns Builder object.
230         *
231         * @param val the suppressor to use.
232         * @return current instance
233         * @noinspection ReturnOfInnerClass
234         * @noinspectionreason ReturnOfInnerClass - builder is only used in enclosing class
235         */
236        public Builder suppressor(MatchSuppressor val) {
237            suppressor = val;
238            return this;
239        }
240
241        /**
242         * Returns new DetectorOptions instance.
243         *
244         * @return DetectorOptions instance.
245         */
246        public DetectorOptions build() {
247            message = Optional.ofNullable(message).orElse("");
248            suppressor = Optional.ofNullable(suppressor).orElse(NeverSuppress.INSTANCE);
249            pattern = Optional.ofNullable(format).map(this::createPattern).orElse(null);
250            return DetectorOptions.this;
251        }
252
253        /**
254         * Creates pattern to use by DetectorOptions instance.
255         *
256         * @param formatValue the format to use.
257         * @return Pattern object.
258         */
259        private Pattern createPattern(String formatValue) {
260            int options = compileFlags;
261            if (ignoreCase) {
262                options |= Pattern.CASE_INSENSITIVE;
263            }
264            return Pattern.compile(formatValue, options);
265        }
266
267    }
268
269}