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.utils;
21
22 import java.io.Closeable;
23 import java.io.File;
24 import java.io.IOException;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.net.MalformedURLException;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.net.URL;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.util.AbstractMap;
34 import java.util.Map;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37 import java.util.regex.PatternSyntaxException;
38
39 import org.apache.commons.beanutils.ConversionException;
40
41 import antlr.Token;
42 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
43 import com.puppycrawl.tools.checkstyle.api.DetailAST;
44 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
45
46
47
48
49
50 public final class CommonUtil {
51
52
53 public static final int DEFAULT_TAB_WIDTH = 8;
54
55
56 public static final String[] EMPTY_STRING_ARRAY = new String[0];
57
58 public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = new Integer[0];
59
60 public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
61
62 public static final int[] EMPTY_INT_ARRAY = new int[0];
63
64 public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
65
66 public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
67
68
69 private static final String UNABLE_TO_FIND_EXCEPTION_PREFIX = "Unable to find: ";
70
71
72 private static final String JAVADOC_START = "/**";
73
74 private static final String BLOCK_MULTIPLE_COMMENT_BEGIN = "/*";
75
76 private static final String BLOCK_MULTIPLE_COMMENT_END = "*/";
77
78
79 private CommonUtil() {
80 }
81
82
83
84
85
86
87
88
89
90
91 public static Pattern createPattern(String pattern) {
92 return createPattern(pattern, 0);
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106 public static Pattern createPattern(String pattern, int flags) {
107 try {
108 return Pattern.compile(pattern, flags);
109 }
110 catch (final PatternSyntaxException ex) {
111 throw new IllegalArgumentException(
112 "Failed to initialise regular expression " + pattern, ex);
113 }
114 }
115
116
117
118
119
120
121 public static DetailAST createBlockCommentNode(String content) {
122 final DetailAST blockCommentBegin = new DetailAST();
123 blockCommentBegin.setType(TokenTypes.BLOCK_COMMENT_BEGIN);
124 blockCommentBegin.setText(BLOCK_MULTIPLE_COMMENT_BEGIN);
125 blockCommentBegin.setLineNo(0);
126 blockCommentBegin.setColumnNo(-JAVADOC_START.length());
127
128 final DetailAST commentContent = new DetailAST();
129 commentContent.setType(TokenTypes.COMMENT_CONTENT);
130 commentContent.setText("*" + content);
131 commentContent.setLineNo(0);
132
133
134 commentContent.setColumnNo(-1);
135
136 final DetailAST blockCommentEnd = new DetailAST();
137 blockCommentEnd.setType(TokenTypes.BLOCK_COMMENT_END);
138 blockCommentEnd.setText(BLOCK_MULTIPLE_COMMENT_END);
139
140 blockCommentBegin.setFirstChild(commentContent);
141 commentContent.setNextSibling(blockCommentEnd);
142 return blockCommentBegin;
143 }
144
145
146
147
148
149
150
151 public static DetailAST createBlockCommentNode(Token token) {
152 final DetailAST blockComment = new DetailAST();
153 blockComment.initialize(TokenTypes.BLOCK_COMMENT_BEGIN, BLOCK_MULTIPLE_COMMENT_BEGIN);
154
155
156 blockComment.setColumnNo(token.getColumn() - 1);
157 blockComment.setLineNo(token.getLine());
158
159 final DetailAST blockCommentContent = new DetailAST();
160 blockCommentContent.setType(TokenTypes.COMMENT_CONTENT);
161
162
163
164 blockCommentContent.setColumnNo(token.getColumn() - 1 + 2);
165 blockCommentContent.setLineNo(token.getLine());
166 blockCommentContent.setText(token.getText());
167
168 final DetailAST blockCommentClose = new DetailAST();
169 blockCommentClose.initialize(TokenTypes.BLOCK_COMMENT_END, BLOCK_MULTIPLE_COMMENT_END);
170
171 final Map.Entry<Integer, Integer> linesColumns = countLinesColumns(
172 token.getText(), token.getLine(), token.getColumn());
173 blockCommentClose.setLineNo(linesColumns.getKey());
174 blockCommentClose.setColumnNo(linesColumns.getValue());
175
176 blockComment.addChild(blockCommentContent);
177 blockComment.addChild(blockCommentClose);
178 return blockComment;
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192 private static Map.Entry<Integer, Integer> countLinesColumns(
193 String text, int initialLinesCnt, int initialColumnsCnt) {
194 int lines = initialLinesCnt;
195 int columns = initialColumnsCnt;
196 boolean foundCr = false;
197 for (char c : text.toCharArray()) {
198 if (c == '\n') {
199 foundCr = false;
200 lines++;
201 columns = 0;
202 }
203 else {
204 if (foundCr) {
205 foundCr = false;
206 lines++;
207 columns = 0;
208 }
209 if (c == '\r') {
210 foundCr = true;
211 }
212 columns++;
213 }
214 }
215 if (foundCr) {
216 lines++;
217 columns = 0;
218 }
219 return new AbstractMap.SimpleEntry<>(lines, columns);
220 }
221
222
223
224
225
226
227
228
229
230
231 public static boolean matchesFileExtension(File file, String... fileExtensions) {
232 boolean result = false;
233 if (fileExtensions == null || fileExtensions.length == 0) {
234 result = true;
235 }
236 else {
237
238 final String[] withDotExtensions = new String[fileExtensions.length];
239 for (int i = 0; i < fileExtensions.length; i++) {
240 final String extension = fileExtensions[i];
241 if (startsWithChar(extension, '.')) {
242 withDotExtensions[i] = extension;
243 }
244 else {
245 withDotExtensions[i] = "." + extension;
246 }
247 }
248
249 final String fileName = file.getName();
250 for (final String fileExtension : withDotExtensions) {
251 if (fileName.endsWith(fileExtension)) {
252 result = true;
253 break;
254 }
255 }
256 }
257
258 return result;
259 }
260
261
262
263
264
265
266
267
268
269
270 public static boolean hasWhitespaceBefore(int index, String line) {
271 boolean result = true;
272 for (int i = 0; i < index; i++) {
273 if (!Character.isWhitespace(line.charAt(i))) {
274 result = false;
275 break;
276 }
277 }
278 return result;
279 }
280
281
282
283
284
285
286
287
288
289
290 public static int lengthMinusTrailingWhitespace(String line) {
291 int len = line.length();
292 for (int i = len - 1; i >= 0; i--) {
293 if (!Character.isWhitespace(line.charAt(i))) {
294 break;
295 }
296 len--;
297 }
298 return len;
299 }
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 public static int lengthExpandedTabs(String inputString,
315 int toIdx,
316 int tabWidth) {
317 int len = 0;
318 for (int idx = 0; idx < toIdx; idx++) {
319 if (inputString.charAt(idx) == '\t') {
320 len = (len / tabWidth + 1) * tabWidth;
321 }
322 else {
323 len++;
324 }
325 }
326 return len;
327 }
328
329
330
331
332
333
334
335
336 public static boolean isPatternValid(String pattern) {
337 boolean isValid = true;
338 try {
339 Pattern.compile(pattern);
340 }
341 catch (final PatternSyntaxException ignored) {
342 isValid = false;
343 }
344 return isValid;
345 }
346
347
348
349
350
351
352
353 public static String baseClassName(String type) {
354 final String className;
355 final int index = type.lastIndexOf('.');
356 if (index == -1) {
357 className = type;
358 }
359 else {
360 className = type.substring(index + 1);
361 }
362 return className;
363 }
364
365
366
367
368
369
370
371
372
373
374
375 public static String relativizeAndNormalizePath(final String baseDirectory, final String path) {
376 final String resultPath;
377 if (baseDirectory == null) {
378 resultPath = path;
379 }
380 else {
381 final Path pathAbsolute = Paths.get(path).normalize();
382 final Path pathBase = Paths.get(baseDirectory).normalize();
383 resultPath = pathBase.relativize(pathAbsolute).toString();
384 }
385 return resultPath;
386 }
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404 public static boolean startsWithChar(String value, char prefix) {
405 return !value.isEmpty() && value.charAt(0) == prefix;
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 public static boolean endsWithChar(String value, char suffix) {
425 return !value.isEmpty() && value.charAt(value.length() - 1) == suffix;
426 }
427
428
429
430
431
432
433
434
435
436
437
438 public static <T> Constructor<T> getConstructor(Class<T> targetClass,
439 Class<?>... parameterTypes) {
440 try {
441 return targetClass.getConstructor(parameterTypes);
442 }
443 catch (NoSuchMethodException ex) {
444 throw new IllegalStateException(ex);
445 }
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459 public static <T> T invokeConstructor(Constructor<T> constructor, Object... parameters) {
460 try {
461 return constructor.newInstance(parameters);
462 }
463 catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
464 throw new IllegalStateException(ex);
465 }
466 }
467
468
469
470
471
472
473
474 public static void close(Closeable closeable) {
475 if (closeable != null) {
476 try {
477 closeable.close();
478 }
479 catch (IOException ex) {
480 throw new IllegalStateException("Cannot close the stream", ex);
481 }
482 }
483 }
484
485
486
487
488
489
490
491 public static URI getUriByFilename(String filename) throws CheckstyleException {
492
493 URI uri;
494 try {
495 final URL url = new URL(filename);
496 uri = url.toURI();
497 }
498 catch (final URISyntaxException | MalformedURLException ignored) {
499 uri = null;
500 }
501
502 if (uri == null) {
503 final File file = new File(filename);
504 if (file.exists()) {
505 uri = file.toURI();
506 }
507 else {
508
509 try {
510 final URL configUrl = CommonUtil.class
511 .getResource(filename);
512 if (configUrl == null) {
513 throw new CheckstyleException(UNABLE_TO_FIND_EXCEPTION_PREFIX + filename);
514 }
515 uri = configUrl.toURI();
516 }
517 catch (final URISyntaxException ex) {
518 throw new CheckstyleException(UNABLE_TO_FIND_EXCEPTION_PREFIX + filename, ex);
519 }
520 }
521 }
522
523 return uri;
524 }
525
526
527
528
529
530
531
532
533
534 public static String fillTemplateWithStringsByRegexp(
535 String template, String lineToPlaceInTemplate, Pattern regexp) {
536 final Matcher matcher = regexp.matcher(lineToPlaceInTemplate);
537 String result = template;
538 if (matcher.find()) {
539 for (int i = 0; i <= matcher.groupCount(); i++) {
540
541 result = result.replaceAll("\\$" + i, matcher.group(i));
542 }
543 }
544 return result;
545 }
546
547
548
549
550
551
552
553
554 public static String getFileNameWithoutExtension(String fullFilename) {
555 final String fileName = new File(fullFilename).getName();
556 final int dotIndex = fileName.lastIndexOf('.');
557 final String fileNameWithoutExtension;
558 if (dotIndex == -1) {
559 fileNameWithoutExtension = fileName;
560 }
561 else {
562 fileNameWithoutExtension = fileName.substring(0, dotIndex);
563 }
564 return fileNameWithoutExtension;
565 }
566
567
568
569
570
571
572
573
574
575
576 public static String getFileExtension(String fileNameWithExtension) {
577 final String fileName = Paths.get(fileNameWithExtension).toString();
578 final int dotIndex = fileName.lastIndexOf('.');
579 final String extension;
580 if (dotIndex == -1) {
581 extension = "";
582 }
583 else {
584 extension = fileName.substring(dotIndex + 1);
585 }
586 return extension;
587 }
588
589
590
591
592
593
594 public static boolean isIdentifier(String str) {
595 boolean isIdentifier = !str.isEmpty();
596
597 for (int i = 0; isIdentifier && i < str.length(); i++) {
598 if (i == 0) {
599 isIdentifier = Character.isJavaIdentifierStart(str.charAt(0));
600 }
601 else {
602 isIdentifier = Character.isJavaIdentifierPart(str.charAt(i));
603 }
604 }
605
606 return isIdentifier;
607 }
608
609
610
611
612
613
614 public static boolean isName(String str) {
615 boolean isName = !str.isEmpty();
616
617 final String[] identifiers = str.split("\\.", -1);
618 for (int i = 0; isName && i < identifiers.length; i++) {
619 isName = isIdentifier(identifiers[i]);
620 }
621
622 return isName;
623 }
624
625
626
627
628
629
630
631 public static boolean isBlank(String value) {
632 boolean result = true;
633 if (value != null && !value.isEmpty()) {
634 for (int i = 0; i < value.length(); i++) {
635 if (!Character.isWhitespace(value.charAt(i))) {
636 result = false;
637 break;
638 }
639 }
640 }
641 return result;
642 }
643
644
645
646
647
648
649 public static boolean isInt(String str) {
650 boolean isInt;
651 if (str == null) {
652 isInt = false;
653 }
654 else {
655 try {
656 Integer.parseInt(str);
657 isInt = true;
658 }
659 catch (NumberFormatException ignored) {
660 isInt = false;
661 }
662 }
663 return isInt;
664 }
665
666 }