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

pmd / pmd / 5

15 May 2025 01:19PM UTC coverage: 77.761% (+0.006%) from 77.755%
5

push

github

adangel
Fix #5724: [java] Implicit functional interface FP with sealed interface (#5726)

Merge pull request #5726 from oowekyala:issue5724-implicit-fun-interface

17657 of 23664 branches covered (74.62%)

Branch coverage included in aggregate %.

3 of 3 new or added lines in 1 file covered. (100.0%)

24 existing lines in 4 files now uncovered.

38678 of 48782 relevant lines covered (79.29%)

0.8 hits per line

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

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

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

7
import java.util.stream.Stream;
8

9
import net.sourceforge.pmd.lang.ast.GenericToken;
10
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
11
import net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeNode;
12
import net.sourceforge.pmd.lang.document.Chars;
13
import net.sourceforge.pmd.lang.document.FileLocation;
14
import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils;
15
import net.sourceforge.pmd.reporting.Reportable;
16
import net.sourceforge.pmd.util.IteratorUtil;
17

18
/**
19
 * Wraps a comment token to provide some utilities.
20
 * This is not a node, it's not part of the tree anywhere,
21
 * just convenient.
22
 *
23
 * <p>This class represents any kind of comment. A specialized subclass
24
 * provides more API for Javadoc comments, see {@link JavadocComment}.
25
 */
26
public class JavaComment implements Reportable {
27
    //TODO maybe move part of this into pmd core
28

29
    private final JavaccToken token;
30

31
    JavaComment(JavaccToken t) {
1✔
32
        this.token = t;
1✔
33
    }
1✔
34

35
    @Override
36
    public FileLocation getReportLocation() {
37
        return getToken().getReportLocation();
1✔
38
    }
39

40
    /** The token underlying this comment. */
41
    public final JavaccToken getToken() {
42
        return token;
1✔
43
    }
44

45
    public boolean isSingleLine() {
46
        return token.kind == JavaTokenKinds.SINGLE_LINE_COMMENT;
1!
47
    }
48

49
    public boolean hasJavadocContent() {
50
        return token.kind == JavaTokenKinds.FORMAL_COMMENT || JavaAstUtils.isMarkdownComment(token);
1✔
51
    }
52

53
    /** Returns the full text of the comment. */
54
    public Chars getText() {
55
        return getToken().getImageCs();
1✔
56
    }
57

58
    /**
59
     * Returns true if the given token has the kind
60
     * of a comment token (there are three such kinds).
61
     */
62
    public static boolean isComment(JavaccToken token) {
63
        return JavaAstUtils.isComment(token);
1✔
64
    }
65

66
    /**
67
     * Removes the leading comment marker (like {@code *}) of each line
68
     * of the comment as well as the start marker ({@code //}, {@code /*}, {@code /**} or {@code ///}
69
     * and the end markers (<code>&#x2a;/</code>).
70
     *
71
     * <p>Empty lines are removed.
72
     *
73
     * @return List of lines of the comments
74
     */
75
    public Iterable<Chars> getFilteredLines() {
76
        return getFilteredLines(false);
1✔
77
    }
78

79
    public Iterable<Chars> getFilteredLines(boolean preserveEmptyLines) {
80
        if (preserveEmptyLines) {
1✔
81
            return () -> IteratorUtil.map(getText().lines().iterator(), JavaComment::removeCommentMarkup);
1✔
82
        } else {
83
            return () -> IteratorUtil.mapNotNull(
1✔
84
                getText().lines().iterator(),
1✔
85
                line -> {
86
                    line = removeCommentMarkup(line);
1✔
87
                    return line.isEmpty() ? null : line;
1✔
88
                }
89
            );
90
        }
91
    }
92

93
    /**
94
     * True if this is a comment delimiter or an asterisk. This
95
     * tests the whole parameter and not a prefix/suffix.
96
     */
97
    @SuppressWarnings("PMD.LiteralsFirstInComparisons") // a fp
98
    public static boolean isMarkupWord(Chars word) {
99
        return word.length() <= 3
×
100
            && (word.contentEquals("*")
×
101
            || word.contentEquals("//")
×
102
            || word.contentEquals("///")
×
103
            || word.contentEquals("/*")
×
104
            || word.contentEquals("*/")
×
105
            || word.contentEquals("/**"));
×
106
    }
107

108
    /**
109
     * Trim the start of the provided line to remove a comment
110
     * markup opener ({@code //, ///, /*, /**, *}) or closer <code>&#x2a;/</code>.
111
     */
112
    public static Chars removeCommentMarkup(Chars line) {
113
        line = line.trim().removeSuffix("*/");
1✔
114
        int subseqFrom = 0;
1✔
115
        if (line.startsWith('/', 0)) {
1✔
116
            if (line.startsWith("**", 1)
1✔
117
                || line.startsWith("//", 1)) {
1✔
118
                subseqFrom = 3;
1✔
119
            } else if (line.startsWith('/', 1)
1✔
120
                || line.startsWith('*', 1)) {
1!
121
                subseqFrom = 2;
1✔
122
            }
123
        } else if (line.startsWith('*', 0)) {
1✔
124
            subseqFrom = 1;
1✔
125
        }
126
        return line.subSequence(subseqFrom, line.length()).trim();
1✔
127
    }
128

129
    private static Stream<JavaccToken> getSpecialTokensIn(JjtreeNode<?> node) {
130
        return GenericToken.streamRange(node.getFirstToken(), node.getLastToken())
1✔
131
                           .flatMap(it -> IteratorUtil.toStream(GenericToken.previousSpecials(it).iterator()));
1✔
132
    }
133

134
    public static Stream<JavaComment> getLeadingComments(JavaNode node) {
135
        Stream<JavaccToken> specialTokens = getSpecialTokensIn(node);
1✔
136
        
137
        if (node instanceof ModifierOwner && !(node instanceof ASTConstructorDeclaration)) {
1✔
138
            node = ((ModifierOwner) node).getModifiers();
1✔
139
            specialTokens = getSpecialTokensIn(node);
1✔
140
            
141
            // if this was a non-implicit empty modifier node, we should also consider comments immediately after
142
            if (!node.getFirstToken().isImplicit()) {
1✔
143
                specialTokens = Stream.concat(specialTokens, getSpecialTokensIn(node.getNextSibling()));
1✔
144
            }
145
        }
146
        
147
        return specialTokens.filter(JavaComment::isComment)
1✔
148
                                         .map(JavaComment::toComment);
1✔
149
    }
150

151
    private static JavaComment toComment(JavaccToken tok) {
152
        switch (tok.kind) {
1!
153
        case JavaTokenKinds.FORMAL_COMMENT:
154
            return new JavadocComment(tok);
1✔
155
        case JavaTokenKinds.MULTI_LINE_COMMENT:
156
        case JavaTokenKinds.SINGLE_LINE_COMMENT:
157
            return new JavaComment(tok);
1✔
158
        default:
UNCOV
159
            throw new IllegalArgumentException("Token is not a comment: " + tok);
×
160
        }
161
    }
162

163
    @Override
164
    public boolean equals(Object o) {
165
        if (this == o) {
1!
UNCOV
166
            return true;
×
167
        }
168
        if (!(o instanceof JavaComment)) {
1!
UNCOV
169
            return false;
×
170
        }
171
        JavaComment that = (JavaComment) o;
1✔
172
        return token.equals(that.token);
1✔
173
    }
174

175
    @Override
176
    public int hashCode() {
UNCOV
177
        return token.hashCode();
×
178
    }
179
}
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