Wed, 21 Sep 2011 21:56:53 -0700
7092965: javac should not close processorClassLoader before end of compilation
Reviewed-by: darcy
1 /*
2 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.javac.parser;
28 import java.nio.*;
30 import com.sun.tools.javac.util.*;
31 import static com.sun.tools.javac.util.LayoutCharacters.*;
33 /** An extension to the base lexical analyzer that captures
34 * and processes the contents of doc comments. It does so by
35 * translating Unicode escape sequences and by stripping the
36 * leading whitespace and starts from each line of the comment.
37 *
38 * <p><b>This is NOT part of any supported API.
39 * If you write code that depends on this, you do so at your own risk.
40 * This code and its internal interfaces are subject to change or
41 * deletion without notice.</b>
42 */
43 public class DocCommentScanner extends Scanner {
45 /** Create a scanner from the input buffer. buffer must implement
46 * array() and compact(), and remaining() must be less than limit().
47 */
48 protected DocCommentScanner(ScannerFactory fac, CharBuffer buffer) {
49 super(fac, buffer);
50 }
52 /** Create a scanner from the input array. The array must have at
53 * least a single character of extra space.
54 */
55 protected DocCommentScanner(ScannerFactory fac, char[] input, int inputLength) {
56 super(fac, input, inputLength);
57 }
59 /** Starting position of the comment in original source
60 */
61 private int pos;
63 /** The comment input buffer, index of next chacter to be read,
64 * index of one past last character in buffer.
65 */
66 private char[] buf;
67 private int bp;
68 private int buflen;
70 /** The current character.
71 */
72 private char ch;
74 /** The column number position of the current character.
75 */
76 private int col;
78 /** The buffer index of the last converted Unicode character
79 */
80 private int unicodeConversionBp = 0;
82 /**
83 * Buffer for doc comment.
84 */
85 private char[] docCommentBuffer = new char[1024];
87 /**
88 * Number of characters in doc comment buffer.
89 */
90 private int docCommentCount;
92 /**
93 * Translated and stripped contents of doc comment
94 */
95 private String docComment = null;
98 /** Unconditionally expand the comment buffer.
99 */
100 private void expandCommentBuffer() {
101 char[] newBuffer = new char[docCommentBuffer.length * 2];
102 System.arraycopy(docCommentBuffer, 0, newBuffer,
103 0, docCommentBuffer.length);
104 docCommentBuffer = newBuffer;
105 }
107 /** Convert an ASCII digit from its base (8, 10, or 16)
108 * to its value.
109 */
110 private int digit(int base) {
111 char c = ch;
112 int result = Character.digit(c, base);
113 if (result >= 0 && c > 0x7f) {
114 ch = "0123456789abcdef".charAt(result);
115 }
116 return result;
117 }
119 /** Convert Unicode escape; bp points to initial '\' character
120 * (Spec 3.3).
121 */
122 private void convertUnicode() {
123 if (ch == '\\' && unicodeConversionBp != bp) {
124 bp++; ch = buf[bp]; col++;
125 if (ch == 'u') {
126 do {
127 bp++; ch = buf[bp]; col++;
128 } while (ch == 'u');
129 int limit = bp + 3;
130 if (limit < buflen) {
131 int d = digit(16);
132 int code = d;
133 while (bp < limit && d >= 0) {
134 bp++; ch = buf[bp]; col++;
135 d = digit(16);
136 code = (code << 4) + d;
137 }
138 if (d >= 0) {
139 ch = (char)code;
140 unicodeConversionBp = bp;
141 return;
142 }
143 }
144 // "illegal.Unicode.esc", reported by base scanner
145 } else {
146 bp--;
147 ch = '\\';
148 col--;
149 }
150 }
151 }
154 /** Read next character.
155 */
156 private void scanChar() {
157 bp++;
158 ch = buf[bp];
159 switch (ch) {
160 case '\r': // return
161 col = 0;
162 break;
163 case '\n': // newline
164 if (bp == 0 || buf[bp-1] != '\r') {
165 col = 0;
166 }
167 break;
168 case '\t': // tab
169 col = (col / TabInc * TabInc) + TabInc;
170 break;
171 case '\\': // possible Unicode
172 col++;
173 convertUnicode();
174 break;
175 default:
176 col++;
177 break;
178 }
179 }
181 /**
182 * Read next character in doc comment, skipping over double '\' characters.
183 * If a double '\' is skipped, put in the buffer and update buffer count.
184 */
185 private void scanDocCommentChar() {
186 scanChar();
187 if (ch == '\\') {
188 if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
189 if (docCommentCount == docCommentBuffer.length)
190 expandCommentBuffer();
191 docCommentBuffer[docCommentCount++] = ch;
192 bp++; col++;
193 } else {
194 convertUnicode();
195 }
196 }
197 }
199 /* Reset doc comment before reading each new token
200 */
201 public void nextToken() {
202 docComment = null;
203 super.nextToken();
204 }
206 /**
207 * Returns the documentation string of the current token.
208 */
209 public String docComment() {
210 return docComment;
211 }
213 /**
214 * Process a doc comment and make the string content available.
215 * Strips leading whitespace and stars.
216 */
217 @SuppressWarnings("fallthrough")
218 protected void processComment(CommentStyle style) {
219 if (style != CommentStyle.JAVADOC) {
220 return;
221 }
223 pos = pos();
224 buf = getRawCharacters(pos, endPos());
225 buflen = buf.length;
226 bp = 0;
227 col = 0;
229 docCommentCount = 0;
231 boolean firstLine = true;
233 // Skip over first slash
234 scanDocCommentChar();
235 // Skip over first star
236 scanDocCommentChar();
238 // consume any number of stars
239 while (bp < buflen && ch == '*') {
240 scanDocCommentChar();
241 }
242 // is the comment in the form /**/, /***/, /****/, etc. ?
243 if (bp < buflen && ch == '/') {
244 docComment = "";
245 return;
246 }
248 // skip a newline on the first line of the comment.
249 if (bp < buflen) {
250 if (ch == LF) {
251 scanDocCommentChar();
252 firstLine = false;
253 } else if (ch == CR) {
254 scanDocCommentChar();
255 if (ch == LF) {
256 scanDocCommentChar();
257 firstLine = false;
258 }
259 }
260 }
262 outerLoop:
264 // The outerLoop processes the doc comment, looping once
265 // for each line. For each line, it first strips off
266 // whitespace, then it consumes any stars, then it
267 // puts the rest of the line into our buffer.
268 while (bp < buflen) {
270 // The wsLoop consumes whitespace from the beginning
271 // of each line.
272 wsLoop:
274 while (bp < buflen) {
275 switch(ch) {
276 case ' ':
277 scanDocCommentChar();
278 break;
279 case '\t':
280 col = ((col - 1) / TabInc * TabInc) + TabInc;
281 scanDocCommentChar();
282 break;
283 case FF:
284 col = 0;
285 scanDocCommentChar();
286 break;
287 // Treat newline at beginning of line (blank line, no star)
288 // as comment text. Old Javadoc compatibility requires this.
289 /*---------------------------------*
290 case CR: // (Spec 3.4)
291 scanDocCommentChar();
292 if (ch == LF) {
293 col = 0;
294 scanDocCommentChar();
295 }
296 break;
297 case LF: // (Spec 3.4)
298 scanDocCommentChar();
299 break;
300 *---------------------------------*/
301 default:
302 // we've seen something that isn't whitespace;
303 // jump out.
304 break wsLoop;
305 }
306 }
308 // Are there stars here? If so, consume them all
309 // and check for the end of comment.
310 if (ch == '*') {
311 // skip all of the stars
312 do {
313 scanDocCommentChar();
314 } while (ch == '*');
316 // check for the closing slash.
317 if (ch == '/') {
318 // We're done with the doc comment
319 // scanChar() and breakout.
320 break outerLoop;
321 }
322 } else if (! firstLine) {
323 //The current line does not begin with a '*' so we will indent it.
324 for (int i = 1; i < col; i++) {
325 if (docCommentCount == docCommentBuffer.length)
326 expandCommentBuffer();
327 docCommentBuffer[docCommentCount++] = ' ';
328 }
329 }
331 // The textLoop processes the rest of the characters
332 // on the line, adding them to our buffer.
333 textLoop:
334 while (bp < buflen) {
335 switch (ch) {
336 case '*':
337 // Is this just a star? Or is this the
338 // end of a comment?
339 scanDocCommentChar();
340 if (ch == '/') {
341 // This is the end of the comment,
342 // set ch and return our buffer.
343 break outerLoop;
344 }
345 // This is just an ordinary star. Add it to
346 // the buffer.
347 if (docCommentCount == docCommentBuffer.length)
348 expandCommentBuffer();
349 docCommentBuffer[docCommentCount++] = '*';
350 break;
351 case ' ':
352 case '\t':
353 if (docCommentCount == docCommentBuffer.length)
354 expandCommentBuffer();
355 docCommentBuffer[docCommentCount++] = ch;
356 scanDocCommentChar();
357 break;
358 case FF:
359 scanDocCommentChar();
360 break textLoop; // treat as end of line
361 case CR: // (Spec 3.4)
362 scanDocCommentChar();
363 if (ch != LF) {
364 // Canonicalize CR-only line terminator to LF
365 if (docCommentCount == docCommentBuffer.length)
366 expandCommentBuffer();
367 docCommentBuffer[docCommentCount++] = (char)LF;
368 break textLoop;
369 }
370 /* fall through to LF case */
371 case LF: // (Spec 3.4)
372 // We've seen a newline. Add it to our
373 // buffer and break out of this loop,
374 // starting fresh on a new line.
375 if (docCommentCount == docCommentBuffer.length)
376 expandCommentBuffer();
377 docCommentBuffer[docCommentCount++] = ch;
378 scanDocCommentChar();
379 break textLoop;
380 default:
381 // Add the character to our buffer.
382 if (docCommentCount == docCommentBuffer.length)
383 expandCommentBuffer();
384 docCommentBuffer[docCommentCount++] = ch;
385 scanDocCommentChar();
386 }
387 } // end textLoop
388 firstLine = false;
389 } // end outerLoop
391 if (docCommentCount > 0) {
392 int i = docCommentCount - 1;
393 trailLoop:
394 while (i > -1) {
395 switch (docCommentBuffer[i]) {
396 case '*':
397 i--;
398 break;
399 default:
400 break trailLoop;
401 }
402 }
403 docCommentCount = i + 1;
405 // Store the text of the doc comment
406 docComment = new String(docCommentBuffer, 0 , docCommentCount);
407 } else {
408 docComment = "";
409 }
410 }
412 /** Build a map for translating between line numbers and
413 * positions in the input.
414 *
415 * @return a LineMap */
416 public Position.LineMap getLineMap() {
417 char[] buf = getRawCharacters();
418 return Position.makeLineMap(buf, buf.length, true);
419 }
420 }