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

pmd / pmd / 4502

13 Mar 2025 12:14PM UTC coverage: 83.089% (+3.4%) from 79.659%
4502

push

github

adangel
[java] Fix crash when parsing class for anonymous class (#5588)

Merge pull request #5588 from oowekyala:fix-anon-class-loading

1912 of 2411 branches covered (79.3%)

Branch coverage included in aggregate %.

29 of 33 new or added lines in 2 files covered. (87.88%)

30 existing lines in 6 files now uncovered.

4559 of 5377 relevant lines covered (84.79%)

14.17 hits per line

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

67.44
/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/javacc/CharStream.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.impl.javacc;
6

7

8
import java.io.EOFException;
9

10
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument.TokenDocumentBehavior;
11
import net.sourceforge.pmd.lang.document.Chars;
12
import net.sourceforge.pmd.lang.document.FileLocation;
13
import net.sourceforge.pmd.lang.document.TextDocument;
14
import net.sourceforge.pmd.lang.document.TextRegion;
15

16
/**
17
 * PMD flavour of character streams used by JavaCC parsers.
18
 */
19
public final class CharStream {
20

21
    // This is thrown when the end of the stream is reached. Callers catch it and do not care about stack trace,
22
    // so we reuse one instance to avoid creating one exception each time.
23
    private static final EOFException EOF_EXCEPTION = new EOFException();
2✔
24

25
    private final JavaccTokenDocument tokenDoc;
26
    private final TextDocument textDoc;
27
    private final Chars chars;
28
    private final boolean useMarkSuffix;
29
    private int curOffset;
30
    private int markOffset;
31

32
    private CharStream(JavaccTokenDocument tokenDoc) {
2✔
33
        this.tokenDoc = tokenDoc;
2✔
34
        this.textDoc = tokenDoc.getTextDocument();
2✔
35
        this.chars = textDoc.getText();
2✔
36
        this.useMarkSuffix = tokenDoc.useMarkSuffix();
2✔
37
    }
2✔
38

39
    /**
40
     * Create a new char stream for the given document. This may create
41
     * a new {@link TextDocument} view over the original, which reflects
42
     * its character escapes.
43
     */
44
    public static CharStream create(TextDocument doc, TokenDocumentBehavior behavior) throws MalformedSourceException {
45
        TextDocument translated = behavior.translate(doc);
2✔
46
        return new CharStream(new JavaccTokenDocument(translated, behavior));
2✔
47
    }
48

49
    /**
50
     * Create a new char stream for the given document with the default token
51
     * document behavior. This may create a new {@link TextDocument} view
52
     * over the original, which reflects its character escapes.
53
     */
54
    public static CharStream create(TextDocument doc) throws MalformedSourceException {
UNCOV
55
        return create(doc, TokenDocumentBehavior.DEFAULT);
×
56
    }
57

58
    /**
59
     * Returns the next character from the input. After a {@link #backup(int)},
60
     * some of the already read chars must be spit out again.
61
     *
62
     * @return The next character
63
     *
64
     * @throws EOFException Upon EOF
65
     */
66
    public char readChar() throws EOFException {
67
        if (curOffset == chars.length()) {
2✔
68
            throw EOF_EXCEPTION;
2✔
69
        }
70
        return chars.charAt(curOffset++);
2✔
71
    }
72

73

74
    /**
75
     * Calls {@link #readChar()} and returns its value, marking its position
76
     * as the beginning of the next token. All characters must remain in
77
     * the buffer between two successive calls to this method to implement
78
     * backup correctly.
79
     */
80
    public char markTokenStart() throws EOFException {
81
        markOffset = curOffset;
2✔
82
        return readChar();
2✔
83
    }
84

85

86
    /**
87
     * Returns a string made up of characters from the token mark up to
88
     * to the current buffer position.
89
     */
90
    public String getTokenImage() {
91
        return getTokenImageCs().toString();
2✔
92
    }
93

94
    /**
95
     * Returns a string made up of characters from the token mark up to
96
     * to the current buffer position.
97
     */
98
    public Chars getTokenImageCs() {
99
        assert markOffset >= 0;
2!
100
        return chars.slice(markOffset, markLen());
2✔
101
    }
102

103
    private int markLen() {
104
        return curOffset - markOffset;
2✔
105
    }
106

107

108
    /**
109
     * Appends the suffix of length 'len' of the current token to the given
110
     * string builder. This is used to build up the matched string
111
     * for use in actions in the case of MORE.
112
     *
113
     * @param len Length of the returned array
114
     *
115
     * @throws IndexOutOfBoundsException If len is greater than the length of the current token
116
     */
117
    public void appendSuffix(StringBuilder sb, int len) {
118
        if (useMarkSuffix) {
×
UNCOV
119
            assert len <= markLen() : "Suffix is greater than the mark length? " + len + " > " + markLen();
×
UNCOV
120
            chars.appendChars(sb, curOffset - len, len);
×
121
        } // otherwise dead code, kept because Javacc's argument expressions do side effects
UNCOV
122
    }
×
123

124

125
    /**
126
     * Pushes a given number of already read chars into the buffer.
127
     * Subsequent calls to {@link #readChar()} will read those characters
128
     * before proceeding to read the underlying char stream.
129
     *
130
     * <p>A lexer calls this method if it has already read some characters,
131
     * but cannot use them to match a (longer) token. So, they will
132
     * be used again as the prefix of the next token.
133
     *
134
     * @throws AssertionError If the requested amount is greater than the
135
     *                        length of the mark
136
     */
137
    public void backup(int amount) {
138
        if (amount > markLen()) {
2✔
139
            throw new IllegalArgumentException();
2✔
140
        }
141
        curOffset -= amount;
2✔
142
    }
2✔
143

144
    /**
145
     * Returns the column number of the last character for the current token.
146
     * This is only used for parse exceptions and is very inefficient.
147
     */
148
    public int getEndColumn() {
UNCOV
149
        return endLocation().getEndColumn();
×
150
    }
151

152

153
    /**
154
     * Returns the line number of the last character for current token.
155
     * This is only used for parse exceptions and is very inefficient.
156
     */
157
    public int getEndLine() {
UNCOV
158
        return endLocation().getEndLine();
×
159
    }
160

161

162
    private FileLocation endLocation() {
UNCOV
163
        return textDoc.toLocation(TextRegion.caretAt(getEndOffset()));
×
164
    }
165

166

167
    /** Returns the start offset of the current token (in the translated source), inclusive. */
168
    public int getStartOffset() {
169
        return markOffset;
2✔
170
    }
171

172

173
    /** Returns the end offset of the current token (in the translated source), exclusive. */
174
    public int getEndOffset() {
175
        return curOffset;
2✔
176
    }
177

178

179
    /**
180
     * Returns the token document for the tokens being built. Having it
181
     * here is the most convenient place for the time being.
182
     */
183
    public JavaccTokenDocument getTokenDocument() {
UNCOV
184
        return tokenDoc;
×
185
    }
186

187
}
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