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