1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.regexp;
21  
22  import java.util.Optional;
23  import java.util.regex.Pattern;
24  
25  import com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter;
26  
27  /**
28   * Options for a detector.
29   */
30  public final class DetectorOptions {
31  
32      /**
33       * Flags to compile a regular expression with.
34       * See {@link Pattern#flags()}.
35       */
36      private int compileFlags;
37      /** Used for reporting violations. */
38      private AbstractViolationReporter reporter;
39      /**
40       * Format of the regular expression to check for.
41       */
42      private String format;
43      /** The message to report on detection. If blank, then use the format. */
44      private String message = "";
45      /** Minimum number of times regular expression should occur in a file. */
46      private int minimum;
47      /** Maximum number of times regular expression should occur in a file. */
48      private int maximum;
49      /** Whether to ignore case when matching. */
50      private boolean ignoreCase;
51      /** Used to determine whether to suppress a detected match. */
52      private MatchSuppressor suppressor;
53      /** Pattern created from format. Lazily initialized. */
54      private Pattern pattern;
55  
56      /** Default constructor.*/
57      private DetectorOptions() {
58      }
59  
60      /**
61       * Returns new Builder object.
62       * @return Builder object.
63       */
64      public static Builder newBuilder() {
65          return new DetectorOptions().new Builder();
66      }
67  
68      /**
69       * Format of the regular expression.
70       * @return format of the regular expression.
71       */
72      public String getFormat() {
73          return format;
74      }
75  
76      /**
77       * The violation reporter to use.
78       * @return the violation reporter to use.
79       */
80      public AbstractViolationReporter getReporter() {
81          return reporter;
82      }
83  
84      /**
85       * The message to report errors with.
86       * @return the message to report errors with.
87       */
88      public String getMessage() {
89          return message;
90      }
91  
92      /**
93       * The minimum number of allowed detections.
94       * @return the minimum number of allowed detections.
95       */
96      public int getMinimum() {
97          return minimum;
98      }
99  
100     /**
101      * The maximum number of allowed detections.
102      * @return the maximum number of allowed detections.
103      */
104     public int getMaximum() {
105         return maximum;
106     }
107 
108     /**
109      * The suppressor to use.
110      * @return the suppressor to use.
111      */
112     public MatchSuppressor getSuppressor() {
113         return suppressor;
114     }
115 
116     /**
117      * The pattern to use when matching.
118      * @return the pattern to use when matching.
119      */
120     public Pattern getPattern() {
121         if (pattern == null) {
122             int options = compileFlags;
123 
124             if (ignoreCase) {
125                 options |= Pattern.CASE_INSENSITIVE;
126             }
127             pattern = Pattern.compile(format, options);
128         }
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          * @param val for reporting violations.
138          * @return Builder object.
139          * @noinspection ReturnOfInnerClass
140          */
141         public Builder reporter(AbstractViolationReporter val) {
142             reporter = val;
143             return this;
144         }
145 
146         /**
147          * Specifies the compile flags to compile a regular expression with
148          * and returns Builder object.
149          * @param val the format to use when matching lines.
150          * @return Builder object.
151          * @noinspection ReturnOfInnerClass
152          */
153         public Builder compileFlags(int val) {
154             compileFlags = val;
155             return this;
156         }
157 
158         /**
159          * Specifies the format to use when matching lines and returns Builder object.
160          * @param val the format to use when matching lines.
161          * @return Builder object.
162          * @noinspection ReturnOfInnerClass
163          */
164         public Builder format(String val) {
165             format = val;
166             return this;
167         }
168 
169         /**
170          * Specifies message to use when reporting a match and returns Builder object.
171          * @param val message to use when reporting a match.
172          * @return Builder object.
173          * @noinspection ReturnOfInnerClass
174          */
175         public Builder message(String val) {
176             message = val;
177             return this;
178         }
179 
180         /**
181          * Specifies the minimum allowed number of detections and returns Builder object.
182          * @param val the minimum allowed number of detections.
183          * @return Builder object.
184          * @noinspection ReturnOfInnerClass
185          */
186         public Builder minimum(int val) {
187             minimum = val;
188             return this;
189         }
190 
191         /**
192          * Specifies the maximum allowed number of detections and returns Builder object.
193          * @param val the maximum allowed number of detections.
194          * @return Builder object.
195          * @noinspection ReturnOfInnerClass
196          */
197         public Builder maximum(int val) {
198             maximum = val;
199             return this;
200         }
201 
202         /**
203          * Specifies whether to ignore case when matching and returns Builder object.
204          * @param val whether to ignore case when matching.
205          * @return Builder object.
206          * @noinspection ReturnOfInnerClass, BooleanParameter
207          */
208         public Builder ignoreCase(boolean val) {
209             ignoreCase = val;
210             return this;
211         }
212 
213         /**
214          * Specifies the suppressor to use and returns Builder object.
215          * @param val the suppressor to use.
216          * @return current instance
217          * @noinspection ReturnOfInnerClass
218          */
219         public Builder suppressor(MatchSuppressor val) {
220             suppressor = val;
221             return this;
222         }
223 
224         /**
225          * Returns new DetectorOptions instance.
226          * @return DetectorOptions instance.
227          */
228         public DetectorOptions build() {
229             message = Optional.ofNullable(message).orElse("");
230             suppressor = Optional.ofNullable(suppressor).orElse(NeverSuppress.INSTANCE);
231             return DetectorOptions.this;
232         }
233 
234     }
235 
236 }