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