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