• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 23

30 May 2025 04:25PM UTC coverage: 78.377% (-0.2%) from 78.601%
23

push

github

adangel
[core] Add rule to report unnecessary suppression comments/annotations (#5609)

Merge pull request #5609 from oowekyala:new-rule-UnnecessarySuppression

17712 of 23434 branches covered (75.58%)

Branch coverage included in aggregate %.

159 of 328 new or added lines in 22 files covered. (48.48%)

36 existing lines in 4 files now uncovered.

38902 of 48799 relevant lines covered (79.72%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.0
/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstInfo.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.ast;
6

7
import java.util.Collection;
8
import java.util.Collections;
9
import java.util.HashMap;
10
import java.util.HashSet;
11
import java.util.Map;
12
import java.util.Set;
13

14
import org.checkerframework.checker.nullness.qual.NonNull;
15
import org.checkerframework.checker.nullness.qual.Nullable;
16

17
import net.sourceforge.pmd.PMDConfiguration;
18
import net.sourceforge.pmd.lang.LanguageProcessor;
19
import net.sourceforge.pmd.lang.LanguageProcessorRegistry;
20
import net.sourceforge.pmd.lang.ast.Parser.ParserTask;
21
import net.sourceforge.pmd.lang.document.FileLocation;
22
import net.sourceforge.pmd.lang.document.TextDocument;
23
import net.sourceforge.pmd.reporting.Reportable;
24
import net.sourceforge.pmd.reporting.ViolationSuppressor;
25
import net.sourceforge.pmd.reporting.ViolationSuppressor.SuppressionCommentWrapper;
26
import net.sourceforge.pmd.util.AssertionUtil;
27
import net.sourceforge.pmd.util.CollectionUtil;
28
import net.sourceforge.pmd.util.DataMap;
29
import net.sourceforge.pmd.util.DataMap.DataKey;
30

31
/**
32
 * The output of {@link Parser#parse(ParserTask)}.
33
 *
34
 * @param <T> Type of root nodes
35
 */
36
public final class AstInfo<T extends RootNode> {
37

38
    private final TextDocument textDocument;
39
    private final T rootNode;
40
    private final LanguageProcessorRegistry lpReg;
41
    private final Map<Integer, SuppressionCommentWrapper> suppressionComments;
42
    private final DataMap<DataKey<?, ?>> userMap = DataMap.newDataMap();
1✔
43

44

45
    public AstInfo(ParserTask task, T rootNode) {
46
        this(task.getTextDocument(), rootNode, task.getLpRegistry(), Collections.emptyMap());
1✔
47
    }
1✔
48

49
    private AstInfo(TextDocument textDocument,
50
                    T rootNode,
51
                    LanguageProcessorRegistry lpReg,
52
                    Map<Integer, SuppressionCommentWrapper> suppressionComments) {
1✔
53
        this.textDocument = AssertionUtil.requireParamNotNull("text document", textDocument);
1✔
54
        this.rootNode = AssertionUtil.requireParamNotNull("root node", rootNode);
1✔
55
        this.lpReg = lpReg;
1✔
56
        this.suppressionComments = AssertionUtil.requireParamNotNull("suppress map", suppressionComments);
1✔
57
    }
1✔
58

59

60
    public T getRootNode() {
61
        return rootNode;
×
62
    }
63

64
    /**
65
     * Returns the text document that was parsed.
66
     * This has info like language version, etc.
67
     */
68
    public @NonNull TextDocument getTextDocument() {
69
        return textDocument;
1✔
70
    }
71

72
    /**
73
     * Returns the language processor that parsed the tree.
74
     */
75
    public LanguageProcessor getLanguageProcessor() {
76
        return lpReg.getProcessor(textDocument.getLanguageVersion().getLanguage());
1✔
77
    }
78

79
    /**
80
     * Returns the map of line numbers to suppression / review comments.
81
     * Only single line comments are considered, that start with the configured
82
     * "suppressMarker", which by default is "PMD". The text after the
83
     * suppressMarker is used as a "review comment" and included in this map.
84
     *
85
     * <p>This map is later used to determine, if a violation is being suppressed.
86
     * It is suppressed, if the line of the violation is contained in this suppress map.
87
     *
88
     * @return map of the suppressed lines with the corresponding review comments.
89
     * @deprecated Since 7.14.0. Use {@link #getAllSuppressionComments()} or {@link #getSuppressionComment(int)}
90
     */
91
    @Deprecated
92
    public Map<Integer, String> getSuppressionComments() {
NEW
93
        return CollectionUtil.mapView(suppressionComments, ViolationSuppressor.SuppressionCommentWrapper::getUserMessage);
×
94
    }
95

96

97
    /**
98
     * Return the suppresson comment at the given line, or null if there is none.
99
     *
100
     * @since 7.14.0
101
     */
102
    public @Nullable SuppressionCommentWrapper getSuppressionComment(int lineNumber) {
103
        return suppressionComments.get(lineNumber);
1✔
104
    }
105

106
    /**
107
     * Return all suppression comments in the file.
108
     * Only single line comments are considered, that start with the configured
109
     * "suppress marker", which by default is {@link PMDConfiguration#DEFAULT_SUPPRESS_MARKER}.
110
     * The text after the suppress marker is used as a "review comment" and included in this map.
111
     *
112
     * @since 7.14.0
113
     */
114
    public Collection<SuppressionCommentWrapper> getAllSuppressionComments() {
NEW
115
        return Collections.unmodifiableCollection(suppressionComments.values());
×
116
    }
117

118
    /**
119
     * Returns a data map used to store additional information on this ast info.
120
     *
121
     * @return The user data map of this node
122
     *
123
     * @since 7.14.0
124
     */
125
    public DataMap<DataKey<?, ?>> getUserMap() {
126
        return userMap;
1✔
127
    }
128

129

130
    /**
131
     * @deprecated Since 7.14.0. Use {@link #withSuppressionComments(Collection)}
132
     */
133
    @Deprecated
134
    public AstInfo<T> withSuppressMap(Map<Integer, String> map) {
NEW
135
        Set<SuppressionCommentWrapper> comments = new HashSet<>();
×
NEW
136
        for (Map.Entry<Integer, String> entry : map.entrySet()) {
×
NEW
137
            String comment = entry.getValue();
×
NEW
138
            int line = entry.getKey();
×
NEW
139
            comments.add(new SuppressionCommentWrapper() {
×
140
                @Override
141
                public String getUserMessage() {
NEW
142
                    return comment;
×
143
                }
144

145
                @Override
146
                public Reportable getLocation() {
NEW
147
                    return () -> FileLocation.caret(textDocument.getFileId(), line, 1);
×
148
                }
149
            });
NEW
150
        }
×
NEW
151
        return withSuppressionComments(comments);
×
152
    }
153

154

155
    /**
156
     * @since 7.14.0
157
     */
158
    public AstInfo<T> withSuppressionComments(Collection<? extends SuppressionCommentWrapper> suppressionComments) {
159
        Map<Integer, SuppressionCommentWrapper> suppressMap = new HashMap<>(suppressionComments.size());
1✔
160
        for (SuppressionCommentWrapper comment : suppressionComments) {
1✔
161
            suppressMap.put(comment.getLocation().getReportLocation().getStartLine(), comment);
1✔
162
        }
1✔
163
        return new AstInfo<>(
1✔
164
            textDocument,
165
            rootNode,
166
            lpReg,
167
            Collections.unmodifiableMap(suppressMap)
1✔
168
        );
169
    }
170

171
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc