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