001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2023 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.filters; 021 022import java.lang.ref.WeakReference; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.List; 026import java.util.Objects; 027import java.util.regex.Matcher; 028import java.util.regex.Pattern; 029import java.util.regex.PatternSyntaxException; 030 031import com.puppycrawl.tools.checkstyle.PropertyType; 032import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; 033import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; 034import com.puppycrawl.tools.checkstyle.XdocsPropertyType; 035import com.puppycrawl.tools.checkstyle.api.AutomaticBean; 036import com.puppycrawl.tools.checkstyle.api.FileContents; 037import com.puppycrawl.tools.checkstyle.api.TextBlock; 038import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 039 040/** 041 * <p> 042 * Filter {@code SuppressWithNearbyCommentFilter} uses nearby comments to suppress audit events. 043 * </p> 044 * <p> 045 * Rationale: Same as {@code SuppressionCommentFilter}. 046 * Whereas the SuppressionCommentFilter uses matched pairs of filters to turn 047 * on/off comment matching, {@code SuppressWithNearbyCommentFilter} uses single comments. 048 * This requires fewer lines to mark a region, and may be aesthetically preferable in some contexts. 049 * </p> 050 * <p> 051 * Attention: This filter may only be specified within the TreeWalker module 052 * ({@code <module name="TreeWalker"/>}) and only applies to checks which are also 053 * defined within this module. To filter non-TreeWalker checks like {@code RegexpSingleline}, 054 * a <a href="https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter"> 055 * SuppressWithPlainTextCommentFilter</a> or similar filter must be used. 056 * </p> 057 * <p> 058 * SuppressWithNearbyCommentFilter can suppress Checks that have 059 * Treewalker as parent module. 060 * </p> 061 * <ul> 062 * <li> 063 * Property {@code commentFormat} - Specify comment pattern to trigger filter to begin suppression. 064 * Type is {@code java.util.regex.Pattern}. 065 * Default value is {@code "SUPPRESS CHECKSTYLE (\w+)"}. 066 * </li> 067 * <li> 068 * Property {@code checkFormat} - Specify check pattern to suppress. 069 * Type is {@code java.util.regex.Pattern}. 070 * Default value is {@code ".*"}. 071 * </li> 072 * <li> 073 * Property {@code messageFormat} - Define message pattern to suppress. 074 * Type is {@code java.util.regex.Pattern}. 075 * Default value is {@code null}. 076 * </li> 077 * <li> 078 * Property {@code idFormat} - Specify check ID pattern to suppress. 079 * Type is {@code java.util.regex.Pattern}. 080 * Default value is {@code null}. 081 * </li> 082 * <li> 083 * Property {@code influenceFormat} - Specify negative/zero/positive value that 084 * defines the number of lines preceding/at/following the suppression comment. 085 * Type is {@code java.lang.String}. 086 * Default value is {@code "0"}. 087 * </li> 088 * <li> 089 * Property {@code checkCPP} - Control whether to check C++ style comments ({@code //}). 090 * Type is {@code boolean}. 091 * Default value is {@code true}. 092 * </li> 093 * <li> 094 * Property {@code checkC} - Control whether to check C style comments ({@code /* ... */}). 095 * Type is {@code boolean}. 096 * Default value is {@code true}. 097 * </li> 098 * </ul> 099 * <p> 100 * To configure a filter to suppress audit events for <i>check</i> on any line 101 * with a comment {@code SUPPRESS CHECKSTYLE <i>check</i>}: 102 * </p> 103 * <pre> 104 * <module name="SuppressWithNearbyCommentFilter"/> 105 * </pre> 106 * <pre> 107 * private int [] array; // SUPPRESS CHECKSTYLE 108 * </pre> 109 * <p> 110 * To configure a filter to suppress all audit events on any line containing 111 * the comment {@code CHECKSTYLE IGNORE THIS LINE}: 112 * </p> 113 * <pre> 114 * <module name="SuppressWithNearbyCommentFilter"> 115 * <property name="commentFormat" value="CHECKSTYLE IGNORE THIS LINE"/> 116 * <property name="checkFormat" value=".*"/> 117 * <property name="influenceFormat" value="0"/> 118 * </module> 119 * </pre> 120 * <pre> 121 * public static final int lowerCaseConstant; // CHECKSTYLE IGNORE THIS LINE 122 * </pre> 123 * <p> 124 * To configure a filter so that {@code // OK to catch (Throwable|Exception|RuntimeException) here} 125 * permits the current and previous line to avoid generating an IllegalCatch audit event: 126 * </p> 127 * <pre> 128 * <module name="SuppressWithNearbyCommentFilter"> 129 * <property name="commentFormat" value="OK to catch (\w+) here"/> 130 * <property name="checkFormat" value="IllegalCatchCheck"/> 131 * <property name="messageFormat" value="$1"/> 132 * <property name="influenceFormat" value="-1"/> 133 * </module> 134 * </pre> 135 * <pre> 136 * . . . 137 * catch (RuntimeException re) { 138 * // OK to catch RuntimeException here 139 * } 140 * catch (Throwable th) { ... } 141 * . . . 142 * </pre> 143 * <p> 144 * To configure a filter so that {@code CHECKSTYLE IGNORE <i>check</i> FOR NEXT 145 * <i>var</i> LINES} avoids triggering any audits for the given check for 146 * the current line and the next <i>var</i> lines (for a total of <i>var</i>+1 lines): 147 * </p> 148 * <pre> 149 * <module name="SuppressWithNearbyCommentFilter"> 150 * <property name="commentFormat" 151 * value="CHECKSTYLE IGNORE (\w+) FOR NEXT (\d+) LINES"/> 152 * <property name="checkFormat" value="$1"/> 153 * <property name="influenceFormat" value="$2"/> 154 * </module> 155 * </pre> 156 * <pre> 157 * static final int lowerCaseConstant; // CHECKSTYLE IGNORE ConstantNameCheck FOR NEXT 3 LINES 158 * static final int lowerCaseConstant1; 159 * static final int lowerCaseConstant2; 160 * static final int lowerCaseConstant3; 161 * static final int lowerCaseConstant4; // will warn here 162 * </pre> 163 * <p> 164 * To configure a filter to avoid any audits on code like: 165 * </p> 166 * <pre> 167 * <module name="SuppressWithNearbyCommentFilter"> 168 * <property name="commentFormat" 169 * value="ALLOW (\\w+) ON PREVIOUS LINE"/> 170 * <property name="checkFormat" value="$1"/> 171 * <property name="influenceFormat" value="-1"/> 172 * </module> 173 * </pre> 174 * <pre> 175 * private int D2; 176 * // ALLOW MemberName ON PREVIOUS LINE 177 * . . . 178 * </pre> 179 * <p> 180 * To configure a filter to allow suppress one or more Checks (separated by "|") 181 * and demand comment no less than 14 symbols: 182 * </p> 183 * <pre> 184 * <module name="SuppressWithNearbyCommentFilter"> 185 * <property name="commentFormat" 186 * value="@cs\.suppress \[(\w+(\|\w+)*)\] \w[-\.'`,:;\w ]{14,}"/> 187 * <property name="checkFormat" value="$1"/> 188 * <property name="influenceFormat" value="1"/> 189 * </module> 190 * </pre> 191 * <pre> 192 * public static final int [] array; // @cs.suppress [ConstantName|NoWhitespaceAfter] A comment here 193 * </pre> 194 * <p> 195 * It is possible to specify an ID of checks, so that it can be leveraged by 196 * the SuppressWithNearbyCommentFilter to skip validations. The following examples show how to skip 197 * validations near code that has comment like {@code // @cs-: <ID/> (reason)}, 198 * where ID is the ID of checks you want to suppress. 199 * </p> 200 * <p> 201 * Examples of Checkstyle checks configuration: 202 * </p> 203 * <pre> 204 * <module name="RegexpSinglelineJava"> 205 * <property name="id" value="ignore"/> 206 * <property name="format" value="^.*@Ignore\s*$"/> 207 * <property name="message" value="@Ignore should have a reason."/> 208 * </module> 209 * 210 * <module name="RegexpSinglelineJava"> 211 * <property name="id" value="systemout"/> 212 * <property name="format" value="^.*System\.(out|err).*$"/> 213 * <property name="message" value="Don't use System.out/err, use SLF4J instead."/> 214 * </module> 215 * </pre> 216 * <p> 217 * Example of SuppressWithNearbyCommentFilter configuration (idFormat which is set to 218 * '$1' points that ID of the checks is in the first group of commentFormat regular expressions): 219 * </p> 220 * <pre> 221 * <module name="SuppressWithNearbyCommentFilter"> 222 * <property name="commentFormat" value="@cs-: (\w+) \(.*\)"/> 223 * <property name="idFormat" value="$1"/> 224 * <property name="influenceFormat" value="0"/> 225 * </module> 226 * </pre> 227 * <pre> 228 * @Ignore // @cs-: ignore (test has not been implemented yet) 229 * @Test 230 * public void testMethod() { } 231 * 232 * public static void foo() { 233 * System.out.println("Debug info."); // @cs-: systemout (should not fail RegexpSinglelineJava) 234 * } 235 * </pre> 236 * <p> 237 * Example of how to configure the check to suppress more than one checks. 238 * The influence format is specified in the second regexp group. 239 * </p> 240 * <pre> 241 * <module name="SuppressWithNearbyCommentFilter"> 242 * <property name="commentFormat" value="@cs-\: ([\w\|]+) influence (\d+)"/> 243 * <property name="checkFormat" value="$1"/> 244 * <property name="influenceFormat" value="$2"/> 245 * </module> 246 * </pre> 247 * <pre> 248 * // @cs-: ClassDataAbstractionCoupling influence 2 249 * // @cs-: MagicNumber influence 4 250 * @Service // no violations from ClassDataAbstractionCoupling here 251 * @Transactional 252 * public class UserService { 253 * private int value = 10022; // no violations from MagicNumber here 254 * } 255 * </pre> 256 * <p> 257 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 258 * </p> 259 * 260 * @since 5.0 261 */ 262public class SuppressWithNearbyCommentFilter 263 extends AutomaticBean 264 implements TreeWalkerFilter { 265 266 /** Format to turn checkstyle reporting off. */ 267 private static final String DEFAULT_COMMENT_FORMAT = 268 "SUPPRESS CHECKSTYLE (\\w+)"; 269 270 /** Default regex for checks that should be suppressed. */ 271 private static final String DEFAULT_CHECK_FORMAT = ".*"; 272 273 /** Default regex for lines that should be suppressed. */ 274 private static final String DEFAULT_INFLUENCE_FORMAT = "0"; 275 276 /** Tagged comments. */ 277 private final List<Tag> tags = new ArrayList<>(); 278 279 /** Control whether to check C style comments ({@code /* ... */}). */ 280 private boolean checkC = true; 281 282 /** Control whether to check C++ style comments ({@code //}). */ 283 // -@cs[AbbreviationAsWordInName] We can not change it as, 284 // check's property is a part of API (used in configurations). 285 private boolean checkCPP = true; 286 287 /** Specify comment pattern to trigger filter to begin suppression. */ 288 private Pattern commentFormat = Pattern.compile(DEFAULT_COMMENT_FORMAT); 289 290 /** Specify check pattern to suppress. */ 291 @XdocsPropertyType(PropertyType.PATTERN) 292 private String checkFormat = DEFAULT_CHECK_FORMAT; 293 294 /** Define message pattern to suppress. */ 295 @XdocsPropertyType(PropertyType.PATTERN) 296 private String messageFormat; 297 298 /** Specify check ID pattern to suppress. */ 299 @XdocsPropertyType(PropertyType.PATTERN) 300 private String idFormat; 301 302 /** 303 * Specify negative/zero/positive value that defines the number of lines 304 * preceding/at/following the suppression comment. 305 */ 306 private String influenceFormat = DEFAULT_INFLUENCE_FORMAT; 307 308 /** 309 * References the current FileContents for this filter. 310 * Since this is a weak reference to the FileContents, the FileContents 311 * can be reclaimed as soon as the strong references in TreeWalker 312 * are reassigned to the next FileContents, at which time filtering for 313 * the current FileContents is finished. 314 */ 315 private WeakReference<FileContents> fileContentsReference = new WeakReference<>(null); 316 317 /** 318 * Setter to specify comment pattern to trigger filter to begin suppression. 319 * 320 * @param pattern a pattern. 321 */ 322 public final void setCommentFormat(Pattern pattern) { 323 commentFormat = pattern; 324 } 325 326 /** 327 * Returns FileContents for this filter. 328 * 329 * @return the FileContents for this filter. 330 */ 331 private FileContents getFileContents() { 332 return fileContentsReference.get(); 333 } 334 335 /** 336 * Set the FileContents for this filter. 337 * 338 * @param fileContents the FileContents for this filter. 339 * @noinspection WeakerAccess 340 * @noinspectionreason WeakerAccess - we avoid 'protected' when possible 341 */ 342 public void setFileContents(FileContents fileContents) { 343 fileContentsReference = new WeakReference<>(fileContents); 344 } 345 346 /** 347 * Setter to specify check pattern to suppress. 348 * 349 * @param format a {@code String} value 350 */ 351 public final void setCheckFormat(String format) { 352 checkFormat = format; 353 } 354 355 /** 356 * Setter to define message pattern to suppress. 357 * 358 * @param format a {@code String} value 359 */ 360 public void setMessageFormat(String format) { 361 messageFormat = format; 362 } 363 364 /** 365 * Setter to specify check ID pattern to suppress. 366 * 367 * @param format a {@code String} value 368 */ 369 public void setIdFormat(String format) { 370 idFormat = format; 371 } 372 373 /** 374 * Setter to specify negative/zero/positive value that defines the number 375 * of lines preceding/at/following the suppression comment. 376 * 377 * @param format a {@code String} value 378 */ 379 public final void setInfluenceFormat(String format) { 380 influenceFormat = format; 381 } 382 383 /** 384 * Setter to control whether to check C++ style comments ({@code //}). 385 * 386 * @param checkCpp {@code true} if C++ comments are checked. 387 */ 388 // -@cs[AbbreviationAsWordInName] We can not change it as, 389 // check's property is a part of API (used in configurations). 390 public void setCheckCPP(boolean checkCpp) { 391 checkCPP = checkCpp; 392 } 393 394 /** 395 * Setter to control whether to check C style comments ({@code /* ... */}). 396 * 397 * @param checkC {@code true} if C comments are checked. 398 */ 399 public void setCheckC(boolean checkC) { 400 this.checkC = checkC; 401 } 402 403 @Override 404 protected void finishLocalSetup() { 405 // No code by default 406 } 407 408 @Override 409 public boolean accept(TreeWalkerAuditEvent event) { 410 boolean accepted = true; 411 412 if (event.getViolation() != null) { 413 // Lazy update. If the first event for the current file, update file 414 // contents and tag suppressions 415 final FileContents currentContents = event.getFileContents(); 416 417 if (getFileContents() != currentContents) { 418 setFileContents(currentContents); 419 tagSuppressions(); 420 } 421 if (matchesTag(event)) { 422 accepted = false; 423 } 424 } 425 return accepted; 426 } 427 428 /** 429 * Whether current event matches any tag from {@link #tags}. 430 * 431 * @param event TreeWalkerAuditEvent to test match on {@link #tags}. 432 * @return true if event matches any tag from {@link #tags}, false otherwise. 433 */ 434 private boolean matchesTag(TreeWalkerAuditEvent event) { 435 boolean result = false; 436 for (final Tag tag : tags) { 437 if (tag.isMatch(event)) { 438 result = true; 439 break; 440 } 441 } 442 return result; 443 } 444 445 /** 446 * Collects all the suppression tags for all comments into a list and 447 * sorts the list. 448 */ 449 private void tagSuppressions() { 450 tags.clear(); 451 final FileContents contents = getFileContents(); 452 if (checkCPP) { 453 tagSuppressions(contents.getSingleLineComments().values()); 454 } 455 if (checkC) { 456 final Collection<List<TextBlock>> cComments = 457 contents.getBlockComments().values(); 458 cComments.forEach(this::tagSuppressions); 459 } 460 } 461 462 /** 463 * Appends the suppressions in a collection of comments to the full 464 * set of suppression tags. 465 * 466 * @param comments the set of comments. 467 */ 468 private void tagSuppressions(Collection<TextBlock> comments) { 469 for (final TextBlock comment : comments) { 470 final int startLineNo = comment.getStartLineNo(); 471 final String[] text = comment.getText(); 472 tagCommentLine(text[0], startLineNo); 473 for (int i = 1; i < text.length; i++) { 474 tagCommentLine(text[i], startLineNo + i); 475 } 476 } 477 } 478 479 /** 480 * Tags a string if it matches the format for turning 481 * checkstyle reporting on or the format for turning reporting off. 482 * 483 * @param text the string to tag. 484 * @param line the line number of text. 485 */ 486 private void tagCommentLine(String text, int line) { 487 final Matcher matcher = commentFormat.matcher(text); 488 if (matcher.find()) { 489 addTag(matcher.group(0), line); 490 } 491 } 492 493 /** 494 * Adds a comment suppression {@code Tag} to the list of all tags. 495 * 496 * @param text the text of the tag. 497 * @param line the line number of the tag. 498 */ 499 private void addTag(String text, int line) { 500 final Tag tag = new Tag(text, line, this); 501 tags.add(tag); 502 } 503 504 /** 505 * A Tag holds a suppression comment and its location. 506 */ 507 private static final class Tag { 508 509 /** The text of the tag. */ 510 private final String text; 511 512 /** The first line where warnings may be suppressed. */ 513 private final int firstLine; 514 515 /** The last line where warnings may be suppressed. */ 516 private final int lastLine; 517 518 /** The parsed check regexp, expanded for the text of this tag. */ 519 private final Pattern tagCheckRegexp; 520 521 /** The parsed message regexp, expanded for the text of this tag. */ 522 private final Pattern tagMessageRegexp; 523 524 /** The parsed check ID regexp, expanded for the text of this tag. */ 525 private final Pattern tagIdRegexp; 526 527 /** 528 * Constructs a tag. 529 * 530 * @param text the text of the suppression. 531 * @param line the line number. 532 * @param filter the {@code SuppressWithNearbyCommentFilter} with the context 533 * @throws IllegalArgumentException if unable to parse expanded text. 534 */ 535 private Tag(String text, int line, SuppressWithNearbyCommentFilter filter) { 536 this.text = text; 537 538 // Expand regexp for check and message 539 // Does not intern Patterns with Utils.getPattern() 540 String format = ""; 541 try { 542 format = CommonUtil.fillTemplateWithStringsByRegexp( 543 filter.checkFormat, text, filter.commentFormat); 544 tagCheckRegexp = Pattern.compile(format); 545 if (filter.messageFormat == null) { 546 tagMessageRegexp = null; 547 } 548 else { 549 format = CommonUtil.fillTemplateWithStringsByRegexp( 550 filter.messageFormat, text, filter.commentFormat); 551 tagMessageRegexp = Pattern.compile(format); 552 } 553 if (filter.idFormat == null) { 554 tagIdRegexp = null; 555 } 556 else { 557 format = CommonUtil.fillTemplateWithStringsByRegexp( 558 filter.idFormat, text, filter.commentFormat); 559 tagIdRegexp = Pattern.compile(format); 560 } 561 format = CommonUtil.fillTemplateWithStringsByRegexp( 562 filter.influenceFormat, text, filter.commentFormat); 563 564 final int influence = parseInfluence(format, filter.influenceFormat, text); 565 566 if (influence >= 1) { 567 firstLine = line; 568 lastLine = line + influence; 569 } 570 else { 571 firstLine = line + influence; 572 lastLine = line; 573 } 574 } 575 catch (final PatternSyntaxException ex) { 576 throw new IllegalArgumentException( 577 "unable to parse expanded comment " + format, ex); 578 } 579 } 580 581 /** 582 * Gets influence from suppress filter influence format param. 583 * 584 * @param format influence format to parse 585 * @param influenceFormat raw influence format 586 * @param text text of the suppression 587 * @return parsed influence 588 * @throws IllegalArgumentException when unable to parse int in format 589 */ 590 private static int parseInfluence(String format, String influenceFormat, String text) { 591 try { 592 return Integer.parseInt(format); 593 } 594 catch (final NumberFormatException ex) { 595 throw new IllegalArgumentException("unable to parse influence from '" + text 596 + "' using " + influenceFormat, ex); 597 } 598 } 599 600 @Override 601 public boolean equals(Object other) { 602 if (this == other) { 603 return true; 604 } 605 if (other == null || getClass() != other.getClass()) { 606 return false; 607 } 608 final Tag tag = (Tag) other; 609 return Objects.equals(firstLine, tag.firstLine) 610 && Objects.equals(lastLine, tag.lastLine) 611 && Objects.equals(text, tag.text) 612 && Objects.equals(tagCheckRegexp, tag.tagCheckRegexp) 613 && Objects.equals(tagMessageRegexp, tag.tagMessageRegexp) 614 && Objects.equals(tagIdRegexp, tag.tagIdRegexp); 615 } 616 617 @Override 618 public int hashCode() { 619 return Objects.hash(text, firstLine, lastLine, tagCheckRegexp, tagMessageRegexp, 620 tagIdRegexp); 621 } 622 623 /** 624 * Determines whether the source of an audit event 625 * matches the text of this tag. 626 * 627 * @param event the {@code TreeWalkerAuditEvent} to check. 628 * @return true if the source of event matches the text of this tag. 629 */ 630 public boolean isMatch(TreeWalkerAuditEvent event) { 631 return isInScopeOfSuppression(event) 632 && isCheckMatch(event) 633 && isIdMatch(event) 634 && isMessageMatch(event); 635 } 636 637 /** 638 * Checks whether the {@link TreeWalkerAuditEvent} is in the scope of the suppression. 639 * 640 * @param event {@link TreeWalkerAuditEvent} instance. 641 * @return true if the {@link TreeWalkerAuditEvent} is in the scope of the suppression. 642 */ 643 private boolean isInScopeOfSuppression(TreeWalkerAuditEvent event) { 644 final int line = event.getLine(); 645 return line >= firstLine && line <= lastLine; 646 } 647 648 /** 649 * Checks whether {@link TreeWalkerAuditEvent} source name matches the check format. 650 * 651 * @param event {@link TreeWalkerAuditEvent} instance. 652 * @return true if the {@link TreeWalkerAuditEvent} source name matches the check format. 653 */ 654 private boolean isCheckMatch(TreeWalkerAuditEvent event) { 655 final Matcher checkMatcher = tagCheckRegexp.matcher(event.getSourceName()); 656 return checkMatcher.find(); 657 } 658 659 /** 660 * Checks whether the {@link TreeWalkerAuditEvent} module ID matches the ID format. 661 * 662 * @param event {@link TreeWalkerAuditEvent} instance. 663 * @return true if the {@link TreeWalkerAuditEvent} module ID matches the ID format. 664 */ 665 private boolean isIdMatch(TreeWalkerAuditEvent event) { 666 boolean match = true; 667 if (tagIdRegexp != null) { 668 if (event.getModuleId() == null) { 669 match = false; 670 } 671 else { 672 final Matcher idMatcher = tagIdRegexp.matcher(event.getModuleId()); 673 match = idMatcher.find(); 674 } 675 } 676 return match; 677 } 678 679 /** 680 * Checks whether the {@link TreeWalkerAuditEvent} message matches the message format. 681 * 682 * @param event {@link TreeWalkerAuditEvent} instance. 683 * @return true if the {@link TreeWalkerAuditEvent} message matches the message format. 684 */ 685 private boolean isMessageMatch(TreeWalkerAuditEvent event) { 686 boolean match = true; 687 if (tagMessageRegexp != null) { 688 final Matcher messageMatcher = tagMessageRegexp.matcher(event.getMessage()); 689 match = messageMatcher.find(); 690 } 691 return match; 692 } 693 694 @Override 695 public String toString() { 696 return "Tag[text='" + text + '\'' 697 + ", firstLine=" + firstLine 698 + ", lastLine=" + lastLine 699 + ", tagCheckRegexp=" + tagCheckRegexp 700 + ", tagMessageRegexp=" + tagMessageRegexp 701 + ", tagIdRegexp=" + tagIdRegexp 702 + ']'; 703 } 704 705 } 706 707}