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