1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3 * SPDX-License-Identifier: MIT
4 */
5 package com.qulice.checkstyle;
6
7 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
8 import java.util.Collection;
9
10 /**
11 * One {@code @checkstyle} suppression comment and the range it covers.
12 *
13 * <p>A comment like {@code @checkstyle TypeName (N lines)} tells the
14 * suppression filters of {@code checks.xml} to drop violations of
15 * {@code TypeName} on the lines it influences. The same holds for a pair
16 * of {@code disable} and {@code enable} comments, whose range runs from
17 * one to the other. A tag that influences
18 * no violation of its check suppresses nothing and lingers as a lie about
19 * the code, which is what {@link Suppressions} finds with the help of this
20 * class.</p>
21 *
22 * @since 1.0
23 */
24 final class SuppressionTag {
25
26 /**
27 * Name of the check that the suppression targets.
28 */
29 private final String check;
30
31 /**
32 * First line of the range the suppression influences, which is also
33 * the line of the comment where a violation about it is reported.
34 */
35 private final int first;
36
37 /**
38 * Last line of the range the suppression influences.
39 */
40 private final int last;
41
42 /**
43 * Constructor.
44 *
45 * @param check Name of the suppressed check
46 * @param first First line of the influence range, and of the comment
47 * @param last Last line of the influence range
48 */
49 SuppressionTag(final String check, final int first, final int last) {
50 this.check = check;
51 this.first = first;
52 this.last = last;
53 }
54
55 /**
56 * Name of the suppressed check.
57 *
58 * @return The name
59 */
60 String check() {
61 return this.check;
62 }
63
64 /**
65 * Line of the comment, where a violation about it belongs.
66 *
67 * @return Line number
68 */
69 int line() {
70 return this.first;
71 }
72
73 /**
74 * Does this suppression influence none of these events?
75 *
76 * <p>The filters match the captured name against the fully qualified
77 * class name of the check, which the name is a substring of, so the
78 * same test decides here whether an event belongs to the suppressed
79 * check.</p>
80 *
81 * @param events Events collected with the nearby filters removed
82 * @return True if no event of the check falls in the influence range
83 */
84 boolean unused(final Collection<AuditEvent> events) {
85 return events.stream().noneMatch(this::covers);
86 }
87
88 private boolean covers(final AuditEvent event) {
89 return event.getSourceName().contains(this.check)
90 && event.getLine() >= this.first
91 && event.getLine() <= this.last;
92 }
93 }