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.MagicNumberCheck",
245 "com.puppycrawl.tools.checkstyle.checks.coding.MatchXpathCheck",
246 "com.puppycrawl.tools.checkstyle.checks.coding.ModifiedControlVariableCheck",
247 "com.puppycrawl.tools.checkstyle.checks.coding.MultipleStringLiteralsCheck",
248 "com.puppycrawl.tools.checkstyle.checks.coding.NestedForDepthCheck",
249 "com.puppycrawl.tools.checkstyle.checks.coding.NestedTryDepthCheck",
250 "com.puppycrawl.tools.checkstyle.checks.coding.StringLiteralEqualityCheck",
251 "com.puppycrawl.tools.checkstyle.checks.coding.SuperFinalizeCheck",
252 "com.puppycrawl.tools.checkstyle.checks.coding"
253 + ".UnnecessarySemicolonAfterTypeMemberDeclarationCheck",
254 "com.puppycrawl.tools.checkstyle.checks.design.DesignForExtensionCheck",
255 "com.puppycrawl.tools.checkstyle.checks.design.HideUtilityClassConstructorCheck",
256 "com.puppycrawl.tools.checkstyle.checks.design.InnerTypeLastCheck",
257 "com.puppycrawl.tools.checkstyle.checks.design.MutableExceptionCheck",
258 "com.puppycrawl.tools.checkstyle.checks.design.OneTopLevelClassCheck",
259
260 "com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck",
261 "com.puppycrawl.tools.checkstyle.checks.javadoc."
262 + "AbstractJavadocCheckTest$TokenIsNotInAcceptablesCheck",
263 "com.puppycrawl.tools.checkstyle.checks.javadoc.AtclauseOrderCheck",
264 "com.puppycrawl.tools.checkstyle.checks.javadoc.InvalidJavadocPositionCheck",
265 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocBlockTagLocationCheck",
266 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMissingLeadingAsteriskCheck",
267 "com.puppycrawl.tools.checkstyle.checks.javadoc"
268 + ".JavadocMissingWhitespaceAfterAsteriskCheck",
269 "com.puppycrawl.tools.checkstyle.checks.javadoc"
270 + ".JavadocTagContinuationIndentationCheck",
271 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck",
272 "com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck",
273 "com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocPackageCheck",
274 "com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocTypeCheck",
275 "com.puppycrawl.tools.checkstyle.checks.javadoc.NonEmptyAtclauseDescriptionCheck",
276 "com.puppycrawl.tools.checkstyle.checks.javadoc"
277 + ".RequireEmptyLineBeforeBlockTagGroupCheck",
278 "com.puppycrawl.tools.checkstyle.checks.javadoc.SingleLineJavadocCheck",
279 "com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheck",
280 "com.puppycrawl.tools.checkstyle.checks.metrics.ClassDataAbstractionCouplingCheck",
281 "com.puppycrawl.tools.checkstyle.checks.metrics.ClassFanOutComplexityCheck",
282 "com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexityCheck",
283 "com.puppycrawl.tools.checkstyle.checks.metrics.NPathComplexityCheck",
284 "com.puppycrawl.tools.checkstyle.checks.modifier.ClassMemberImpliedModifierCheck",
285 "com.puppycrawl.tools.checkstyle.checks.modifier.InterfaceMemberImpliedModifierCheck",
286 "com.puppycrawl.tools.checkstyle.checks.modifier.RedundantModifierCheck",
287 "com.puppycrawl.tools.checkstyle.checks.naming.AbbreviationAsWordInNameCheck",
288
289 "com.puppycrawl.tools.checkstyle.checks.naming.IllegalIdentifierNameCheck",
290 "com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck",
291 "com.puppycrawl.tools.checkstyle.checks.naming.MethodTypeParameterNameCheck",
292 "com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck",
293 "com.puppycrawl.tools.checkstyle.checks.naming.PatternVariableNameCheck",
294 "com.puppycrawl.tools.checkstyle.checks.naming.RecordComponentNameCheck",
295 "com.puppycrawl.tools.checkstyle.checks.naming.RecordTypeParameterNameCheck",
296 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpMultilineCheck",
297 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck",
298 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck",
299 "com.puppycrawl.tools.checkstyle.checks.sizes.AnonInnerLengthCheck",
300 "com.puppycrawl.tools.checkstyle.checks.sizes.ExecutableStatementCountCheck",
301 "com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck",
302 "com.puppycrawl.tools.checkstyle.checks.sizes.OuterTypeNumberCheck",
303 "com.puppycrawl.tools.checkstyle.checks.sizes.ParameterNumberCheck",
304 "com.puppycrawl.tools.checkstyle.checks.sizes.RecordComponentNumberCheck",
305 "com.puppycrawl.tools.checkstyle.checks.TodoCommentCheck",
306 "com.puppycrawl.tools.checkstyle.checks.TrailingCommentCheck",
307 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoLineWrapCheck",
308 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceAfterCheck",
309 "com.puppycrawl.tools.checkstyle.checks.whitespace."
310 + "NoWhitespaceBeforeCaseDefaultColonCheck",
311 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCheck",
312 "com.puppycrawl.tools.checkstyle.checks.whitespace.ParenPadCheck",
313 "com.puppycrawl.tools.checkstyle.checks.whitespace.SingleSpaceSeparatorCheck",
314 "com.puppycrawl.tools.checkstyle.api.AbstractCheckTest$ViolationAstCheck",
315 "com.puppycrawl.tools.checkstyle.CheckerTest$VerifyPositionAfterTabFileSet"
316 );
317
318
319
320
321
322 private static final Set<String> SUPPRESSED_MODULES = Set.of(
323 "com.puppycrawl.tools.checkstyle.checks.TodoCommentCheck",
324 "com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck",
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.MethodNameCheck",
363 "com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck",
364 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpCheck",
365 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck",
366 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck",
367 "com.puppycrawl.tools.checkstyle.checks.sizes.FileLengthCheck",
368 "com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck",
369 "com.puppycrawl.tools.checkstyle.checks.sizes.ParameterNumberCheck",
370 "com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck",
371 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceAfterCheck",
372 "com.puppycrawl.tools.checkstyle.checks.whitespace.ParenPadCheck",
373 "com.puppycrawl.tools.checkstyle.checks.whitespace.WhitespaceAfterCheck",
374 "com.puppycrawl.tools.checkstyle.checks.whitespace.WhitespaceAroundCheck",
375 "com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder",
376 "com.puppycrawl.tools.checkstyle.filters.SuppressWithPlainTextCommentFilter",
377 "com.puppycrawl.tools.checkstyle.filters.SuppressionCommentFilter",
378 "com.puppycrawl.tools.checkstyle.filters.SuppressionXpathFilter",
379 "com.puppycrawl.tools.checkstyle.filters.SuppressionXpathSingleFilter"
380 );
381
382
383 private static final Map<String, String> MODULE_MAPPINGS = new HashMap<>();
384
385 private static final Map<String, ModuleDetails> PUBLIC_MODULE_DETAILS_MAP = new HashMap<>();
386
387
388 static {
389 MODULE_MAPPINGS.put("IllegalCatch",
390 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalCatchCheck");
391 MODULE_MAPPINGS.put("MagicNumber",
392 "com.puppycrawl.tools.checkstyle.checks.coding.MagicNumberCheck");
393 MODULE_MAPPINGS.put("SummaryJavadoc",
394 "com.puppycrawl.tools.checkstyle.checks.javadoc.SummaryJavadocCheck");
395 MODULE_MAPPINGS.put("ClassDataAbstractionCoupling",
396 "com.puppycrawl.tools.checkstyle.checks.metrics.ClassDataAbstractionCouplingCheck");
397 MODULE_MAPPINGS.put("ConstantName",
398 "com.puppycrawl.tools.checkstyle.checks.naming.ConstantNameCheck");
399 MODULE_MAPPINGS.put("MemberName",
400 "com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck");
401 MODULE_MAPPINGS.put("MethodName",
402 "com.puppycrawl.tools.checkstyle.checks.naming.MethodNameCheck");
403 MODULE_MAPPINGS.put("ParameterName",
404 "com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheck");
405 MODULE_MAPPINGS.put("RegexpOnFilename",
406 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpOnFilenameCheck");
407 MODULE_MAPPINGS.put("RegexpSingleline",
408 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineCheck");
409 MODULE_MAPPINGS.put("RegexpSinglelineJava",
410 "com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck");
411 MODULE_MAPPINGS.put("LineLength",
412 "com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck");
413 MODULE_MAPPINGS.put("ParameterNumber",
414 "com.puppycrawl.tools.checkstyle.checks.sizes.ParameterNumberCheck");
415 MODULE_MAPPINGS.put("NoWhitespaceAfter",
416 "com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceAfterCheck");
417 MODULE_MAPPINGS.put("OrderedProperties",
418 "com.puppycrawl.tools.checkstyle.checks.OrderedPropertiesCheck");
419 MODULE_MAPPINGS.put("SuppressWarningsHolder",
420 "com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder");
421 MODULE_MAPPINGS.put("UniqueProperties",
422 "com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck");
423 MODULE_MAPPINGS.put("SuppressionXpathSingleFilter",
424 "com.puppycrawl.tools.checkstyle.filters.SuppressionXpathSingleFilter");
425 MODULE_MAPPINGS.put("SuppressWarningsFilter",
426 "com.puppycrawl.tools.checkstyle.filters.SuppressWarningsFilter");
427 MODULE_MAPPINGS.put("LeftCurly",
428 "com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck");
429 MODULE_MAPPINGS.put("RequireThis",
430 "com.puppycrawl.tools.checkstyle.checks.coding.RequireThisCheck");
431 MODULE_MAPPINGS.put("IllegalThrows",
432 "com.puppycrawl.tools.checkstyle.checks.coding.IllegalThrowsCheck");
433 MODULE_MAPPINGS.put("LocalFinalVariableName",
434 "com.puppycrawl.tools.checkstyle.checks.naming.LocalFinalVariableNameCheck");
435 MODULE_MAPPINGS.put("PackageName",
436 "com.puppycrawl.tools.checkstyle.checks.naming.PackageNameCheck");
437 MODULE_MAPPINGS.put("RedundantModifier",
438 "com.puppycrawl.tools.checkstyle.checks.modifier.RedundantModifierCheck");
439 MODULE_MAPPINGS.put("AbstractClassName",
440 "com.puppycrawl.tools.checkstyle.checks.naming.AbstractClassNameCheck");
441 MODULE_MAPPINGS.put("JavadocMethod",
442 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck");
443 MODULE_MAPPINGS.put("IllegalIdentifierName",
444 "com.puppycrawl.tools.checkstyle.checks.naming.IllegalIdentifierNameCheck");
445 MODULE_MAPPINGS.put("FileLength",
446 "com.puppycrawl.tools.checkstyle.checks.sizes.FileLengthCheck");
447 MODULE_MAPPINGS.put("EqualsAvoidNull",
448 "com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck");
449 MODULE_MAPPINGS.put("JavadocStyle",
450 "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocStyleCheck");
451 MODULE_MAPPINGS.put("CyclomaticComplexity",
452 "com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexityCheck");
453 MODULE_MAPPINGS.put("EmptyLineSeparator",
454 "com.puppycrawl.tools.checkstyle.checks.whitespace.EmptyLineSeparatorCheck");
455 MODULE_MAPPINGS.put("LocalVariableName",
456 "com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck");
457 MODULE_MAPPINGS.put("ModifierOrder",
458 "com.puppycrawl.tools.checkstyle.checks.modifier.ModifierOrderCheck");
459 }
460
461
462 private InlineConfigParser() {
463 }
464
465 public static TestInputConfiguration parse(String inputFilePath) throws Exception {
466 return parse(inputFilePath, false);
467 }
468
469
470
471
472
473
474
475
476 private static TestInputConfiguration parse(String inputFilePath,
477 boolean setFilteredViolations) throws Exception {
478 final TestInputConfiguration.Builder testInputConfigBuilder =
479 new TestInputConfiguration.Builder();
480 final Path filePath = Path.of(inputFilePath);
481 final List<String> lines = readFile(filePath);
482 try {
483 setModules(testInputConfigBuilder, inputFilePath, lines);
484 }
485 catch (Exception exc) {
486 throw new CheckstyleException("Config comment not specified properly in "
487 + inputFilePath, exc);
488 }
489 try {
490 setViolations(testInputConfigBuilder, lines, setFilteredViolations);
491 }
492 catch (CheckstyleException exc) {
493 throw new CheckstyleException(exc.getMessage() + " in " + inputFilePath, exc);
494 }
495 return testInputConfigBuilder.build();
496 }
497
498 public static List<TestInputViolation> getViolationsFromInputFile(String inputFilePath)
499 throws Exception {
500 final TestInputConfiguration.Builder testInputConfigBuilder =
501 new TestInputConfiguration.Builder();
502 final Path filePath = Path.of(inputFilePath);
503 final List<String> lines = readFile(filePath);
504
505 try {
506 for (int lineNo = 0; lineNo < lines.size(); lineNo++) {
507 setViolations(testInputConfigBuilder, lines, false, lineNo, true);
508 }
509 }
510 catch (CheckstyleException exc) {
511 throw new CheckstyleException(exc.getMessage() + " in " + inputFilePath, exc);
512 }
513
514 return testInputConfigBuilder.build().getViolations();
515 }
516
517 public static List<TestInputViolation> getFilteredViolationsFromInputFile(String inputFilePath)
518 throws Exception {
519 final TestInputConfiguration.Builder testInputConfigBuilder =
520 new TestInputConfiguration.Builder();
521 final Path filePath = Path.of(inputFilePath);
522 final List<String> lines = readFile(filePath);
523
524 try {
525 for (int lineNo = 0; lineNo < lines.size(); lineNo++) {
526 setViolations(testInputConfigBuilder, lines, true, lineNo, true);
527 }
528 }
529 catch (CheckstyleException exc) {
530 throw new CheckstyleException(exc.getMessage() + " in " + inputFilePath, exc);
531 }
532
533 return testInputConfigBuilder.build().getFilteredViolations();
534 }
535
536 public static TestInputConfiguration parseWithFilteredViolations(String inputFilePath)
537 throws Exception {
538 return parse(inputFilePath, true);
539 }
540
541
542
543
544
545
546
547 public static TestInputConfiguration parseWithXmlHeader(String inputFilePath)
548 throws Exception {
549
550 final Path filePath = Path.of(inputFilePath);
551 final List<String> lines = readFile(filePath);
552 if (!checkIsXmlConfig(lines)) {
553 throw new CheckstyleException("Config cannot be parsed as xml.");
554 }
555
556 final List<String> inlineConfig = getInlineConfig(lines);
557 final String stringXmlConfig = LATEST_DTD + String.join("", inlineConfig);
558 final InputSource inputSource = new InputSource(new StringReader(stringXmlConfig));
559 final Configuration xmlConfig = ConfigurationLoader.loadConfiguration(
560 inputSource, new PropertiesExpander(System.getProperties()),
561 ConfigurationLoader.IgnoredModulesOptions.EXECUTE
562 );
563 final String configName = xmlConfig.getName();
564 if (!"Checker".equals(configName)) {
565 throw new CheckstyleException(
566 "First module should be Checker, but was " + configName);
567 }
568
569 final TestInputConfiguration.Builder testInputConfigBuilder =
570 new TestInputConfiguration.Builder();
571 testInputConfigBuilder.setXmlConfiguration(xmlConfig);
572 try {
573 setViolations(testInputConfigBuilder, lines, false);
574 }
575 catch (CheckstyleException exc) {
576 throw new CheckstyleException(exc.getMessage() + " in " + inputFilePath, exc);
577 }
578 return testInputConfigBuilder.buildWithXmlConfiguration();
579 }
580
581
582
583
584
585
586
587 private static boolean checkIsXmlConfig(List<String> lines) {
588 return "/*xml".equals(lines.get(0));
589 }
590
591 private static void setModules(TestInputConfiguration.Builder testInputConfigBuilder,
592 String inputFilePath, List<String> lines)
593 throws Exception {
594 if (!lines.get(0).startsWith("/*")) {
595 throw new CheckstyleException("Config not specified on top."
596 + "Please see other inputs for examples of what is required.");
597 }
598
599 final List<String> inlineConfig = getInlineConfig(lines);
600
601 if (checkIsXmlConfig(lines)) {
602 final String stringXmlConfig = LATEST_DTD + String.join("", inlineConfig);
603 final InputSource inputSource = new InputSource(new StringReader(stringXmlConfig));
604 final Configuration xmlConfig = ConfigurationLoader.loadConfiguration(
605 inputSource, new PropertiesExpander(System.getProperties()),
606 ConfigurationLoader.IgnoredModulesOptions.EXECUTE
607 );
608 final String configName = xmlConfig.getName();
609 if (!"Checker".equals(configName)) {
610 throw new CheckstyleException(
611 "First module should be Checker, but was " + configName);
612 }
613 handleXmlConfig(testInputConfigBuilder, inputFilePath, xmlConfig.getChildren());
614 }
615 else {
616 handleKeyValueConfig(testInputConfigBuilder, inputFilePath, inlineConfig);
617 }
618 }
619
620 private static List<String> getInlineConfig(List<String> lines) {
621 return lines.stream()
622 .skip(1)
623 .takeWhile(line -> !line.startsWith("*/"))
624 .toList();
625 }
626
627 private static void handleXmlConfig(TestInputConfiguration.Builder testInputConfigBuilder,
628 String inputFilePath,
629 Configuration... modules)
630 throws CheckstyleException {
631
632 for (Configuration module: modules) {
633 final String moduleName = module.getName();
634 if ("TreeWalker".equals(moduleName)) {
635 handleXmlConfig(testInputConfigBuilder, inputFilePath, module.getChildren());
636 }
637 else {
638 final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
639 new ModuleInputConfiguration.Builder();
640 setModuleName(moduleInputConfigBuilder, inputFilePath, moduleName);
641 setProperties(inputFilePath, module, moduleInputConfigBuilder);
642 testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
643 }
644 }
645 }
646
647 private static void handleKeyValueConfig(TestInputConfiguration.Builder testInputConfigBuilder,
648 String inputFilePath, List<String> lines)
649 throws CheckstyleException, IOException, ReflectiveOperationException {
650 int lineNo = 0;
651 while (lineNo < lines.size()) {
652 final ModuleInputConfiguration.Builder moduleInputConfigBuilder =
653 new ModuleInputConfiguration.Builder();
654 final String moduleName = lines.get(lineNo);
655 setModuleName(moduleInputConfigBuilder, inputFilePath, moduleName);
656 setProperties(moduleInputConfigBuilder, inputFilePath, lines, lineNo + 1, moduleName);
657 testInputConfigBuilder.addChildModule(moduleInputConfigBuilder.build());
658 do {
659 lineNo++;
660 } while (lineNo < lines.size()
661 && lines.get(lineNo).isEmpty()
662 || !lines.get(lineNo - 1).isEmpty());
663 }
664 }
665
666 private static Map<String, String> getDefaultProperties(String fullyQualifiedClassName) {
667
668 final Map<String, String> defaultProperties = new HashMap<>();
669 final boolean isSuppressedModule = SUPPRESSED_MODULES.contains(fullyQualifiedClassName);
670
671 if (PUBLIC_MODULE_DETAILS_MAP.isEmpty()) {
672 XmlMetaReader.readAllModulesIncludingThirdPartyIfAny().forEach(module -> {
673 PUBLIC_MODULE_DETAILS_MAP.put(module.getFullQualifiedName(), module);
674 });
675 }
676
677 final ModuleDetails moduleDetails = PUBLIC_MODULE_DETAILS_MAP.get(fullyQualifiedClassName);
678
679 if (!isSuppressedModule && moduleDetails != null) {
680 defaultProperties.putAll(moduleDetails.getProperties().stream()
681 .filter(prop -> {
682 return prop.getName() != null && prop.getDefaultValue() != null;
683 })
684 .collect(Collectors.toUnmodifiableMap(
685 ModulePropertyDetails::getName,
686 ModulePropertyDetails::getDefaultValue
687 )));
688 }
689
690 return defaultProperties;
691 }
692
693 private static String getFullyQualifiedClassName(String filePath, String moduleName)
694 throws CheckstyleException {
695 String fullyQualifiedClassName;
696 if (MODULE_MAPPINGS.containsKey(moduleName)) {
697 fullyQualifiedClassName = MODULE_MAPPINGS.get(moduleName);
698 }
699 else if (moduleName.startsWith("com.")) {
700 fullyQualifiedClassName = moduleName;
701 }
702 else {
703 final String path = SLASH_PATTERN.matcher(filePath).replaceAll(".");
704 final int endIndex = path.lastIndexOf(moduleName.toLowerCase(Locale.ROOT));
705 if (endIndex == -1) {
706 throw new CheckstyleException("Unable to resolve module name: " + moduleName
707 + ". Please check for spelling errors or specify fully qualified class name.");
708 }
709 final int beginIndex = path.indexOf("com.puppycrawl");
710 fullyQualifiedClassName = path.substring(beginIndex, endIndex) + moduleName;
711 if (!fullyQualifiedClassName.endsWith("Filter")) {
712 fullyQualifiedClassName += "Check";
713 }
714 }
715 return fullyQualifiedClassName;
716 }
717
718 private static String getFilePath(String fileName, String inputFilePath) {
719 final int lastSlashIndex = Math.max(inputFilePath.lastIndexOf('\\'),
720 inputFilePath.lastIndexOf('/'));
721 final String root = inputFilePath.substring(0, lastSlashIndex + 1);
722 return root + fileName;
723 }
724
725 private static String getResourcePath(String fileName, String inputFilePath) {
726 final String filePath = getUriPath(fileName, inputFilePath);
727 final int lastSlashIndex = filePath.lastIndexOf('/');
728 final String root = filePath.substring(filePath.indexOf("puppycrawl") - 5,
729 lastSlashIndex + 1);
730 return root + fileName;
731 }
732
733 private static String getUriPath(String fileName, String inputFilePath) {
734 return new File(getFilePath(fileName, inputFilePath)).toURI().toString();
735 }
736
737 private static String getResolvedPath(String fileValue, String inputFilePath) {
738 final String resolvedFilePath;
739
740 if (fileValue.startsWith("(resource)")) {
741 resolvedFilePath =
742 getResourcePath(fileValue.substring(fileValue.indexOf(')') + 1),
743 inputFilePath);
744 }
745 else if (fileValue.startsWith("(uri)")) {
746 resolvedFilePath =
747 getUriPath(fileValue.substring(fileValue.indexOf(')') + 1), inputFilePath);
748 }
749 else if (fileValue.contains("/") || fileValue.contains("\\")) {
750 resolvedFilePath = fileValue;
751 }
752 else {
753 resolvedFilePath = getFilePath(fileValue, inputFilePath);
754 }
755
756 return resolvedFilePath;
757 }
758
759 private static List<String> readFile(Path filePath) throws CheckstyleException {
760 try {
761 return Files.readAllLines(filePath);
762 }
763 catch (IOException exc) {
764 throw new CheckstyleException("Failed to read " + filePath, exc);
765 }
766 }
767
768 private static void setModuleName(ModuleInputConfiguration.Builder moduleInputConfigBuilder,
769 String filePath, String moduleName)
770 throws CheckstyleException {
771 final String fullyQualifiedClassName = getFullyQualifiedClassName(filePath, moduleName);
772 moduleInputConfigBuilder.setModuleName(fullyQualifiedClassName);
773 }
774
775 private static String toStringConvertForArrayValue(Object value) {
776 String result = NULL_STRING;
777
778 if (value instanceof double[] arr) {
779 result = Arrays.stream(arr)
780 .boxed()
781 .map(number -> {
782 return BigDecimal.valueOf(number)
783 .stripTrailingZeros()
784 .toPlainString();
785 })
786 .collect(Collectors.joining(","));
787 }
788 else if (value instanceof int[] ints) {
789 result = Arrays.toString(ints).replaceAll("[\\[\\]\\s]", "");
790 }
791 else if (value instanceof boolean[] booleans) {
792 result = Arrays.toString(booleans).replaceAll("[\\[\\]\\s]", "");
793 }
794 else if (value instanceof long[] longs) {
795 result = Arrays.toString(longs).replaceAll("[\\[\\]\\s]", "");
796 }
797 else if (value instanceof Object[] objects) {
798 result = Arrays.toString(objects).replaceAll("[\\[\\]\\s]", "");
799 }
800 return result;
801 }
802
803
804
805
806
807
808
809
810 private static void validateDefault(String propertyName,
811 String propertyDefaultValue,
812 String fullyQualifiedModuleName)
813 throws ReflectiveOperationException {
814 final Object checkInstance = createCheckInstance(fullyQualifiedModuleName);
815 final Object actualDefault;
816 final Class<?> propertyType;
817 final String actualDefaultAsString;
818
819 if ("tokens".equals(propertyName)) {
820 actualDefault = TestUtil.invokeMethod(checkInstance, "getDefaultTokens");
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, "getDefaultJavadocTokens");
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 void setViolations(TestInputConfiguration.Builder inputConfigBuilder,
1078 List<String> lines, boolean useFilteredViolations)
1079 throws CheckstyleException {
1080 final List<ModuleInputConfiguration> moduleLists = inputConfigBuilder.getChildrenModules();
1081 final boolean specifyViolationMessage = moduleLists.size() == 1
1082 && !PERMANENT_SUPPRESSED_CHECKS.contains(moduleLists.get(0).getModuleName())
1083 && !SUPPRESSED_CHECKS.contains(moduleLists.get(0).getModuleName());
1084 for (int lineNo = 0; lineNo < lines.size(); lineNo++) {
1085 setViolations(inputConfigBuilder, lines,
1086 useFilteredViolations, lineNo, specifyViolationMessage);
1087 }
1088 }
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105 private static void setViolations(TestInputConfiguration.Builder inputConfigBuilder,
1106 List<String> lines, boolean useFilteredViolations,
1107 int lineNo, boolean specifyViolationMessage)
1108 throws CheckstyleException {
1109 final String line = lines.get(lineNo);
1110 if (ANY_OK_VIOLATION_PATTERN.matcher(line).matches()
1111 && !ALLOWED_OK_VIOLATION_PATTERN.matcher(line).matches()) {
1112 throw new CheckstyleException(
1113 "Invalid format (must be \"// ok...\" or \"// violation...\"): " + line);
1114 }
1115
1116 final Matcher violationMatcher =
1117 VIOLATION_PATTERN.matcher(lines.get(lineNo));
1118 final Matcher violationAboveMatcher =
1119 VIOLATION_ABOVE_PATTERN.matcher(lines.get(lineNo));
1120 final Matcher violationBelowMatcher =
1121 VIOLATION_BELOW_PATTERN.matcher(lines.get(lineNo));
1122 final Matcher violationAboveWithExplanationMatcher =
1123 VIOLATION_ABOVE_WITH_EXPLANATION_PATTERN.matcher(lines.get(lineNo));
1124 final Matcher violationBelowWithExplanationMatcher =
1125 VIOLATION_BELOW_WITH_EXPLANATION_PATTERN.matcher(lines.get(lineNo));
1126 final Matcher violationWithExplanationMatcher =
1127 VIOLATION_WITH_EXPLANATION_PATTERN.matcher(lines.get(lineNo));
1128 final Matcher multipleViolationsMatcher =
1129 MULTIPLE_VIOLATIONS_PATTERN.matcher(lines.get(lineNo));
1130 final Matcher multipleViolationsAboveMatcher =
1131 MULTIPLE_VIOLATIONS_ABOVE_PATTERN.matcher(lines.get(lineNo));
1132 final Matcher multipleViolationsBelowMatcher =
1133 MULTIPLE_VIOLATIONS_BELOW_PATTERN.matcher(lines.get(lineNo));
1134 final Matcher violationSomeLinesAboveMatcher =
1135 VIOLATION_SOME_LINES_ABOVE_PATTERN.matcher(lines.get(lineNo));
1136 final Matcher violationSomeLinesBelowMatcher =
1137 VIOLATION_SOME_LINES_BELOW_PATTERN.matcher(lines.get(lineNo));
1138 final Matcher violationsAboveMatcherWithMessages =
1139 VIOLATIONS_ABOVE_PATTERN_WITH_MESSAGES.matcher(lines.get(lineNo));
1140 final Matcher violationsSomeLinesAboveMatcher =
1141 VIOLATIONS_SOME_LINES_ABOVE_PATTERN.matcher(lines.get(lineNo));
1142 final Matcher violationsSomeLinesBelowMatcher =
1143 VIOLATIONS_SOME_LINES_BELOW_PATTERN.matcher(lines.get(lineNo));
1144 final Matcher violationsDefault =
1145 VIOLATION_DEFAULT.matcher(lines.get(lineNo));
1146 if (violationMatcher.matches()) {
1147 final String violationMessage = violationMatcher.group(1);
1148 final int violationLineNum = lineNo + 1;
1149 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1150 violationLineNum);
1151 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
1152 }
1153 else if (violationAboveMatcher.matches()) {
1154 final String violationMessage = violationAboveMatcher.group(1);
1155 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage, lineNo);
1156 inputConfigBuilder.addViolation(lineNo, violationMessage);
1157 }
1158 else if (violationBelowMatcher.matches()) {
1159 final String violationMessage = violationBelowMatcher.group(1);
1160 final int violationLineNum = lineNo + 2;
1161 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1162 violationLineNum);
1163 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
1164 }
1165 else if (violationAboveWithExplanationMatcher.matches()) {
1166 final String violationMessage = violationAboveWithExplanationMatcher.group(1);
1167 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage, lineNo);
1168 inputConfigBuilder.addViolation(lineNo, violationMessage);
1169 }
1170 else if (violationBelowWithExplanationMatcher.matches()) {
1171 final String violationMessage = violationBelowWithExplanationMatcher.group(1);
1172 final int violationLineNum = lineNo + 2;
1173 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1174 violationLineNum);
1175 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
1176 }
1177 else if (violationWithExplanationMatcher.matches()) {
1178 final int violationLineNum = lineNo + 1;
1179 inputConfigBuilder.addViolation(violationLineNum, null);
1180 }
1181 else if (violationSomeLinesAboveMatcher.matches()) {
1182 final String violationMessage = violationSomeLinesAboveMatcher.group(2);
1183 final int linesAbove = Integer.parseInt(violationSomeLinesAboveMatcher.group(1)) - 1;
1184 final int violationLineNum = lineNo - linesAbove;
1185 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1186 violationLineNum);
1187 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
1188 }
1189 else if (violationSomeLinesBelowMatcher.matches()) {
1190 final String violationMessage = violationSomeLinesBelowMatcher.group(2);
1191 final int linesBelow = Integer.parseInt(violationSomeLinesBelowMatcher.group(1)) + 1;
1192 final int violationLineNum = lineNo + linesBelow;
1193 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1194 violationLineNum);
1195 inputConfigBuilder.addViolation(violationLineNum, violationMessage);
1196 }
1197 else if (violationsAboveMatcherWithMessages.matches()) {
1198 inputConfigBuilder.addViolations(
1199 getExpectedViolationsForSpecificLine(
1200 lines, lineNo, lineNo, violationsAboveMatcherWithMessages));
1201 }
1202 else if (violationsSomeLinesAboveMatcher.matches()) {
1203 inputConfigBuilder.addViolations(
1204 getExpectedViolations(
1205 lines, lineNo, violationsSomeLinesAboveMatcher, true));
1206 }
1207 else if (violationsSomeLinesBelowMatcher.matches()) {
1208 inputConfigBuilder.addViolations(
1209 getExpectedViolations(
1210 lines, lineNo, violationsSomeLinesBelowMatcher, false));
1211 }
1212 else if (multipleViolationsMatcher.matches()) {
1213 Collections
1214 .nCopies(Integer.parseInt(multipleViolationsMatcher.group(1)), lineNo + 1)
1215 .forEach(actualLineNumber -> {
1216 inputConfigBuilder.addViolation(actualLineNumber, null);
1217 });
1218 }
1219 else if (multipleViolationsAboveMatcher.matches()) {
1220 Collections
1221 .nCopies(Integer.parseInt(multipleViolationsAboveMatcher.group(1)), lineNo)
1222 .forEach(actualLineNumber -> {
1223 inputConfigBuilder.addViolation(actualLineNumber, null);
1224 });
1225 }
1226 else if (multipleViolationsBelowMatcher.matches()) {
1227 Collections
1228 .nCopies(Integer.parseInt(multipleViolationsBelowMatcher.group(1)),
1229 lineNo + 2)
1230 .forEach(actualLineNumber -> {
1231 inputConfigBuilder.addViolation(actualLineNumber, null);
1232 });
1233 }
1234 else if (useFilteredViolations) {
1235 setFilteredViolation(inputConfigBuilder, lineNo + 1,
1236 lines.get(lineNo), specifyViolationMessage);
1237 }
1238 else if (violationsDefault.matches()) {
1239 final int violationLineNum = lineNo + 1;
1240 inputConfigBuilder.addViolation(violationLineNum, null);
1241 }
1242 }
1243
1244 private static List<TestInputViolation> getExpectedViolationsForSpecificLine(
1245 List<String> lines, int lineNo, int violationLineNum,
1246 Matcher matcher) {
1247 final List<TestInputViolation> results = new ArrayList<>();
1248
1249 final int expectedMessageCount =
1250 Integer.parseInt(matcher.group(1));
1251 for (int index = 1; index <= expectedMessageCount; index++) {
1252 final String lineWithMessage = lines.get(lineNo + index);
1253 final Matcher messageMatcher = VIOLATION_MESSAGE_PATTERN.matcher(lineWithMessage);
1254 if (messageMatcher.find()) {
1255 final String violationMessage = messageMatcher.group(1);
1256 results.add(new TestInputViolation(violationLineNum, violationMessage));
1257 }
1258 }
1259 if (results.size() != expectedMessageCount) {
1260 final String message = String.format(Locale.ROOT,
1261 "Declared amount of violation messages at line %s is %s but found %s",
1262 lineNo + 1, expectedMessageCount, results.size());
1263 throw new IllegalStateException(message);
1264 }
1265 return results;
1266 }
1267
1268 private static List<TestInputViolation> getExpectedViolations(
1269 List<String> lines, int lineNo,
1270 Matcher matcher, boolean isAbove) {
1271 final int violationLine =
1272 Integer.parseInt(matcher.group(2));
1273 final int violationLineNum;
1274 if (isAbove) {
1275 violationLineNum = lineNo - violationLine + 1;
1276 }
1277 else {
1278 violationLineNum = lineNo + violationLine + 1;
1279 }
1280 return getExpectedViolationsForSpecificLine(lines,
1281 lineNo, violationLineNum, matcher);
1282 }
1283
1284 private static void setFilteredViolation(TestInputConfiguration.Builder inputConfigBuilder,
1285 int lineNo, String line,
1286 boolean specifyViolationMessage)
1287 throws CheckstyleException {
1288 final Matcher violationMatcher =
1289 FILTERED_VIOLATION_PATTERN.matcher(line);
1290 final Matcher violationAboveMatcher =
1291 FILTERED_VIOLATION_ABOVE_PATTERN.matcher(line);
1292 final Matcher violationBelowMatcher =
1293 FILTERED_VIOLATION_BELOW_PATTERN.matcher(line);
1294 final Matcher violationSomeLinesAboveMatcher =
1295 FILTERED_VIOLATION_SOME_LINES_ABOVE_PATTERN.matcher(line);
1296 final Matcher violationSomeLinesBelowMatcher =
1297 FILTERED_VIOLATION_SOME_LINES_BELOW_PATTERN.matcher(line);
1298 if (violationMatcher.matches()) {
1299 final String violationMessage = violationMatcher.group(1);
1300 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage, lineNo);
1301 inputConfigBuilder.addFilteredViolation(lineNo, violationMessage);
1302 }
1303 else if (violationAboveMatcher.matches()) {
1304 final String violationMessage = violationAboveMatcher.group(1);
1305 final int violationLineNum = lineNo - 1;
1306 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1307 violationLineNum);
1308 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1309 }
1310 else if (violationBelowMatcher.matches()) {
1311 final String violationMessage = violationBelowMatcher.group(1);
1312 final int violationLineNum = lineNo + 1;
1313 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1314 violationLineNum);
1315 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1316 }
1317 else if (violationSomeLinesAboveMatcher.matches()) {
1318 final String violationMessage = violationSomeLinesAboveMatcher.group(2);
1319 final int linesAbove = Integer.parseInt(violationSomeLinesAboveMatcher.group(1));
1320 final int violationLineNum = lineNo - linesAbove;
1321 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1322 violationLineNum);
1323 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1324 }
1325 else if (violationSomeLinesBelowMatcher.matches()) {
1326 final String violationMessage = violationSomeLinesBelowMatcher.group(2);
1327 final int linesBelow = Integer.parseInt(violationSomeLinesBelowMatcher.group(1));
1328 final int violationLineNum = lineNo + linesBelow;
1329 checkWhetherViolationSpecified(specifyViolationMessage, violationMessage,
1330 violationLineNum);
1331 inputConfigBuilder.addFilteredViolation(violationLineNum, violationMessage);
1332 }
1333 }
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343 private static void checkWhetherViolationSpecified(boolean shouldViolationMsgBeSpecified,
1344 String violationMessage, int lineNum) throws CheckstyleException {
1345 if (shouldViolationMsgBeSpecified && violationMessage == null) {
1346 throw new CheckstyleException(
1347 "Violation message should be specified on line " + lineNum);
1348 }
1349 }
1350
1351 private static Map<Object, Object> loadProperties(String propertyContent) throws IOException {
1352 final Properties properties = new Properties();
1353 properties.load(new StringReader(propertyContent));
1354 return properties;
1355 }
1356
1357 private static boolean isNumericType(Class<?> fieldType) {
1358 return Number.class.isAssignableFrom(fieldType)
1359 || fieldType.equals(int.class)
1360 || fieldType.equals(double.class)
1361 || fieldType.equals(long.class)
1362 || fieldType.equals(float.class);
1363 }
1364
1365 public static Object getPropertyDefaultValue(Object checkInstance,
1366 String propertyName) {
1367 Object retVal;
1368 try {
1369 retVal = TestUtil.getInternalState(checkInstance, propertyName, Object.class);
1370 }
1371 catch (IllegalStateException exc) {
1372 retVal = null;
1373 }
1374 return retVal;
1375 }
1376
1377 private static boolean isNull(String propertyDefaultValue) {
1378 return NULL_STRING.equals(propertyDefaultValue)
1379 || propertyDefaultValue.isEmpty()
1380 || "null".equals(propertyDefaultValue)
1381 || "\"\"".equals(propertyDefaultValue);
1382 }
1383
1384 }