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