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.bdd;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.StringReader;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.Method;
27 import java.math.BigDecimal;
28 import java.nio.file.Files;
29 import java.nio.file.Path;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.BitSet;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.Properties;
41 import java.util.Set;
42 import java.util.regex.Matcher;
43 import java.util.regex.Pattern;
44 import java.util.stream.Collectors;
45
46 import org.xml.sax.InputSource;
47
48 import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
49 import com.puppycrawl.tools.checkstyle.PropertiesExpander;
50 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
51 import com.puppycrawl.tools.checkstyle.api.Configuration;
52 import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
53 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
54
55 public final class InlineConfigParser {
56
57
58 private static final Pattern SLASH_PATTERN = Pattern.compile("[\\\\/]");
59
60
61
62
63
64 private static final Pattern VIOLATION_MESSAGE_PATTERN = Pattern
65 .compile(".*//\\s*(?:['\"](.*)['\"])?$");
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 private static final Pattern VIOLATION_PATTERN = Pattern
87 .compile(".*//\\s*violation,?\\s*(?:['\"](.*)['\"])?$");
88
89
90 private static final Pattern VIOLATION_ABOVE_PATTERN = Pattern
91 .compile(".*//\\s*violation above,?\\s*(?:['\"](.*)['\"])?$");
92
93
94 private static final Pattern VIOLATION_BELOW_PATTERN = Pattern
95 .compile(".*//\\s*violation below,?\\s*(?:['\"](.*)['\"])?$");
96
97
98 private static final Pattern VIOLATION_ABOVE_WITH_EXPLANATION_PATTERN = Pattern
99 .compile(".*//\\s*violation above,\\s.+\\s(?:['\"](.*)['\"])?$");
100
101
102 private static final Pattern VIOLATION_BELOW_WITH_EXPLANATION_PATTERN = Pattern
103 .compile(".*//\\s*violation below,\\s.+\\s(?:['\"](.*)['\"])?$");
104
105
106 private static final Pattern VIOLATION_WITH_EXPLANATION_PATTERN = Pattern
107 .compile(".*//\\s*violation,\\s+(?:.*)?$");
108
109
110 private static final Pattern MULTIPLE_VIOLATIONS_PATTERN = Pattern
111 .compile(".*//\\s*(\\d+) violations$");
112
113
114 private static final Pattern MULTIPLE_VIOLATIONS_ABOVE_PATTERN = Pattern
115 .compile(".*//\\s*(\\d+) violations above$");
116
117
118 private static final Pattern MULTIPLE_VIOLATIONS_BELOW_PATTERN = Pattern
119 .compile(".*//\\s*(\\d+) violations below$");
120
121
122 private static final Pattern FILTERED_VIOLATION_PATTERN = Pattern
123 .compile(".*//\\s*filtered violation\\s*(?:['\"](.*)['\"])?$");
124
125
126 private static final Pattern FILTERED_VIOLATION_ABOVE_PATTERN = Pattern
127 .compile(".*//\\s*filtered violation above\\s*(?:['\"](.*)['\"])?$");
128
129
130 private static final Pattern FILTERED_VIOLATION_BELOW_PATTERN = Pattern
131 .compile(".*//\\s*filtered violation below\\s*(?:['\"](.*)['\"])?$");
132
133
134 private static final Pattern FILTERED_VIOLATION_SOME_LINES_ABOVE_PATTERN = Pattern
135 .compile(".*//\\s*filtered violation (\\d+) lines above\\s*(?:['\"](.*)['\"])?$");
136
137
138 private static final Pattern VIOLATION_SOME_LINES_ABOVE_PATTERN = Pattern
139 .compile(".*//\\s*violation (\\d+) lines above\\s*(?:['\"](.*)['\"])?$");
140
141
142 private static final Pattern VIOLATION_SOME_LINES_BELOW_PATTERN = Pattern
143 .compile(".*//\\s*violation (\\d+) lines below\\s*(?:['\"](.*)['\"])?$");
144
145
146
147
148
149
150
151
152
153
154
155
156
157 private static final Pattern VIOLATIONS_ABOVE_PATTERN_WITH_MESSAGES = Pattern
158 .compile(".*//\\s*(\\d+) violations above:$");
159
160
161
162
163
164
165
166
167
168
169
170
171
172 private static final Pattern VIOLATIONS_SOME_LINES_ABOVE_PATTERN = Pattern
173 .compile(".*//\\s*(\\d+) violations (\\d+) lines above:$");
174
175
176
177
178
179
180
181
182
183
184
185
186
187 private static final Pattern VIOLATIONS_SOME_LINES_BELOW_PATTERN = Pattern
188 .compile(".*//\\s*(\\d+) violations (\\d+) lines below:$");
189
190
191 private static final Pattern VIOLATION_DEFAULT = Pattern
192 .compile("//.*violation.*");
193
194
195 private static final String NULL_STRING = "(null)";
196
197 private static final String LATEST_DTD = String.format(Locale.ROOT,
198 "<!DOCTYPE module PUBLIC \"%s\" \"%s\">%n",
199 ConfigurationLoader.DTD_PUBLIC_CS_ID_1_3,
200 ConfigurationLoader.DTD_PUBLIC_CS_ID_1_3);
201
202
203
204
205
206
207 private static final Set<String> PERMANENT_SUPPRESSED_CHECKS = Set.of(
208
209 "com.puppycrawl.tools.checkstyle.checks.OrderedPropertiesCheck",
210 "com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck",
211 "com.puppycrawl.tools.checkstyle.checks.TranslationCheck"
212 );
213
214
215
216
217
218 private static final Set<String> SUPPRESSED_CHECKS = Set.of(
219 "com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheck",
220 "com.puppycrawl.tools.checkstyle.checks.coding.ExplicitInitializationCheck",
221 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalInstantiationCheck",
222 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalTokenTextCheck",
223 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalTypeCheck",
224 "com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck",
225 "com.puppycrawl.tools.checkstyle.checks.coding.MatchXpathCheck",
226 "com.puppycrawl.tools.checkstyle.checks.coding.ModifiedControlVariableCheck",
227 "com.puppycrawl.tools.checkstyle.checks.coding.MultipleStringLiteralsCheck",
228 "com.puppycrawl.tools.checkstyle.checks.coding.NestedForDepthCheck",
229 "com.puppycrawl.tools.checkstyle.checks.coding.NestedTryDepthCheck",
230 "com.puppycrawl.tools.checkstyle.checks.coding.StringLiteralEqualityCheck",
231 "com.puppycrawl.tools.checkstyle.checks.coding.SuperFinalizeCheck",
232 "com.puppycrawl.tools.checkstyle.checks.coding"
233 + ".UnnecessarySemicolonAfterTypeMemberDeclarationCheck",
234 "com.puppycrawl.tools.checkstyle.checks.coding"
235 + ".UnusedCatchParameterShouldBeUnnamedCheck",
236 "com.puppycrawl.tools.checkstyle.checks.design.DesignForExtensionCheck",
237 "com.puppycrawl.tools.checkstyle.checks.design.HideUtilityClassConstructorCheck",
238 "com.puppycrawl.tools.checkstyle.checks.design.InnerTypeLastCheck",
239 "com.puppycrawl.tools.checkstyle.checks.design.MutableExceptionCheck",
240 "com.puppycrawl.tools.checkstyle.checks.design.OneTopLevelClassCheck",
241
242 "com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck",
243 "com.puppycrawl.tools.checkstyle.checks.javadoc."
244 + "AbstractJavadocCheckTest$TokenIsNotInAcceptablesCheck",
245 "com.puppycrawl.tools.checkstyle.checks.javadoc.AtclauseOrderCheck",
246 "com.puppycrawl.tools.checkstyle.checks.javadoc.InvalidJavadocPositionCheck",
247 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocBlockTagLocationCheck",
248 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMissingLeadingAsteriskCheck",
249 "com.puppycrawl.tools.checkstyle.checks.javadoc"
250 + ".JavadocMissingWhitespaceAfterAsteriskCheck",
251 "com.puppycrawl.tools.checkstyle.checks.javadoc"
252 + ".JavadocTagContinuationIndentationCheck",
253 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck",
254 "com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck",
255 "com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocPackageCheck",
256 "com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocTypeCheck",
257 "com.puppycrawl.tools.checkstyle.checks.javadoc.NonEmptyAtclauseDescriptionCheck",
258 "com.puppycrawl.tools.checkstyle.checks.javadoc"
259 + ".RequireEmptyLineBeforeBlockTagGroupCheck",
260 "com.puppycrawl.tools.checkstyle.checks.javadoc.SingleLineJavadocCheck",
261 "com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheck",
262 "com.puppycrawl.tools.checkstyle.checks.metrics.ClassDataAbstractionCouplingCheck",
263 "com.puppycrawl.tools.checkstyle.checks.metrics.ClassFanOutComplexityCheck",
264 "com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexityCheck",
265 "com.puppycrawl.tools.checkstyle.checks.metrics.NPathComplexityCheck",
266 "com.puppycrawl.tools.checkstyle.checks.modifier.ClassMemberImpliedModifierCheck",
267 "com.puppycrawl.tools.checkstyle.checks.modifier.InterfaceMemberImpliedModifierCheck",
268 "com.puppycrawl.tools.checkstyle.checks.modifier.RedundantModifierCheck",
269 "com.puppycrawl.tools.checkstyle.checks.naming.AbbreviationAsWordInNameCheck",
270
271 "com.puppycrawl.tools.checkstyle.checks.naming.IllegalIdentifierNameCheck",
272 "com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck",
273 "com.puppycrawl.tools.checkstyle.checks.naming.MethodTypeParameterNameCheck",
274 "com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck",
275 "com.puppycrawl.tools.checkstyle.checks.naming.PatternVariableNameCheck",
276 "com.puppycrawl.tools.checkstyle.checks.naming.RecordComponentNameCheck",
277 "com.puppycrawl.tools.checkstyle.checks.naming.RecordTypeParameterNameCheck",
278 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpMultilineCheck",
279 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck",
280 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck",
281 "com.puppycrawl.tools.checkstyle.checks.sizes.AnonInnerLengthCheck",
282 "com.puppycrawl.tools.checkstyle.checks.sizes.ExecutableStatementCountCheck",
283 "com.puppycrawl.tools.checkstyle.checks.sizes.LambdaBodyLengthCheck",
284 "com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck",
285 "com.puppycrawl.tools.checkstyle.checks.sizes.OuterTypeNumberCheck",
286 "com.puppycrawl.tools.checkstyle.checks.sizes.ParameterNumberCheck",
287 "com.puppycrawl.tools.checkstyle.checks.sizes.RecordComponentNumberCheck",
288 "com.puppycrawl.tools.checkstyle.checks.TodoCommentCheck",
289 "com.puppycrawl.tools.checkstyle.checks.TrailingCommentCheck",
290 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoLineWrapCheck",
291 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceAfterCheck",
292 "com.puppycrawl.tools.checkstyle.checks.whitespace."
293 + "NoWhitespaceBeforeCaseDefaultColonCheck",
294 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCheck",
295 "com.puppycrawl.tools.checkstyle.checks.whitespace.ParenPadCheck",
296 "com.puppycrawl.tools.checkstyle.checks.whitespace.SingleSpaceSeparatorCheck",
297 "com.puppycrawl.tools.checkstyle.meta.JavadocMetadataScraper",
298 "com.puppycrawl.tools.checkstyle.api.AbstractCheckTest$ViolationAstCheck",
299 "com.puppycrawl.tools.checkstyle.CheckerTest$VerifyPositionAfterTabFileSet"
300 );
301
302
303 private static final Map<String, String> MODULE_MAPPINGS = new HashMap<>();
304
305
306 static {
307 MODULE_MAPPINGS.put("IllegalCatch",
308 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck");
309 MODULE_MAPPINGS.put("MagicNumber",
310 "com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck");
311 MODULE_MAPPINGS.put("SummaryJavadoc",
312 "com.puppycrawl.tools.checkstyle.checks.javadoc.SummaryJavadocCheck");
313 MODULE_MAPPINGS.put("ClassDataAbstractionCoupling",
314 "com.puppycrawl.tools.checkstyle.checks.metrics.ClassDataAbstractionCouplingCheck");
315 MODULE_MAPPINGS.put("ConstantName",
316 "com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck");
317 MODULE_MAPPINGS.put("MemberName",
318 "com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck");
319 MODULE_MAPPINGS.put("MethodName",
320 "com.puppycrawl.tools.checkstyle.checks.naming.MethodNameCheck");
321 MODULE_MAPPINGS.put("ParameterName",
322 "com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck");
323 MODULE_MAPPINGS.put("RegexpOnFilename",
324 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpOnFilenameCheck");
325 MODULE_MAPPINGS.put("RegexpSingleline",
326 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck");
327 MODULE_MAPPINGS.put("RegexpSinglelineJava",
328 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck");
329 MODULE_MAPPINGS.put("LineLength",
330 "com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck");
331 MODULE_MAPPINGS.put("ParameterNumber",
332 "com.puppycrawl.tools.checkstyle.checks.sizes.ParameterNumberCheck");
333 MODULE_MAPPINGS.put("NoWhitespaceAfter",
334 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceAfterCheck");
335 MODULE_MAPPINGS.put("OrderedProperties",
336 "com.puppycrawl.tools.checkstyle.checks.OrderedPropertiesCheck");
337 MODULE_MAPPINGS.put("SuppressWarningsHolder",
338 "com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder");
339 MODULE_MAPPINGS.put("UniqueProperties",
340 "com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck");
341 MODULE_MAPPINGS.put("SuppressionXpathSingleFilter",
342 "com.puppycrawl.tools.checkstyle.filters.SuppressionXpathSingleFilter");
343 MODULE_MAPPINGS.put("SuppressWarningsFilter",
344 "com.puppycrawl.tools.checkstyle.filters.SuppressWarningsFilter");
345 MODULE_MAPPINGS.put("LeftCurly",
346 "com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck");
347 MODULE_MAPPINGS.put("RequireThis",
348 "com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck");
349 MODULE_MAPPINGS.put("IllegalThrows",
350 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalThrowsCheck");
351 MODULE_MAPPINGS.put("LocalFinalVariableName",
352 "com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheck");
353 MODULE_MAPPINGS.put("PackageName",
354 "com.puppycrawl.tools.checkstyle.checks.naming.PackageNameCheck");
355 MODULE_MAPPINGS.put("RedundantModifier",
356 "com.puppycrawl.tools.checkstyle.checks.modifier.RedundantModifierCheck");
357 MODULE_MAPPINGS.put("AbstractClassName",
358 "com.puppycrawl.tools.checkstyle.checks.naming.AbstractClassNameCheck");
359 MODULE_MAPPINGS.put("JavadocMethod",
360 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck");
361 MODULE_MAPPINGS.put("IllegalIdentifierName",
362 "com.puppycrawl.tools.checkstyle.checks.naming.IllegalIdentifierNameCheck");
363 MODULE_MAPPINGS.put("FileLength",
364 "com.puppycrawl.tools.checkstyle.checks.sizes.FileLengthCheck");
365 MODULE_MAPPINGS.put("EqualsAvoidNull",
366 "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck");
367 MODULE_MAPPINGS.put("JavadocStyle",
368 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocStyleCheck");
369 }
370
371
372 private InlineConfigParser() {
373 }
374
375 public static TestInputConfiguration parse(String inputFilePath) throws Exception {
376 return parse(inputFilePath, false);
377 }
378
379
380
381
382
383
384
385
386 private static TestInputConfiguration parse(String inputFilePath,
387 boolean setFilteredViolations) throws Exception {
388 final TestInputConfiguration.Builder testInputConfigBuilder =
389 new TestInputConfiguration.Builder();
390 final Path filePath = Path.of(inputFilePath);
391 final List<String> lines = readFile(filePath);
392 try {
393 setModules(testInputConfigBuilder, inputFilePath, lines);
394 }
395 catch (Exception ex) {
396 throw new CheckstyleException("Config comment not specified properly in "
397 + inputFilePath, ex);
398 }
399 try {
400 setViolations(testInputConfigBuilder, lines, setFilteredViolations);
401 }
402 catch (CheckstyleException ex) {
403 throw new CheckstyleException(ex.getMessage() + " in " + inputFilePath, ex);
404 }
405 return testInputConfigBuilder.build();
406 }
407
408 public static List<TestInputViolation> getViolationsFromInputFile(String inputFilePath)
409 throws Exception {
410 final TestInputConfiguration.Builder testInputConfigBuilder =
411 new TestInputConfiguration.Builder();
412 final Path filePath = Path.of(inputFilePath);
413 final List<String> lines = readFile(filePath);
414
415 try {
416 for (int lineNo = 0; lineNo < lines.size(); lineNo++) {
417 setViolations(testInputConfigBuilder, lines, false, lineNo, true);
418 }
419 }
420 catch (CheckstyleException ex) {
421 throw new CheckstyleException(ex.getMessage() + " in " + inputFilePath, ex);
422 }
423
424 return testInputConfigBuilder.build().getViolations();
425 }
426
427 public static TestInputConfiguration parseWithFilteredViolations(String inputFilePath)
428 throws Exception {
429 return parse(inputFilePath, true);
430 }
431
432
433
434
435
436
437
438 public static TestInputConfiguration parseWithXmlHeader(String inputFilePath)
439 throws Exception {
440
441 final Path filePath = Path.of(inputFilePath);
442 final List<String> lines = readFile(filePath);
443 if (!checkIsXmlConfig(lines)) {
444 throw new CheckstyleException("Config cannot be parsed as xml.");
445 }
446
447 final List<String> inlineConfig = getInlineConfig(lines);
448 final String stringXmlConfig = LATEST_DTD + String.join("", inlineConfig);
449 final InputSource inputSource = new InputSource(new StringReader(stringXmlConfig));
450 final Configuration xmlConfig = ConfigurationLoader.loadConfiguration(
451 inputSource, new PropertiesExpander(System.getProperties()),
452 ConfigurationLoader.IgnoredModulesOptions.EXECUTE
453 );
454 final String configName = xmlConfig.getName();
455 if (!"Checker".equals(configName)) {
456 throw new CheckstyleException(
457 "First module should be Checker, but was " + configName);
458 }
459
460 final TestInputConfiguration.Builder testInputConfigBuilder =
461 new TestInputConfiguration.Builder();
462 testInputConfigBuilder.setXmlConfiguration(xmlConfig);
463 try {
464 setViolations(testInputConfigBuilder, lines, false);
465 }
466 catch (CheckstyleException ex) {
467 throw new CheckstyleException(ex.getMessage() + " in " + inputFilePath, ex);
468 }
469 return testInputConfigBuilder.buildWithXmlConfiguration();
470 }
471
472
473
474
475
476
477
478 private static boolean checkIsXmlConfig(List<String> lines) {
479 return "/*xml".equals(lines.get(0));
480 }
481
482 private static void setModules(TestInputConfiguration.Builder testInputConfigBuilder,
483 String inputFilePath, List<String> lines)
484 throws Exception {
485 if (!lines.get(0).startsWith("/*")) {
486 throw new CheckstyleException("Config not specified on top."
487 + "Please see other inputs for examples of what is required.");
488 }
489
490 final List<String> inlineConfig = getInlineConfig(lines);
491
492 if (checkIsXmlConfig(lines)) {
493 final String stringXmlConfig = LATEST_DTD + String.join("", inlineConfig);
494 final InputSource inputSource = new InputSource(new StringReader(stringXmlConfig));
495 final Configuration xmlConfig = ConfigurationLoader.loadConfiguration(
496 inputSource, new PropertiesExpander(System.getProperties()),
497 ConfigurationLoader.IgnoredModulesOptions.EXECUTE
498 );
499 final String configName = xmlConfig.getName();
500 if (!"Checker".equals(configName)) {
501 throw new CheckstyleException(
502 "First module should be Checker, but was " + configName);
503 }
504 handleXmlConfig(testInputConfigBuilder, inputFilePath, xmlConfig.getChildren());
505 }
506 else {
507 handleKeyValueConfig(testInputConfigBuilder, inputFilePath, inlineConfig);
508 }
509 }
510
511 private static List<String> getInlineConfig(List<String> lines) {
512 return lines.stream()
513 .skip(1)
514 .takeWhile(line -> !line.startsWith("*/"))
515 .collect(Collectors.toUnmodifiableList());
516 }
517
518 private static void handleXmlConfig(TestInputConfiguration.Builder testInputConfigBuilder,
519 String inputFilePath,
520 Configuration... modules)
521 throws CheckstyleException {
522
523 for (Configuration module: modules) {
524 final String moduleName = module.getName();
525 if ("TreeWalker".equals(moduleName)) {
526 handleXmlConfig(testInputConfigBuilder, inputFilePath, module.getChildren());
527 }
528 else {
529 final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
530 new ModuleInputConfiguration.Builder();
531 setModuleName(moduleInputConfigBuilder, inputFilePath, moduleName);
532 setProperties(inputFilePath, module, moduleInputConfigBuilder);
533 testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
534 }
535 }
536 }
537
538 private static void handleKeyValueConfig(TestInputConfiguration.Builder testInputConfigBuilder,
539 String inputFilePath, List<String> lines)
540 throws CheckstyleException, IOException, ReflectiveOperationException {
541 int lineNo = 0;
542 while (lineNo < lines.size()) {
543 final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
544 new ModuleInputConfiguration.Builder();
545 final String moduleName = lines.get(lineNo);
546 setModuleName(moduleInputConfigBuilder, inputFilePath, moduleName);
547 setProperties(moduleInputConfigBuilder, inputFilePath, lines, lineNo + 1, moduleName);
548 testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
549 do {
550 lineNo++;
551 } while (lineNo < lines.size()
552 && lines.get(lineNo).isEmpty()
553 || !lines.get(lineNo - 1).isEmpty());
554 }
555 }
556
557 private static String getFullyQualifiedClassName(String filePath, String moduleName)
558 throws CheckstyleException {
559 String fullyQualifiedClassName;
560 if (MODULE_MAPPINGS.containsKey(moduleName)) {
561 fullyQualifiedClassName = MODULE_MAPPINGS.get(moduleName);
562 }
563 else if (moduleName.startsWith("com.")) {
564 fullyQualifiedClassName = moduleName;
565 }
566 else {
567 final String path = SLASH_PATTERN.matcher(filePath).replaceAll(".");
568 final int endIndex = path.lastIndexOf(moduleName.toLowerCase(Locale.ROOT));
569 if (endIndex == -1) {
570 throw new CheckstyleException("Unable to resolve module name: " + moduleName
571 + ". Please check for spelling errors or specify fully qualified class name.");
572 }
573 final int beginIndex = path.indexOf("com.puppycrawl");
574 fullyQualifiedClassName = path.substring(beginIndex, endIndex) + moduleName;
575 if (!fullyQualifiedClassName.endsWith("Filter")) {
576 fullyQualifiedClassName += "Check";
577 }
578 }
579 return fullyQualifiedClassName;
580 }
581
582 private static String getFilePath(String fileName, String inputFilePath) {
583 final int lastSlashIndex = Math.max(inputFilePath.lastIndexOf('\\'),
584 inputFilePath.lastIndexOf('/'));
585 final String root = inputFilePath.substring(0, lastSlashIndex + 1);
586 return root + fileName;
587 }
588
589 private static String getResourcePath(String fileName, String inputFilePath) {
590 final String filePath = getUriPath(fileName, inputFilePath);
591 final int lastSlashIndex = filePath.lastIndexOf('/');
592 final String root = filePath.substring(filePath.indexOf("puppycrawl") - 5,
593 lastSlashIndex + 1);
594 return root + fileName;
595 }
596
597 private static String getUriPath(String fileName, String inputFilePath) {
598 return new File(getFilePath(fileName, inputFilePath)).toURI().toString();
599 }
600
601 private static String getResolvedPath(String fileValue, String inputFilePath) {
602 final String resolvedFilePath;
603 if (fileValue.startsWith("(resource)")) {
604 resolvedFilePath =
605 getResourcePath(fileValue.substring(fileValue.indexOf(')') + 1),
606 inputFilePath);
607 }
608 else if (fileValue.startsWith("(uri)")) {
609 resolvedFilePath =
610 getUriPath(fileValue.substring(fileValue.indexOf(')') + 1), inputFilePath);
611 }
612 else {
613 resolvedFilePath = getFilePath(fileValue, inputFilePath);
614 }
615 return resolvedFilePath;
616 }
617
618 private static List<String> readFile(Path filePath) throws CheckstyleException {
619 try {
620 return Files.readAllLines(filePath);
621 }
622 catch (IOException ex) {
623 throw new CheckstyleException("Failed to read " + filePath, ex);
624 }
625 }
626
627 private static void setModuleName(ModuleInputConfiguration.Builder moduleInputConfigBuilder,
628 String filePath, String moduleName)
629 throws CheckstyleException {
630 final String fullyQualifiedClassName = getFullyQualifiedClassName(filePath, moduleName);
631 moduleInputConfigBuilder.setModuleName(fullyQualifiedClassName);
632 }
633
634 private static String toStringConvertForArrayValue(Object value) {
635 String result = NULL_STRING;
636
637 if (value instanceof double[]) {
638 final double[] arr = (double[]) value;
639 result = Arrays.stream(arr)
640 .boxed()
641 .map(number -> {
642 return BigDecimal.valueOf(number)
643 .stripTrailingZeros()
644 .toPlainString();
645 })
646 .collect(Collectors.joining(","));
647 }
648 else if (value instanceof int[]) {
649 result = Arrays.toString((int[]) value).replaceAll("[\\[\\]\\s]", "");
650 }
651 else if (value instanceof boolean[]) {
652 result = Arrays.toString((boolean[]) value).replaceAll("[\\[\\]\\s]", "");
653 }
654 else if (value instanceof long[]) {
655 result = Arrays.toString((long[]) value).replaceAll("[\\[\\]\\s]", "");
656 }
657 else if (value instanceof Object[]) {
658 result = Arrays.toString((Object[]) value).replaceAll("[\\[\\]\\s]", "");
659 }
660 return result;
661 }
662
663
664
665
666
667
668
669
670 private static void validateDefault(String propertyName,
671 String propertyDefaultValue,
672 String fullyQualifiedModuleName)
673 throws ReflectiveOperationException {
674 final Object checkInstance = createCheckInstance(fullyQualifiedModuleName);
675 final Object actualDefault;
676 final Class<?> propertyType;
677 final String actualDefaultAsString;
678
679 if ("tokens".equals(propertyName)) {
680 final Method getter = checkInstance.getClass().getMethod("getDefaultTokens");
681 actualDefault = getter.invoke(checkInstance);
682 propertyType = actualDefault.getClass();
683 final int[] arr = (int[]) actualDefault;
684 actualDefaultAsString = Arrays.stream(arr)
685 .mapToObj(TokenUtil::getTokenName)
686 .collect(Collectors.joining(", "));
687 }
688 else if ("javadocTokens".equals(propertyName)) {
689 final Method getter = checkInstance.getClass().getMethod("getDefaultJavadocTokens");
690 actualDefault = getter.invoke(checkInstance);
691 propertyType = actualDefault.getClass();
692 final int[] arr = (int[]) actualDefault;
693 actualDefaultAsString = Arrays.stream(arr)
694 .mapToObj(JavadocUtil::getTokenName)
695 .collect(Collectors.joining(", "));
696 }
697 else {
698 actualDefault = getPropertyDefaultValue(checkInstance, propertyName);
699 if (actualDefault == null) {
700 propertyType = null;
701 }
702 else {
703 propertyType = actualDefault.getClass();
704 }
705 actualDefaultAsString = convertDefaultValueToString(actualDefault);
706 }
707 if (!isDefaultValue(propertyDefaultValue, actualDefaultAsString, propertyType)) {
708 final String message = String.format(Locale.ROOT,
709 "Default value mismatch for %s in %s: specified '%s' but actually is '%s'",
710 propertyName, fullyQualifiedModuleName,
711 propertyDefaultValue, actualDefaultAsString);
712 throw new IllegalArgumentException(message);
713 }
714 }
715
716 private static boolean isCollectionValues(String specifiedDefault, String actualDefault) {
717 final Set<String> specifiedSet = new HashSet<>(
718 Arrays.asList(specifiedDefault.replaceAll("[\\[\\]\\s]", "").split(",")));
719 final Set<String> actualSet = new HashSet<>(
720 Arrays.asList(actualDefault.replaceAll("[\\[\\]\\s]", "").split(",")));
721 return actualSet.containsAll(specifiedSet);
722 }
723
724 private static String convertDefaultValueToString(Object value) {
725 final String defaultValueAsString;
726 if (value == null) {
727 defaultValueAsString = NULL_STRING;
728 }
729 else if (value instanceof String) {
730 defaultValueAsString = toStringForStringValue((String) value);
731 }
732 else if (value.getClass().isArray()) {
733 defaultValueAsString = toStringConvertForArrayValue(value);
734 }
735 else if (value instanceof BitSet) {
736 defaultValueAsString = toStringForBitSetValue((BitSet) value);
737 }
738 else if (value instanceof Collection<?>) {
739 defaultValueAsString = toStringForCollectionValue((Collection<?>) value);
740 }
741 else {
742 defaultValueAsString = String.valueOf(value);
743 }
744 return defaultValueAsString;
745 }
746
747 private static String toStringForStringValue(String strValue) {
748 final String str;
749 if (strValue.startsWith("(") && strValue.endsWith(")")) {
750 str = strValue.substring(1, strValue.length() - 1);
751 }
752 else {
753 str = strValue;
754 }
755 return str;
756 }
757
758 private static String toStringForBitSetValue(BitSet bitSet) {
759 return bitSet.stream()
760 .mapToObj(TokenUtil::getTokenName)
761 .collect(Collectors.joining(","));
762 }
763
764 private static String toStringForCollectionValue(Collection<?> collection) {
765 return collection.toString().replaceAll("[\\[\\]\\s]", "");
766 }
767
768
769
770
771
772
773
774
775 private static boolean isDefaultValue(final String propertyDefaultValue,
776 final String actualDefault,
777 final Class<?> fieldType) {
778 final boolean result;
779
780 if (NULL_STRING.equals(actualDefault)) {
781 result = isNull(propertyDefaultValue);
782 }
783 else if (isNumericType(fieldType)) {
784 final BigDecimal specified = new BigDecimal(propertyDefaultValue);
785 final BigDecimal actual = new BigDecimal(actualDefault);
786 result = specified.compareTo(actual) == 0;
787 }
788 else if (fieldType.isArray()
789 || Collection.class.isAssignableFrom(fieldType)
790 || BitSet.class.isAssignableFrom(fieldType)) {
791 result = isCollectionValues(propertyDefaultValue, actualDefault);
792 }
793 else if (fieldType.isEnum() || fieldType.isLocalClass()) {
794 result = propertyDefaultValue.equalsIgnoreCase(actualDefault);
795 }
796 else {
797 result = propertyDefaultValue.equals(actualDefault);
798 }
799 return result;
800 }
801
802 private static Object createCheckInstance(String className) throws
803 ReflectiveOperationException {
804 final Class<?> checkClass = Class.forName(className);
805 return checkClass.getDeclaredConstructor().newInstance();
806 }
807
808 private static String readPropertiesContent(int beginLineNo, List<String> lines) {
809 final StringBuilder stringBuilder = new StringBuilder(128);
810 int lineNo = beginLineNo;
811 String line = lines.get(lineNo);
812 while (!line.isEmpty() && !"*/".equals(line)) {
813 stringBuilder.append(line).append('\n');
814 lineNo++;
815 line = lines.get(lineNo);
816 }
817 return stringBuilder.toString();
818 }
819
820 private static void setProperties(ModuleInputConfiguration.Builder inputConfigBuilder,
821 String inputFilePath,
822 List<String> lines,
823 int beginLineNo, String moduleName)
824 throws IOException, CheckstyleException, ReflectiveOperationException {
825
826 final String propertyContent = readPropertiesContent(beginLineNo, lines);
827 final Map<Object, Object> properties = loadProperties(propertyContent);
828
829 for (final Map.Entry<Object, Object> entry : properties.entrySet()) {
830 final String key = entry.getKey().toString();
831 final String value = entry.getValue().toString();
832
833 if (key.startsWith("message.")) {
834 inputConfigBuilder.addModuleMessage(key.substring(8), value);
835 }
836 else if (NULL_STRING.equals(value)) {
837 inputConfigBuilder.addNonDefaultProperty(key, null);
838 }
839 else if (value.startsWith("(file)")) {
840 final String fileName = value.substring(value.indexOf(')') + 1);
841 final String filePath = getResolvedPath(fileName, inputFilePath);
842 inputConfigBuilder.addNonDefaultProperty(key, filePath);
843 }
844 else if (value.startsWith("(default)")) {
845 final String defaultValue = value.substring(value.indexOf(')') + 1);
846 final String fullyQualifiedModuleName =
847 getFullyQualifiedClassName(inputFilePath, moduleName);
848
849 validateDefault(key, defaultValue, fullyQualifiedModuleName);
850
851 if (NULL_STRING.equals(defaultValue)) {
852 inputConfigBuilder.addDefaultProperty(key, null);
853 }
854 else {
855 inputConfigBuilder.addDefaultProperty(key, defaultValue);
856 }
857 }
858 else {
859 inputConfigBuilder.addNonDefaultProperty(key, value);
860 }
861 }
862 }
863
864 private static void setProperties(String inputFilePath, Configuration module,
865 ModuleInputConfiguration.Builder moduleInputConfigBuilder)
866 throws CheckstyleException {
867 final String[] getPropertyNames = module.getPropertyNames();
868 for (final String propertyName : getPropertyNames) {
869 final String propertyValue = module.getProperty(propertyName);
870
871 if ("file".equals(propertyName)) {
872 final String filePath = getResolvedPath(propertyValue, inputFilePath);
873 moduleInputConfigBuilder.addNonDefaultProperty(propertyName, filePath);
874 }
875 else {
876 if (NULL_STRING.equals(propertyValue)) {
877 moduleInputConfigBuilder.addNonDefaultProperty(propertyName, null);
878 }
879 else {
880 moduleInputConfigBuilder.addNonDefaultProperty(propertyName, propertyValue);
881 }
882 }
883 }
884
885 final Map<String, String> messages = module.getMessages();
886 for (final Map.Entry<String, String> entry : messages.entrySet()) {
887 final String key = entry.getKey();
888 final String value = entry.getValue();
889 moduleInputConfigBuilder.addModuleMessage(key, value);
890 }
891 }
892
893 private static void setViolations(TestInputConfiguration.Builder inputConfigBuilder,
894 List<String> lines, boolean useFilteredViolations)
895 throws CheckstyleException {
896 final List<ModuleInputConfiguration> moduleLists = inputConfigBuilder.getChildrenModules();
897 final boolean specifyViolationMessage = moduleLists.size() == 1
898 && !PERMANENT_SUPPRESSED_CHECKS.contains(moduleLists.get(0).getModuleName())
899 && !SUPPRESSED_CHECKS.contains(moduleLists.get(0).getModuleName());
900 for (int lineNo = 0; lineNo < lines.size(); lineNo++) {
901 setViolations(inputConfigBuilder, lines,
902 useFilteredViolations, lineNo, specifyViolationMessage);
903 }
904 }
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921 private static void setViolations(TestInputConfiguration.Builder inputConfigBuilder,
922 List<String> lines, boolean useFilteredViolations,
923 int lineNo, boolean specifyViolationMessage)
924 throws CheckstyleException {
925 final Matcher violationMatcher =
926 VIOLATION_PATTERN.matcher(lines.get(lineNo));
927 final Matcher violationAboveMatcher =
928 VIOLATION_ABOVE_PATTERN.matcher(lines.get(lineNo));
929 final Matcher violationBelowMatcher =
930 VIOLATION_BELOW_PATTERN.matcher(lines.get(lineNo));
931 final Matcher violationAboveWithExplanationMatcher =
932 VIOLATION_ABOVE_WITH_EXPLANATION_PATTERN.matcher(lines.get(lineNo));
933 final Matcher violationBelowWithExplanationMatcher =
934 VIOLATION_BELOW_WITH_EXPLANATION_PATTERN.matcher(lines.get(lineNo));
935 final Matcher violationWithExplanationMatcher =
936 VIOLATION_WITH_EXPLANATION_PATTERN.matcher(lines.get(lineNo));
937 final Matcher multipleViolationsMatcher =
938 MULTIPLE_VIOLATIONS_PATTERN.matcher(lines.get(lineNo));
939 final Matcher multipleViolationsAboveMatcher =
940 MULTIPLE_VIOLATIONS_ABOVE_PATTERN.matcher(lines.get(lineNo));
941 final Matcher multipleViolationsBelowMatcher =
942 MULTIPLE_VIOLATIONS_BELOW_PATTERN.matcher(lines.get(lineNo));
943 final Matcher violationSomeLinesAboveMatcher =
944 VIOLATION_SOME_LINES_ABOVE_PATTERN.matcher(lines.get(lineNo));
945 final Matcher violationSomeLinesBelowMatcher =
946 VIOLATION_SOME_LINES_BELOW_PATTERN.matcher(lines.get(lineNo));
947 final Matcher violationsAboveMatcherWithMessages =
948 VIOLATIONS_ABOVE_PATTERN_WITH_MESSAGES.matcher(lines.get(lineNo));
949 final Matcher violationsSomeLinesAboveMatcher =
950 VIOLATIONS_SOME_LINES_ABOVE_PATTERN.matcher(lines.get(lineNo));
951 final Matcher violationsSomeLinesBelowMatcher =
952 VIOLATIONS_SOME_LINES_BELOW_PATTERN.matcher(lines.get(lineNo));
953 final Matcher violationsDefault =
954 VIOLATION_DEFAULT.matcher(lines.get(lineNo));
955 if (violationMatcher.matches()) {
956 final String violationMessage = violationMatcher.group(1);
957 final int violationLineNum = lineNo + 1;
958 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
959 violationLineNum);
960 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
961 }
962 else if (violationAboveMatcher.matches()) {
963 final String violationMessage = violationAboveMatcher.group(1);
964 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage, lineNo);
965 inputConfigBuilder.addViolation(lineNo, violationMessage);
966 }
967 else if (violationBelowMatcher.matches()) {
968 final String violationMessage = violationBelowMatcher.group(1);
969 final int violationLineNum = lineNo + 2;
970 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
971 violationLineNum);
972 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
973 }
974 else if (violationAboveWithExplanationMatcher.matches()) {
975 final String violationMessage = violationAboveWithExplanationMatcher.group(1);
976 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage, lineNo);
977 inputConfigBuilder.addViolation(lineNo, violationMessage);
978 }
979 else if (violationBelowWithExplanationMatcher.matches()) {
980 final String violationMessage = violationBelowWithExplanationMatcher.group(1);
981 final int violationLineNum = lineNo + 2;
982 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
983 violationLineNum);
984 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
985 }
986 else if (violationWithExplanationMatcher.matches()) {
987 final int violationLineNum = lineNo + 1;
988 inputConfigBuilder.addViolation(violationLineNum, null);
989 }
990 else if (violationSomeLinesAboveMatcher.matches()) {
991 final String violationMessage = violationSomeLinesAboveMatcher.group(2);
992 final int linesAbove = Integer.parseInt(violationSomeLinesAboveMatcher.group(1)) - 1;
993 final int violationLineNum = lineNo - linesAbove;
994 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
995 violationLineNum);
996 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
997 }
998 else if (violationSomeLinesBelowMatcher.matches()) {
999 final String violationMessage = violationSomeLinesBelowMatcher.group(2);
1000 final int linesBelow = Integer.parseInt(violationSomeLinesBelowMatcher.group(1)) + 1;
1001 final int violationLineNum = lineNo + linesBelow;
1002 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1003 violationLineNum);
1004 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
1005 }
1006 else if (violationsAboveMatcherWithMessages.matches()) {
1007 inputConfigBuilder.addViolations(
1008 getExpectedViolationsForSpecificLine(
1009 lines, lineNo, lineNo, violationsAboveMatcherWithMessages));
1010 }
1011 else if (violationsSomeLinesAboveMatcher.matches()) {
1012 inputConfigBuilder.addViolations(
1013 getExpectedViolations(
1014 lines, lineNo, violationsSomeLinesAboveMatcher, true));
1015 }
1016 else if (violationsSomeLinesBelowMatcher.matches()) {
1017 inputConfigBuilder.addViolations(
1018 getExpectedViolations(
1019 lines, lineNo, violationsSomeLinesBelowMatcher, false));
1020 }
1021 else if (multipleViolationsMatcher.matches()) {
1022 Collections
1023 .nCopies(Integer.parseInt(multipleViolationsMatcher.group(1)), lineNo + 1)
1024 .forEach(actualLineNumber -> {
1025 inputConfigBuilder.addViolation(actualLineNumber, null);
1026 });
1027 }
1028 else if (multipleViolationsAboveMatcher.matches()) {
1029 Collections
1030 .nCopies(Integer.parseInt(multipleViolationsAboveMatcher.group(1)), lineNo)
1031 .forEach(actualLineNumber -> {
1032 inputConfigBuilder.addViolation(actualLineNumber, null);
1033 });
1034 }
1035 else if (multipleViolationsBelowMatcher.matches()) {
1036 Collections
1037 .nCopies(Integer.parseInt(multipleViolationsBelowMatcher.group(1)),
1038 lineNo + 2)
1039 .forEach(actualLineNumber -> {
1040 inputConfigBuilder.addViolation(actualLineNumber, null);
1041 });
1042 }
1043 else if (useFilteredViolations) {
1044 setFilteredViolation(inputConfigBuilder, lineNo + 1,
1045 lines.get(lineNo), specifyViolationMessage);
1046 }
1047 else if (violationsDefault.matches()) {
1048 final int violationLineNum = lineNo + 1;
1049 inputConfigBuilder.addViolation(violationLineNum, null);
1050 }
1051 }
1052
1053 private static List<TestInputViolation> getExpectedViolationsForSpecificLine(
1054 List<String> lines, int lineNo, int violationLineNum,
1055 Matcher matcher) {
1056 final List<TestInputViolation> results = new ArrayList<>();
1057
1058 final int expectedMessageCount =
1059 Integer.parseInt(matcher.group(1));
1060 for (int index = 1; index <= expectedMessageCount; index++) {
1061 final String lineWithMessage = lines.get(lineNo + index);
1062 final Matcher messageMatcher = VIOLATION_MESSAGE_PATTERN.matcher(lineWithMessage);
1063 if (messageMatcher.find()) {
1064 final String violationMessage = messageMatcher.group(1);
1065 results.add(new TestInputViolation(violationLineNum, violationMessage));
1066 }
1067 }
1068 if (results.size() != expectedMessageCount) {
1069 final String message = String.format(Locale.ROOT,
1070 "Declared amount of violation messages at line %s is %s but found %s",
1071 lineNo + 1, expectedMessageCount, results.size());
1072 throw new IllegalStateException(message);
1073 }
1074 return results;
1075 }
1076
1077 private static List<TestInputViolation> getExpectedViolations(
1078 List<String> lines, int lineNo,
1079 Matcher matcher, boolean isAbove) {
1080 final int violationLine =
1081 Integer.parseInt(matcher.group(2));
1082 final int violationLineNum;
1083 if (isAbove) {
1084 violationLineNum = lineNo - violationLine + 1;
1085 }
1086 else {
1087 violationLineNum = lineNo + violationLine + 1;
1088 }
1089 return getExpectedViolationsForSpecificLine(lines,
1090 lineNo, violationLineNum, matcher);
1091 }
1092
1093 private static void setFilteredViolation(TestInputConfiguration.Builder inputConfigBuilder,
1094 int lineNo, String line,
1095 boolean specifyViolationMessage)
1096 throws CheckstyleException {
1097 final Matcher violationMatcher =
1098 FILTERED_VIOLATION_PATTERN.matcher(line);
1099 final Matcher violationAboveMatcher =
1100 FILTERED_VIOLATION_ABOVE_PATTERN.matcher(line);
1101 final Matcher violationBelowMatcher =
1102 FILTERED_VIOLATION_BELOW_PATTERN.matcher(line);
1103 final Matcher violationSomeLinesAboveMatcher =
1104 FILTERED_VIOLATION_SOME_LINES_ABOVE_PATTERN.matcher(line);
1105 if (violationMatcher.matches()) {
1106 final String violationMessage = violationMatcher.group(1);
1107 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage, lineNo);
1108 inputConfigBuilder.addFilteredViolation(lineNo, violationMessage);
1109 }
1110 else if (violationAboveMatcher.matches()) {
1111 final String violationMessage = violationAboveMatcher.group(1);
1112 final int violationLineNum = lineNo - 1;
1113 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1114 violationLineNum);
1115 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1116 }
1117 else if (violationBelowMatcher.matches()) {
1118 final String violationMessage = violationBelowMatcher.group(1);
1119 final int violationLineNum = lineNo + 1;
1120 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1121 violationLineNum);
1122 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1123 }
1124 else if (violationSomeLinesAboveMatcher.matches()) {
1125 final String violationMessage = violationSomeLinesAboveMatcher.group(2);
1126 final int linesAbove = Integer.parseInt(violationSomeLinesAboveMatcher.group(1)) - 1;
1127 final int violationLineNum = lineNo - linesAbove;
1128 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1129 violationLineNum);
1130 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1131 }
1132 }
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142 private static void checkWhetherViolationSpecified(boolean shouldViolationMsgBeSpecified,
1143 String violationMessage, int lineNum) throws CheckstyleException {
1144 if (shouldViolationMsgBeSpecified && violationMessage == null) {
1145 throw new CheckstyleException(
1146 "Violation message should be specified on line " + lineNum);
1147 }
1148 }
1149
1150 private static Map<Object, Object> loadProperties(String propertyContent) throws IOException {
1151 final Properties properties = new Properties();
1152 properties.load(new StringReader(propertyContent));
1153 return properties;
1154 }
1155
1156 private static boolean isNumericType(Class<?> fieldType) {
1157 return Number.class.isAssignableFrom(fieldType)
1158 || fieldType.equals(int.class)
1159 || fieldType.equals(double.class)
1160 || fieldType.equals(long.class)
1161 || fieldType.equals(float.class);
1162 }
1163
1164 public static Object getPropertyDefaultValue(Object checkInstance,
1165 String propertyName)
1166 throws IllegalAccessException {
1167 Object result = null;
1168 Class<?> currentClass = checkInstance.getClass();
1169 while (currentClass != null) {
1170 try {
1171 final Field field = currentClass.getDeclaredField(propertyName);
1172 field.setAccessible(true);
1173 result = field.get(checkInstance);
1174 break;
1175 }
1176 catch (NoSuchFieldException ex) {
1177 currentClass = currentClass.getSuperclass();
1178 }
1179 }
1180 return result;
1181 }
1182
1183 private static boolean isNull(String propertyDefaultValue) {
1184 return NULL_STRING.equals(propertyDefaultValue)
1185 || propertyDefaultValue.isEmpty()
1186 || "null".equals(propertyDefaultValue)
1187 || "\"\"".equals(propertyDefaultValue);
1188 }
1189 }