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.internal.utils;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.lang.reflect.Field;
25 import java.nio.charset.Charset;
26 import java.text.MessageFormat;
27 import java.util.Arrays;
28 import java.util.HashSet;
29 import java.util.Locale;
30 import java.util.OptionalInt;
31 import java.util.Properties;
32 import java.util.Set;
33 import java.util.stream.Collectors;
34
35 import javax.xml.parsers.DocumentBuilder;
36 import javax.xml.parsers.DocumentBuilderFactory;
37
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42
43 import com.google.common.reflect.ClassPath;
44 import com.puppycrawl.tools.checkstyle.api.FileText;
45 import com.puppycrawl.tools.checkstyle.checks.coding.AbstractSuperCheck;
46 import com.puppycrawl.tools.checkstyle.checks.naming.AbstractAccessControlNameCheck;
47 import com.puppycrawl.tools.checkstyle.checks.naming.AbstractNameCheck;
48 import com.puppycrawl.tools.checkstyle.checks.regexp.RegexpMultilineCheck;
49 import com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck;
50 import com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck;
51 import com.puppycrawl.tools.checkstyle.checks.whitespace.AbstractParenPadCheck;
52 import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
53 import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtil;
54 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
55
56 public final class CheckUtil {
57
58 public static final String CRLF = "\r\n";
59
60 private CheckUtil() {
61 }
62
63 public static Set<String> getConfigCheckStyleModules() {
64 return getCheckStyleModulesReferencedInConfig("config/checkstyle-checks.xml");
65 }
66
67 public static Set<String> getConfigSunStyleModules() {
68 return getCheckStyleModulesReferencedInConfig("src/main/resources/sun_checks.xml");
69 }
70
71 public static Set<String> getConfigGoogleStyleModules() {
72 return getCheckStyleModulesReferencedInConfig("src/main/resources/google_checks.xml");
73 }
74
75 public static Set<String> getConfigOpenJdkStyleModules() {
76 return getCheckStyleModulesReferencedInConfig("src/main/resources/openjdk_checks.xml");
77 }
78
79
80
81
82
83
84
85
86 public static Set<String> getSimpleNames(Set<Class<?>> checks) {
87 return checks.stream().map(check -> {
88 String name = check.getSimpleName();
89
90 if (name.endsWith("Check")) {
91 name = name.substring(0, name.length() - 5);
92 }
93
94 return name;
95 }).collect(Collectors.toCollection(HashSet::new));
96 }
97
98
99
100
101
102
103
104
105 private static Set<String> getCheckStyleModulesReferencedInConfig(String configFilePath) {
106 try {
107 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
108
109
110
111 factory.setNamespaceAware(false);
112 factory.setValidating(false);
113 factory.setFeature("http://xml.org/sax/features/namespaces", false);
114 factory.setFeature("http://xml.org/sax/features/validation", false);
115 factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
116 false);
117 factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
118 false);
119
120 final DocumentBuilder builder = factory.newDocumentBuilder();
121 final Document document = builder.parse(new File(configFilePath));
122
123
124
125
126
127 document.getDocumentElement().normalize();
128
129 final NodeList nodeList = document.getElementsByTagName("module");
130
131 final Set<String> checksReferencedInCheckstyleChecksXml = new HashSet<>();
132 for (int i = 0; i < nodeList.getLength(); i++) {
133 final Node currentNode = nodeList.item(i);
134 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
135 final Element module = (Element) currentNode;
136 final String checkName = module.getAttribute("name");
137 checksReferencedInCheckstyleChecksXml.add(checkName);
138 }
139 }
140 return checksReferencedInCheckstyleChecksXml;
141 }
142 catch (Exception exception) {
143 throw new IllegalStateException(exception);
144 }
145 }
146
147
148
149
150
151
152
153 public static Set<Class<?>> getCheckstyleChecks() throws IOException {
154 final ClassLoader loader = Thread.currentThread()
155 .getContextClassLoader();
156 final String packageName = "com.puppycrawl.tools.checkstyle";
157 return getCheckstyleModulesRecursive(packageName, loader).stream()
158 .filter(ModuleReflectionUtil::isCheckstyleTreeWalkerCheck)
159 .collect(Collectors.toUnmodifiableSet());
160 }
161
162
163
164
165
166
167
168 public static Set<Class<?>> getCheckstyleModules() throws IOException {
169 final ClassLoader loader = Thread.currentThread()
170 .getContextClassLoader();
171 final String packageName = "com.puppycrawl.tools.checkstyle";
172 return getCheckstyleModulesRecursive(packageName, loader);
173 }
174
175
176
177
178
179
180
181
182
183
184 private static Set<Class<?>> getCheckstyleModulesRecursive(
185 String packageName, ClassLoader loader) throws IOException {
186 final ClassPath classPath = ClassPath.from(loader);
187 return classPath.getTopLevelClassesRecursive(packageName).stream()
188 .map(ClassPath.ClassInfo::load)
189 .filter(ModuleReflectionUtil::isCheckstyleModule)
190 .filter(CheckUtil::isFromAllowedPackages)
191 .collect(Collectors.toUnmodifiableSet());
192 }
193
194
195
196
197
198
199
200 private static boolean isFromAllowedPackages(Class<?> cls) {
201 final String canonicalName = cls.getCanonicalName();
202 return !canonicalName.startsWith("com.puppycrawl.tools.checkstyle.packageobjectfactory")
203 && !canonicalName.startsWith("com.puppycrawl.tools.checkstyle.internal.testmodules")
204 && !canonicalName.startsWith("com.puppycrawl.tools.checkstyle.site");
205 }
206
207
208
209
210
211
212
213
214
215
216
217 public static Set<Field> getCheckMessages(Class<?> module, boolean deepScan)
218 throws ClassNotFoundException {
219 final Set<Field> checkstyleMessages = new HashSet<>();
220
221
222 final Field[] fields = module.getDeclaredFields();
223
224 for (Field field : fields) {
225 if (field.getName().startsWith("MSG_")) {
226 checkstyleMessages.add(field);
227 }
228 }
229
230
231 final Class<?> superModule = module.getSuperclass();
232
233 if (superModule != null && (deepScan || shouldScanDeepClassForMessages(superModule))) {
234 checkstyleMessages.addAll(getCheckMessages(superModule, deepScan));
235 }
236
237
238 if (module == RegexpMultilineCheck.class) {
239 checkstyleMessages.addAll(getCheckMessages(Class
240 .forName("com.puppycrawl.tools.checkstyle.checks.regexp.MultilineDetector"),
241 deepScan));
242 }
243 else if (module == RegexpSinglelineCheck.class
244 || module == RegexpSinglelineJavaCheck.class) {
245 checkstyleMessages.addAll(getCheckMessages(Class
246 .forName("com.puppycrawl.tools.checkstyle.checks.regexp.SinglelineDetector"),
247 deepScan));
248 }
249
250 return checkstyleMessages;
251 }
252
253
254
255
256
257
258
259 private static boolean shouldScanDeepClassForMessages(Class<?> superModule) {
260 return superModule == AbstractNameCheck.class
261 || superModule == AbstractAccessControlNameCheck.class
262 || superModule == AbstractParenPadCheck.class
263 || superModule == AbstractSuperCheck.class;
264 }
265
266
267
268
269
270
271
272
273
274
275
276 public static String getCheckMessage(Class<?> module, Locale locale, String messageKey,
277 Object... arguments) {
278 String checkMessage;
279 try {
280 final Properties pr = new Properties();
281 if (locale.equals(Locale.ENGLISH)) {
282 pr.load(module.getResourceAsStream("messages.properties"));
283 }
284 else {
285 pr.load(module
286 .getResourceAsStream("messages_" + locale.getLanguage() + ".properties"));
287 }
288 final MessageFormat formatter = new MessageFormat(pr.getProperty(messageKey), locale);
289 checkMessage = formatter.format(arguments);
290 }
291 catch (IOException ignored) {
292 checkMessage = null;
293 }
294 return checkMessage;
295 }
296
297 public static String getTokenText(int[] tokens, int... subtractions) {
298 final String tokenText;
299 if (subtractions.length == 0 && Arrays.equals(tokens, TokenUtil.getAllTokenIds())) {
300 tokenText = "TokenTypes.";
301 }
302 else {
303 final StringBuilder result = new StringBuilder(50);
304 boolean first = true;
305
306 for (int token : tokens) {
307 boolean found = false;
308
309 for (int subtraction : subtractions) {
310 if (subtraction == token) {
311 found = true;
312 break;
313 }
314 }
315
316 if (found) {
317 continue;
318 }
319
320 if (first) {
321 first = false;
322 }
323 else {
324 result.append(", ");
325 }
326
327 result.append(TokenUtil.getTokenName(token));
328 }
329
330 if (!result.isEmpty()) {
331 result.append('.');
332 }
333
334 tokenText = result.toString();
335 }
336 return tokenText;
337 }
338
339 public static Set<String> getTokenNameSet(int... tokens) {
340 final Set<String> result = new HashSet<>();
341
342 for (int token : tokens) {
343 result.add(TokenUtil.getTokenName(token));
344 }
345
346 return result;
347 }
348
349 public static String getJavadocTokenText(int[] tokens, int... subtractions) {
350 final StringBuilder result = new StringBuilder(50);
351 boolean first = true;
352
353 for (int token : tokens) {
354 boolean found = false;
355
356 for (int subtraction : subtractions) {
357 if (subtraction == token) {
358 found = true;
359 break;
360 }
361 }
362
363 if (found) {
364 continue;
365 }
366
367 if (first) {
368 first = false;
369 }
370 else {
371 result.append(", ");
372 }
373
374 result.append(JavadocUtil.getTokenName(token));
375 }
376
377 if (!result.isEmpty()) {
378 result.append('.');
379 }
380
381 return result.toString();
382 }
383
384 public static String getLineSeparatorForFile(String filepath, Charset charset)
385 throws IOException {
386 final OptionalInt endOfLineChar = new FileText(new File(filepath), charset.name())
387 .getFullText()
388 .chars()
389 .filter(character -> character == '\r' || character == '\n')
390 .findFirst();
391
392 final String result;
393 if (endOfLineChar.isPresent() && endOfLineChar.getAsInt() == '\r') {
394 result = CRLF;
395 }
396 else {
397 result = "\n";
398 }
399 return result;
400 }
401 }