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