1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks.regexp;
21
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
26 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
27 import com.puppycrawl.tools.checkstyle.api.DetailAST;
28 import com.puppycrawl.tools.checkstyle.api.FileContents;
29 import com.puppycrawl.tools.checkstyle.api.FileText;
30 import com.puppycrawl.tools.checkstyle.api.LineColumn;
31 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 @FileStatefulCheck
58 public class RegexpCheck extends AbstractCheck {
59
60
61
62
63
64 public static final String MSG_ILLEGAL_REGEXP = "illegal.regexp";
65
66
67
68
69
70 public static final String MSG_REQUIRED_REGEXP = "required.regexp";
71
72
73
74
75
76 public static final String MSG_DUPLICATE_REGEXP = "duplicate.regexp";
77
78
79 private static final int DEFAULT_DUPLICATE_LIMIT = -1;
80
81
82 private static final int DEFAULT_ERROR_LIMIT = 100;
83
84
85 private static final String ERROR_LIMIT_EXCEEDED_MESSAGE =
86 "The error limit has been exceeded, "
87 + "the check is aborting, there may be more unreported errors.";
88
89
90 private String message;
91
92
93 private boolean ignoreComments;
94
95
96 private boolean illegalPattern;
97
98
99 private int errorLimit = DEFAULT_ERROR_LIMIT;
100
101
102 private int duplicateLimit;
103
104
105 private boolean checkForDuplicates;
106
107
108 private int matchCount;
109
110
111 private int errorCount;
112
113
114 private Pattern format = Pattern.compile("$^", Pattern.MULTILINE);
115
116
117 private Matcher matcher;
118
119
120
121
122
123 public void setMessage(String message) {
124 if (message == null) {
125 this.message = "";
126 }
127 else {
128 this.message = message;
129 }
130 }
131
132
133
134
135
136 public void setIgnoreComments(boolean ignoreComments) {
137 this.ignoreComments = ignoreComments;
138 }
139
140
141
142
143
144 public void setIllegalPattern(boolean illegalPattern) {
145 this.illegalPattern = illegalPattern;
146 }
147
148
149
150
151
152 public void setErrorLimit(int errorLimit) {
153 this.errorLimit = errorLimit;
154 }
155
156
157
158
159
160
161 public void setDuplicateLimit(int duplicateLimit) {
162 this.duplicateLimit = duplicateLimit;
163 checkForDuplicates = duplicateLimit > DEFAULT_DUPLICATE_LIMIT;
164 }
165
166
167
168
169
170
171 public final void setFormat(Pattern pattern) {
172 format = CommonUtils.createPattern(pattern.pattern(), Pattern.MULTILINE);
173 }
174
175 @Override
176 public int[] getDefaultTokens() {
177 return getRequiredTokens();
178 }
179
180 @Override
181 public int[] getAcceptableTokens() {
182 return getRequiredTokens();
183 }
184
185 @Override
186 public int[] getRequiredTokens() {
187 return CommonUtils.EMPTY_INT_ARRAY;
188 }
189
190 @Override
191 public void beginTree(DetailAST rootAST) {
192 matcher = format.matcher(getFileContents().getText().getFullText());
193 matchCount = 0;
194 errorCount = 0;
195 findMatch();
196 }
197
198
199 private void findMatch() {
200 final boolean foundMatch = matcher.find();
201 if (foundMatch) {
202 final FileText text = getFileContents().getText();
203 final LineColumn start = text.lineColumn(matcher.start());
204 final int startLine = start.getLine();
205
206 final boolean ignore = isIgnore(startLine, text, start);
207
208 if (!ignore) {
209 matchCount++;
210 if (illegalPattern || checkForDuplicates
211 && matchCount - 1 > duplicateLimit) {
212 errorCount++;
213 logMessage(startLine);
214 }
215 }
216 if (canContinueValidation(ignore)) {
217 findMatch();
218 }
219 }
220 else if (!illegalPattern && matchCount == 0) {
221 logMessage(0);
222 }
223 }
224
225
226
227
228
229
230 private boolean canContinueValidation(boolean ignore) {
231 return errorCount <= errorLimit - 1
232 && (ignore || illegalPattern || checkForDuplicates);
233 }
234
235
236
237
238
239
240
241
242 private boolean isIgnore(int startLine, FileText text, LineColumn start) {
243 final LineColumn end;
244 if (matcher.end() == 0) {
245 end = text.lineColumn(0);
246 }
247 else {
248 end = text.lineColumn(matcher.end() - 1);
249 }
250 boolean ignore = false;
251 if (ignoreComments) {
252 final FileContents theFileContents = getFileContents();
253 final int startColumn = start.getColumn();
254 final int endLine = end.getLine();
255 final int endColumn = end.getColumn();
256 ignore = theFileContents.hasIntersectionWithComment(startLine,
257 startColumn, endLine, endColumn);
258 }
259 return ignore;
260 }
261
262
263
264
265
266 private void logMessage(int lineNumber) {
267 String msg;
268
269 if (message == null || message.isEmpty()) {
270 msg = format.pattern();
271 }
272 else {
273 msg = message;
274 }
275
276 if (errorCount >= errorLimit) {
277 msg = ERROR_LIMIT_EXCEEDED_MESSAGE + msg;
278 }
279
280 if (illegalPattern) {
281 log(lineNumber, MSG_ILLEGAL_REGEXP, msg);
282 }
283 else {
284 if (lineNumber > 0) {
285 log(lineNumber, MSG_DUPLICATE_REGEXP, msg);
286 }
287 else {
288 log(lineNumber, MSG_REQUIRED_REGEXP, msg);
289 }
290 }
291 }
292
293 }