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