Fri, 04 Nov 2011 12:36:40 +0000
7104201: Refactor DocCommentScanner
Summary: Add new Comment helper class to parse contents of comments in source code
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Tue Nov 01 15:49:45 2011 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Fri Nov 04 12:36:40 2011 +0000 1.3 @@ -25,10 +25,11 @@ 1.4 1.5 package com.sun.tools.javac.parser; 1.6 1.7 -import java.nio.CharBuffer; 1.8 import com.sun.tools.javac.code.Source; 1.9 +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; 1.10 import com.sun.tools.javac.util.*; 1.11 1.12 +import java.nio.CharBuffer; 1.13 1.14 import static com.sun.tools.javac.parser.Tokens.*; 1.15 import static com.sun.tools.javac.util.LayoutCharacters.*; 1.16 @@ -65,9 +66,6 @@ 1.17 */ 1.18 private final Log log; 1.19 1.20 - /** The name table. */ 1.21 - private final Names names; 1.22 - 1.23 /** The token factory. */ 1.24 private final Tokens tokens; 1.25 1.26 @@ -87,17 +85,11 @@ 1.27 */ 1.28 protected int errPos = Position.NOPOS; 1.29 1.30 - /** Has a @deprecated been encountered in last doc comment? 1.31 - * this needs to be reset by client. 1.32 + /** The Unicode reader (low-level stream reader). 1.33 */ 1.34 - protected boolean deprecatedFlag = false; 1.35 + protected UnicodeReader reader; 1.36 1.37 - /** A character buffer for saved chars. 1.38 - */ 1.39 - protected char[] sbuf = new char[128]; 1.40 - protected int sp; 1.41 - 1.42 - protected UnicodeReader reader; 1.43 + protected ScannerFactory fac; 1.44 1.45 private static final boolean hexFloatsWork = hexFloatsWork(); 1.46 private static boolean hexFloatsWork() { 1.47 @@ -129,14 +121,14 @@ 1.48 } 1.49 1.50 protected JavaTokenizer(ScannerFactory fac, UnicodeReader reader) { 1.51 - log = fac.log; 1.52 - names = fac.names; 1.53 - tokens = fac.tokens; 1.54 - source = fac.source; 1.55 + this.fac = fac; 1.56 + this.log = fac.log; 1.57 + this.tokens = fac.tokens; 1.58 + this.source = fac.source; 1.59 this.reader = reader; 1.60 - allowBinaryLiterals = source.allowBinaryLiterals(); 1.61 - allowHexFloats = source.allowHexFloats(); 1.62 - allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); 1.63 + this.allowBinaryLiterals = source.allowBinaryLiterals(); 1.64 + this.allowHexFloats = source.allowHexFloats(); 1.65 + this.allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); 1.66 } 1.67 1.68 /** Report an error at the given position using the provided arguments. 1.69 @@ -147,38 +139,13 @@ 1.70 errPos = pos; 1.71 } 1.72 1.73 - /** Read next character in comment, skipping over double '\' characters. 1.74 - */ 1.75 - protected void scanCommentChar() { 1.76 - reader.scanChar(); 1.77 - if (reader.ch == '\\') { 1.78 - if (reader.peekChar() == '\\' && !reader.isUnicode()) { 1.79 - reader.skipChar(); 1.80 - } else { 1.81 - reader.convertUnicode(); 1.82 - } 1.83 - } 1.84 - } 1.85 - 1.86 - /** Append a character to sbuf. 1.87 - */ 1.88 - private void putChar(char ch) { 1.89 - if (sp == sbuf.length) { 1.90 - char[] newsbuf = new char[sbuf.length * 2]; 1.91 - System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length); 1.92 - sbuf = newsbuf; 1.93 - } 1.94 - sbuf[sp++] = ch; 1.95 - } 1.96 - 1.97 /** Read next character in character or string literal and copy into sbuf. 1.98 */ 1.99 private void scanLitChar(int pos) { 1.100 if (reader.ch == '\\') { 1.101 if (reader.peekChar() == '\\' && !reader.isUnicode()) { 1.102 reader.skipChar(); 1.103 - putChar('\\'); 1.104 - reader.scanChar(); 1.105 + reader.putChar('\\', true); 1.106 } else { 1.107 reader.scanChar(); 1.108 switch (reader.ch) { 1.109 @@ -195,30 +162,30 @@ 1.110 reader.scanChar(); 1.111 } 1.112 } 1.113 - putChar((char)oct); 1.114 + reader.putChar((char)oct); 1.115 break; 1.116 case 'b': 1.117 - putChar('\b'); reader.scanChar(); break; 1.118 + reader.putChar('\b', true); break; 1.119 case 't': 1.120 - putChar('\t'); reader.scanChar(); break; 1.121 + reader.putChar('\t', true); break; 1.122 case 'n': 1.123 - putChar('\n'); reader.scanChar(); break; 1.124 + reader.putChar('\n', true); break; 1.125 case 'f': 1.126 - putChar('\f'); reader.scanChar(); break; 1.127 + reader.putChar('\f', true); break; 1.128 case 'r': 1.129 - putChar('\r'); reader.scanChar(); break; 1.130 + reader.putChar('\r', true); break; 1.131 case '\'': 1.132 - putChar('\''); reader.scanChar(); break; 1.133 + reader.putChar('\'', true); break; 1.134 case '\"': 1.135 - putChar('\"'); reader.scanChar(); break; 1.136 + reader.putChar('\"', true); break; 1.137 case '\\': 1.138 - putChar('\\'); reader.scanChar(); break; 1.139 + reader.putChar('\\', true); break; 1.140 default: 1.141 lexError(reader.bp, "illegal.esc.char"); 1.142 } 1.143 } 1.144 } else if (reader.bp != reader.buflen) { 1.145 - putChar(reader.ch); reader.scanChar(); 1.146 + reader.putChar(true); 1.147 } 1.148 } 1.149 1.150 @@ -227,7 +194,7 @@ 1.151 int savePos; 1.152 do { 1.153 if (reader.ch != '_') { 1.154 - putChar(reader.ch); 1.155 + reader.putChar(false); 1.156 } else { 1.157 if (!allowUnderscoresInLiterals) { 1.158 lexError(pos, "unsupported.underscore.lit", source.name); 1.159 @@ -246,12 +213,10 @@ 1.160 */ 1.161 private void scanHexExponentAndSuffix(int pos) { 1.162 if (reader.ch == 'p' || reader.ch == 'P') { 1.163 - putChar(reader.ch); 1.164 - reader.scanChar(); 1.165 + reader.putChar(true); 1.166 skipIllegalUnderscores(); 1.167 if (reader.ch == '+' || reader.ch == '-') { 1.168 - putChar(reader.ch); 1.169 - reader.scanChar(); 1.170 + reader.putChar(true); 1.171 } 1.172 skipIllegalUnderscores(); 1.173 if ('0' <= reader.ch && reader.ch <= '9') { 1.174 @@ -268,14 +233,12 @@ 1.175 lexError(pos, "malformed.fp.lit"); 1.176 } 1.177 if (reader.ch == 'f' || reader.ch == 'F') { 1.178 - putChar(reader.ch); 1.179 - reader.scanChar(); 1.180 + reader.putChar(true); 1.181 tk = TokenKind.FLOATLITERAL; 1.182 radix = 16; 1.183 } else { 1.184 if (reader.ch == 'd' || reader.ch == 'D') { 1.185 - putChar(reader.ch); 1.186 - reader.scanChar(); 1.187 + reader.putChar(true); 1.188 } 1.189 tk = TokenKind.DOUBLELITERAL; 1.190 radix = 16; 1.191 @@ -289,14 +252,12 @@ 1.192 if ('0' <= reader.ch && reader.ch <= '9') { 1.193 scanDigits(pos, 10); 1.194 } 1.195 - int sp1 = sp; 1.196 + int sp1 = reader.sp; 1.197 if (reader.ch == 'e' || reader.ch == 'E') { 1.198 - putChar(reader.ch); 1.199 - reader.scanChar(); 1.200 + reader.putChar(true); 1.201 skipIllegalUnderscores(); 1.202 if (reader.ch == '+' || reader.ch == '-') { 1.203 - putChar(reader.ch); 1.204 - reader.scanChar(); 1.205 + reader.putChar(true); 1.206 } 1.207 skipIllegalUnderscores(); 1.208 if ('0' <= reader.ch && reader.ch <= '9') { 1.209 @@ -304,7 +265,7 @@ 1.210 return; 1.211 } 1.212 lexError(pos, "malformed.fp.lit"); 1.213 - sp = sp1; 1.214 + reader.sp = sp1; 1.215 } 1.216 } 1.217 1.218 @@ -314,13 +275,11 @@ 1.219 radix = 10; 1.220 scanFraction(pos); 1.221 if (reader.ch == 'f' || reader.ch == 'F') { 1.222 - putChar(reader.ch); 1.223 - reader.scanChar(); 1.224 + reader.putChar(true); 1.225 tk = TokenKind.FLOATLITERAL; 1.226 } else { 1.227 if (reader.ch == 'd' || reader.ch == 'D') { 1.228 - putChar(reader.ch); 1.229 - reader.scanChar(); 1.230 + reader.putChar(true); 1.231 } 1.232 tk = TokenKind.DOUBLELITERAL; 1.233 } 1.234 @@ -331,8 +290,7 @@ 1.235 private void scanHexFractionAndSuffix(int pos, boolean seendigit) { 1.236 radix = 16; 1.237 Assert.check(reader.ch == '.'); 1.238 - putChar(reader.ch); 1.239 - reader.scanChar(); 1.240 + reader.putChar(true); 1.241 skipIllegalUnderscores(); 1.242 if (reader.digit(pos, 16) >= 0) { 1.243 seendigit = true; 1.244 @@ -369,8 +327,7 @@ 1.245 } else if (seendigit && radix == 16 && (reader.ch == 'p' || reader.ch == 'P')) { 1.246 scanHexExponentAndSuffix(pos); 1.247 } else if (digitRadix == 10 && reader.ch == '.') { 1.248 - putChar(reader.ch); 1.249 - reader.scanChar(); 1.250 + reader.putChar(true); 1.251 scanFractionAndSuffix(pos); 1.252 } else if (digitRadix == 10 && 1.253 (reader.ch == 'e' || reader.ch == 'E' || 1.254 @@ -393,10 +350,7 @@ 1.255 boolean isJavaIdentifierPart; 1.256 char high; 1.257 do { 1.258 - if (sp == sbuf.length) putChar(reader.ch); else sbuf[sp++] = reader.ch; 1.259 - // optimization, was: putChar(reader.ch); 1.260 - 1.261 - reader.scanChar(); 1.262 + reader.putChar(true); 1.263 switch (reader.ch) { 1.264 case 'A': case 'B': case 'C': case 'D': case 'E': 1.265 case 'F': case 'G': case 'H': case 'I': case 'J': 1.266 @@ -423,7 +377,7 @@ 1.267 break; 1.268 case '\u001A': // EOI is also a legal identifier part 1.269 if (reader.bp >= reader.buflen) { 1.270 - name = names.fromChars(sbuf, 0, sp); 1.271 + name = reader.name(); 1.272 tk = tokens.lookupKind(name); 1.273 return; 1.274 } 1.275 @@ -435,11 +389,7 @@ 1.276 } else { 1.277 high = reader.scanSurrogates(); 1.278 if (high != 0) { 1.279 - if (sp == sbuf.length) { 1.280 - putChar(high); 1.281 - } else { 1.282 - sbuf[sp++] = high; 1.283 - } 1.284 + reader.putChar(high); 1.285 isJavaIdentifierPart = Character.isJavaIdentifierPart( 1.286 Character.toCodePoint(high, reader.ch)); 1.287 } else { 1.288 @@ -447,7 +397,7 @@ 1.289 } 1.290 } 1.291 if (!isJavaIdentifierPart) { 1.292 - name = names.fromChars(sbuf, 0, sp); 1.293 + name = reader.name(); 1.294 tk = tokens.lookupKind(name); 1.295 return; 1.296 } 1.297 @@ -474,11 +424,11 @@ 1.298 */ 1.299 private void scanOperator() { 1.300 while (true) { 1.301 - putChar(reader.ch); 1.302 - Name newname = names.fromChars(sbuf, 0, sp); 1.303 + reader.putChar(false); 1.304 + Name newname = reader.name(); 1.305 TokenKind tk1 = tokens.lookupKind(newname); 1.306 if (tk1 == TokenKind.IDENTIFIER) { 1.307 - sp--; 1.308 + reader.sp--; 1.309 break; 1.310 } 1.311 tk = tk1; 1.312 @@ -487,111 +437,17 @@ 1.313 } 1.314 } 1.315 1.316 - /** 1.317 - * Scan a documentation comment; determine if a deprecated tag is present. 1.318 - * Called once the initial /, * have been skipped, positioned at the second * 1.319 - * (which is treated as the beginning of the first line). 1.320 - * Stops positioned at the closing '/'. 1.321 - */ 1.322 - @SuppressWarnings("fallthrough") 1.323 - private void scanDocComment() { 1.324 - boolean deprecatedPrefix = false; 1.325 - 1.326 - forEachLine: 1.327 - while (reader.bp < reader.buflen) { 1.328 - 1.329 - // Skip optional WhiteSpace at beginning of line 1.330 - while (reader.bp < reader.buflen && (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF)) { 1.331 - scanCommentChar(); 1.332 - } 1.333 - 1.334 - // Skip optional consecutive Stars 1.335 - while (reader.bp < reader.buflen && reader.ch == '*') { 1.336 - scanCommentChar(); 1.337 - if (reader.ch == '/') { 1.338 - return; 1.339 - } 1.340 - } 1.341 - 1.342 - // Skip optional WhiteSpace after Stars 1.343 - while (reader.bp < reader.buflen && (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF)) { 1.344 - scanCommentChar(); 1.345 - } 1.346 - 1.347 - deprecatedPrefix = false; 1.348 - // At beginning of line in the JavaDoc sense. 1.349 - if (reader.bp < reader.buflen && reader.ch == '@' && !deprecatedFlag) { 1.350 - scanCommentChar(); 1.351 - if (reader.bp < reader.buflen && reader.ch == 'd') { 1.352 - scanCommentChar(); 1.353 - if (reader.bp < reader.buflen && reader.ch == 'e') { 1.354 - scanCommentChar(); 1.355 - if (reader.bp < reader.buflen && reader.ch == 'p') { 1.356 - scanCommentChar(); 1.357 - if (reader.bp < reader.buflen && reader.ch == 'r') { 1.358 - scanCommentChar(); 1.359 - if (reader.bp < reader.buflen && reader.ch == 'e') { 1.360 - scanCommentChar(); 1.361 - if (reader.bp < reader.buflen && reader.ch == 'c') { 1.362 - scanCommentChar(); 1.363 - if (reader.bp < reader.buflen && reader.ch == 'a') { 1.364 - scanCommentChar(); 1.365 - if (reader.bp < reader.buflen && reader.ch == 't') { 1.366 - scanCommentChar(); 1.367 - if (reader.bp < reader.buflen && reader.ch == 'e') { 1.368 - scanCommentChar(); 1.369 - if (reader.bp < reader.buflen && reader.ch == 'd') { 1.370 - deprecatedPrefix = true; 1.371 - scanCommentChar(); 1.372 - }}}}}}}}}}} 1.373 - if (deprecatedPrefix && reader.bp < reader.buflen) { 1.374 - if (Character.isWhitespace(reader.ch)) { 1.375 - deprecatedFlag = true; 1.376 - } else if (reader.ch == '*') { 1.377 - scanCommentChar(); 1.378 - if (reader.ch == '/') { 1.379 - deprecatedFlag = true; 1.380 - return; 1.381 - } 1.382 - } 1.383 - } 1.384 - 1.385 - // Skip rest of line 1.386 - while (reader.bp < reader.buflen) { 1.387 - switch (reader.ch) { 1.388 - case '*': 1.389 - scanCommentChar(); 1.390 - if (reader.ch == '/') { 1.391 - return; 1.392 - } 1.393 - break; 1.394 - case CR: // (Spec 3.4) 1.395 - scanCommentChar(); 1.396 - if (reader.ch != LF) { 1.397 - continue forEachLine; 1.398 - } 1.399 - /* fall through to LF case */ 1.400 - case LF: // (Spec 3.4) 1.401 - scanCommentChar(); 1.402 - continue forEachLine; 1.403 - default: 1.404 - scanCommentChar(); 1.405 - } 1.406 - } // rest of line 1.407 - } // forEachLine 1.408 - return; 1.409 - } 1.410 - 1.411 /** Read token. 1.412 */ 1.413 public Token readToken() { 1.414 1.415 - sp = 0; 1.416 + reader.sp = 0; 1.417 name = null; 1.418 - deprecatedFlag = false; 1.419 radix = 0; 1.420 + 1.421 int pos = 0; 1.422 int endPos = 0; 1.423 + List<Comment> comments = null; 1.424 1.425 try { 1.426 loop: while (true) { 1.427 @@ -656,7 +512,7 @@ 1.428 scanNumber(pos, 2); 1.429 } 1.430 } else { 1.431 - putChar('0'); 1.432 + reader.putChar('0'); 1.433 if (reader.ch == '_') { 1.434 int savePos = reader.bp; 1.435 do { 1.436 @@ -676,14 +532,13 @@ 1.437 case '.': 1.438 reader.scanChar(); 1.439 if ('0' <= reader.ch && reader.ch <= '9') { 1.440 - putChar('.'); 1.441 + reader.putChar('.'); 1.442 scanFractionAndSuffix(pos); 1.443 } else if (reader.ch == '.') { 1.444 - putChar('.'); putChar('.'); 1.445 - reader.scanChar(); 1.446 + reader.putChar('.'); reader.putChar('.', true); 1.447 if (reader.ch == '.') { 1.448 reader.scanChar(); 1.449 - putChar('.'); 1.450 + reader.putChar('.'); 1.451 tk = TokenKind.ELLIPSIS; 1.452 } else { 1.453 lexError(pos, "malformed.fp.lit"); 1.454 @@ -712,32 +567,36 @@ 1.455 reader.scanChar(); 1.456 if (reader.ch == '/') { 1.457 do { 1.458 - scanCommentChar(); 1.459 + reader.scanCommentChar(); 1.460 } while (reader.ch != CR && reader.ch != LF && reader.bp < reader.buflen); 1.461 if (reader.bp < reader.buflen) { 1.462 - processComment(pos, reader.bp, CommentStyle.LINE); 1.463 + comments = addDocReader(comments, processComment(pos, reader.bp, CommentStyle.LINE)); 1.464 } 1.465 break; 1.466 } else if (reader.ch == '*') { 1.467 + boolean isEmpty = false; 1.468 reader.scanChar(); 1.469 CommentStyle style; 1.470 if (reader.ch == '*') { 1.471 style = CommentStyle.JAVADOC; 1.472 - scanDocComment(); 1.473 + reader.scanCommentChar(); 1.474 + if (reader.ch == '/') { 1.475 + isEmpty = true; 1.476 + } 1.477 } else { 1.478 style = CommentStyle.BLOCK; 1.479 - while (reader.bp < reader.buflen) { 1.480 - if (reader.ch == '*') { 1.481 - reader.scanChar(); 1.482 - if (reader.ch == '/') break; 1.483 - } else { 1.484 - scanCommentChar(); 1.485 - } 1.486 + } 1.487 + while (!isEmpty && reader.bp < reader.buflen) { 1.488 + if (reader.ch == '*') { 1.489 + reader.scanChar(); 1.490 + if (reader.ch == '/') break; 1.491 + } else { 1.492 + reader.scanCommentChar(); 1.493 } 1.494 } 1.495 if (reader.ch == '/') { 1.496 reader.scanChar(); 1.497 - processComment(pos, reader.bp, style); 1.498 + comments = addDocReader(comments, processComment(pos, reader.bp, style)); 1.499 break; 1.500 } else { 1.501 lexError(pos, "unclosed.comment"); 1.502 @@ -789,11 +648,7 @@ 1.503 } else { 1.504 char high = reader.scanSurrogates(); 1.505 if (high != 0) { 1.506 - if (sp == sbuf.length) { 1.507 - putChar(high); 1.508 - } else { 1.509 - sbuf[sp++] = high; 1.510 - } 1.511 + reader.putChar(high); 1.512 1.513 isJavaIdentifierStart = Character.isJavaIdentifierStart( 1.514 Character.toCodePoint(high, reader.ch)); 1.515 @@ -816,10 +671,10 @@ 1.516 } 1.517 endPos = reader.bp; 1.518 switch (tk.tag) { 1.519 - case DEFAULT: return new Token(tk, pos, endPos, deprecatedFlag); 1.520 - case NAMED: return new NamedToken(tk, pos, endPos, name, deprecatedFlag); 1.521 - case STRING: return new StringToken(tk, pos, endPos, new String(sbuf, 0, sp), deprecatedFlag); 1.522 - case NUMERIC: return new NumericToken(tk, pos, endPos, new String(sbuf, 0, sp), radix, deprecatedFlag); 1.523 + case DEFAULT: return new Token(tk, pos, endPos, comments); 1.524 + case NAMED: return new NamedToken(tk, pos, endPos, name, comments); 1.525 + case STRING: return new StringToken(tk, pos, endPos, reader.chars(), comments); 1.526 + case NUMERIC: return new NumericToken(tk, pos, endPos, reader.chars(), radix, comments); 1.527 default: throw new AssertionError(); 1.528 } 1.529 } 1.530 @@ -832,6 +687,12 @@ 1.531 } 1.532 } 1.533 } 1.534 + //where 1.535 + List<Comment> addDocReader(List<Comment> docReaders, Comment docReader) { 1.536 + return docReaders == null ? 1.537 + List.of(docReader) : 1.538 + docReaders.prepend(docReader); 1.539 + } 1.540 1.541 /** Return the position where a lexical error occurred; 1.542 */ 1.543 @@ -845,22 +706,18 @@ 1.544 errPos = pos; 1.545 } 1.546 1.547 - public enum CommentStyle { 1.548 - LINE, 1.549 - BLOCK, 1.550 - JAVADOC, 1.551 - } 1.552 - 1.553 /** 1.554 * Called when a complete comment has been scanned. pos and endPos 1.555 * will mark the comment boundary. 1.556 */ 1.557 - protected void processComment(int pos, int endPos, CommentStyle style) { 1.558 + protected Tokens.Comment processComment(int pos, int endPos, CommentStyle style) { 1.559 if (scannerDebug) 1.560 System.out.println("processComment(" + pos 1.561 + "," + endPos + "," + style + ")=|" 1.562 + new String(reader.getRawCharacters(pos, endPos)) 1.563 + "|"); 1.564 + char[] buf = reader.getRawCharacters(pos, endPos); 1.565 + return new BasicComment<UnicodeReader>(new UnicodeReader(fac, buf, buf.length), style); 1.566 } 1.567 1.568 /** 1.569 @@ -893,4 +750,125 @@ 1.570 public Position.LineMap getLineMap() { 1.571 return Position.makeLineMap(reader.getRawCharacters(), reader.buflen, false); 1.572 } 1.573 + 1.574 + 1.575 + /** 1.576 + * Scan a documentation comment; determine if a deprecated tag is present. 1.577 + * Called once the initial /, * have been skipped, positioned at the second * 1.578 + * (which is treated as the beginning of the first line). 1.579 + * Stops positioned at the closing '/'. 1.580 + */ 1.581 + protected class BasicComment<U extends UnicodeReader> implements Comment { 1.582 + 1.583 + CommentStyle cs; 1.584 + U comment_reader; 1.585 + 1.586 + protected boolean deprecatedFlag = false; 1.587 + protected boolean scanned = false; 1.588 + 1.589 + protected BasicComment(U comment_reader, CommentStyle cs) { 1.590 + this.comment_reader = comment_reader; 1.591 + this.cs = cs; 1.592 + } 1.593 + 1.594 + public String getText() { 1.595 + return null; 1.596 + } 1.597 + 1.598 + public CommentStyle getStyle() { 1.599 + return cs; 1.600 + } 1.601 + 1.602 + public boolean isDeprecated() { 1.603 + if (!scanned && cs == CommentStyle.JAVADOC) { 1.604 + scanDocComment(); 1.605 + } 1.606 + return deprecatedFlag; 1.607 + } 1.608 + 1.609 + @SuppressWarnings("fallthrough") 1.610 + protected void scanDocComment() { 1.611 + try { 1.612 + boolean deprecatedPrefix = false; 1.613 + 1.614 + comment_reader.bp += 3; // '/**' 1.615 + comment_reader.ch = comment_reader.buf[comment_reader.bp]; 1.616 + 1.617 + forEachLine: 1.618 + while (comment_reader.bp < comment_reader.buflen) { 1.619 + 1.620 + // Skip optional WhiteSpace at beginning of line 1.621 + while (comment_reader.bp < comment_reader.buflen && (comment_reader.ch == ' ' || comment_reader.ch == '\t' || comment_reader.ch == FF)) { 1.622 + comment_reader.scanCommentChar(); 1.623 + } 1.624 + 1.625 + // Skip optional consecutive Stars 1.626 + while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '*') { 1.627 + comment_reader.scanCommentChar(); 1.628 + if (comment_reader.ch == '/') { 1.629 + return; 1.630 + } 1.631 + } 1.632 + 1.633 + // Skip optional WhiteSpace after Stars 1.634 + while (comment_reader.bp < comment_reader.buflen && (comment_reader.ch == ' ' || comment_reader.ch == '\t' || comment_reader.ch == FF)) { 1.635 + comment_reader.scanCommentChar(); 1.636 + } 1.637 + 1.638 + deprecatedPrefix = false; 1.639 + // At beginning of line in the JavaDoc sense. 1.640 + if (!deprecatedFlag) { 1.641 + String deprecated = "@deprecated"; 1.642 + int i = 0; 1.643 + while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == deprecated.charAt(i)) { 1.644 + comment_reader.scanCommentChar(); 1.645 + i++; 1.646 + if (i == deprecated.length()) { 1.647 + deprecatedPrefix = true; 1.648 + break; 1.649 + } 1.650 + } 1.651 + } 1.652 + 1.653 + if (deprecatedPrefix && comment_reader.bp < comment_reader.buflen) { 1.654 + if (Character.isWhitespace(comment_reader.ch)) { 1.655 + deprecatedFlag = true; 1.656 + } else if (comment_reader.ch == '*') { 1.657 + comment_reader.scanCommentChar(); 1.658 + if (comment_reader.ch == '/') { 1.659 + deprecatedFlag = true; 1.660 + return; 1.661 + } 1.662 + } 1.663 + } 1.664 + 1.665 + // Skip rest of line 1.666 + while (comment_reader.bp < comment_reader.buflen) { 1.667 + switch (comment_reader.ch) { 1.668 + case '*': 1.669 + comment_reader.scanCommentChar(); 1.670 + if (comment_reader.ch == '/') { 1.671 + return; 1.672 + } 1.673 + break; 1.674 + case CR: // (Spec 3.4) 1.675 + comment_reader.scanCommentChar(); 1.676 + if (comment_reader.ch != LF) { 1.677 + continue forEachLine; 1.678 + } 1.679 + /* fall through to LF case */ 1.680 + case LF: // (Spec 3.4) 1.681 + comment_reader.scanCommentChar(); 1.682 + continue forEachLine; 1.683 + default: 1.684 + comment_reader.scanCommentChar(); 1.685 + } 1.686 + } // rest of line 1.687 + } // forEachLine 1.688 + return; 1.689 + } finally { 1.690 + scanned = true; 1.691 + } 1.692 + } 1.693 + } 1.694 }
2.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Nov 01 15:49:45 2011 -0700 2.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Nov 04 12:36:40 2011 +0000 2.3 @@ -29,6 +29,7 @@ 2.4 2.5 import com.sun.tools.javac.code.*; 2.6 import com.sun.tools.javac.parser.Tokens.*; 2.7 +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; 2.8 import com.sun.tools.javac.tree.*; 2.9 import com.sun.tools.javac.tree.JCTree.*; 2.10 import com.sun.tools.javac.util.*; 2.11 @@ -1584,7 +1585,7 @@ 2.12 break; 2.13 case MONKEYS_AT: 2.14 case FINAL: { 2.15 - String dc = token.docComment; 2.16 + String dc = token.comment(CommentStyle.JAVADOC); 2.17 JCModifiers mods = modifiersOpt(); 2.18 if (token.kind == INTERFACE || 2.19 token.kind == CLASS || 2.20 @@ -1601,21 +1602,21 @@ 2.21 break; 2.22 } 2.23 case ABSTRACT: case STRICTFP: { 2.24 - String dc = token.docComment; 2.25 + String dc = token.comment(CommentStyle.JAVADOC); 2.26 JCModifiers mods = modifiersOpt(); 2.27 stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); 2.28 break; 2.29 } 2.30 case INTERFACE: 2.31 case CLASS: 2.32 - String dc = token.docComment; 2.33 + String dc = token.comment(CommentStyle.JAVADOC); 2.34 stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); 2.35 break; 2.36 case ENUM: 2.37 case ASSERT: 2.38 if (allowEnums && token.kind == ENUM) { 2.39 error(token.pos, "local.enum"); 2.40 - dc = token.docComment; 2.41 + dc = token.comment(CommentStyle.JAVADOC); 2.42 stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); 2.43 break; 2.44 } else if (allowAsserts && token.kind == ASSERT) { 2.45 @@ -1991,7 +1992,7 @@ 2.46 annotations.appendList(partial.annotations); 2.47 pos = partial.pos; 2.48 } 2.49 - if (token.deprecatedFlag) { 2.50 + if (token.deprecatedFlag()) { 2.51 flags |= Flags.DEPRECATED; 2.52 } 2.53 int lastPos = Position.NOPOS; 2.54 @@ -2271,9 +2272,9 @@ 2.55 seenImport = true; 2.56 defs.append(importDeclaration()); 2.57 } else { 2.58 - String docComment = token.docComment; 2.59 + String docComment = token.comment(CommentStyle.JAVADOC); 2.60 if (firstTypeDecl && !seenImport && !seenPackage) { 2.61 - docComment = firstToken.docComment; 2.62 + docComment = firstToken.comment(CommentStyle.JAVADOC); 2.63 consumedToplevelDoc = true; 2.64 } 2.65 JCTree def = typeDeclaration(mods, docComment); 2.66 @@ -2288,7 +2289,7 @@ 2.67 } 2.68 JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList()); 2.69 if (!consumedToplevelDoc) 2.70 - attach(toplevel, firstToken.docComment); 2.71 + attach(toplevel, firstToken.comment(CommentStyle.JAVADOC)); 2.72 if (defs.elems.isEmpty()) 2.73 storeEnd(toplevel, S.prevToken().endPos); 2.74 if (keepDocComments) 2.75 @@ -2498,9 +2499,9 @@ 2.76 /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ] 2.77 */ 2.78 JCTree enumeratorDeclaration(Name enumName) { 2.79 - String dc = token.docComment; 2.80 + String dc = token.comment(CommentStyle.JAVADOC); 2.81 int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM; 2.82 - if (token.deprecatedFlag) { 2.83 + if (token.deprecatedFlag()) { 2.84 flags |= Flags.DEPRECATED; 2.85 } 2.86 int pos = token.pos; 2.87 @@ -2587,7 +2588,7 @@ 2.88 nextToken(); 2.89 return List.<JCTree>nil(); 2.90 } else { 2.91 - String dc = token.docComment; 2.92 + String dc = token.comment(CommentStyle.JAVADOC); 2.93 int pos = token.pos; 2.94 JCModifiers mods = modifiersOpt(); 2.95 if (token.kind == CLASS ||
3.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java Tue Nov 01 15:49:45 2011 -0700 3.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java Fri Nov 04 12:36:40 2011 +0000 3.3 @@ -25,8 +25,8 @@ 3.4 3.5 package com.sun.tools.javac.parser; 3.6 3.7 -import com.sun.tools.javac.file.JavacFileManager; 3.8 -import com.sun.tools.javac.parser.Tokens.Token; 3.9 +import com.sun.tools.javac.parser.Tokens.Comment; 3.10 +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; 3.11 import com.sun.tools.javac.util.*; 3.12 3.13 import java.nio.*; 3.14 @@ -59,352 +59,295 @@ 3.15 super(fac, input, inputLength); 3.16 } 3.17 3.18 - /** The comment input buffer, index of next chacter to be read, 3.19 - * index of one past last character in buffer. 3.20 - */ 3.21 - private char[] buf; 3.22 - private int bp; 3.23 - private int buflen; 3.24 - 3.25 - /** The current character. 3.26 - */ 3.27 - private char ch; 3.28 - 3.29 - /** The column number position of the current character. 3.30 - */ 3.31 - private int col; 3.32 - 3.33 - /** The buffer index of the last converted Unicode character 3.34 - */ 3.35 - private int unicodeConversionBp = 0; 3.36 + @Override 3.37 + protected Comment processComment(int pos, int endPos, CommentStyle style) { 3.38 + char[] buf = reader.getRawCharacters(pos, endPos); 3.39 + return new JavadocComment(new ColReader(fac, buf, buf.length), style); 3.40 + } 3.41 3.42 /** 3.43 - * Buffer for doc comment. 3.44 + * This is a specialized version of UnicodeReader that keeps track of the 3.45 + * column position within a given character stream (used for Javadoc processing). 3.46 */ 3.47 - private char[] docCommentBuffer = new char[1024]; 3.48 + static class ColReader extends UnicodeReader { 3.49 3.50 - /** 3.51 - * Number of characters in doc comment buffer. 3.52 - */ 3.53 - private int docCommentCount; 3.54 + int col; 3.55 3.56 - /** 3.57 - * Translated and stripped contents of doc comment 3.58 - */ 3.59 - private String docComment = null; 3.60 + ColReader(ScannerFactory fac, char[] input, int inputLength) { 3.61 + super(fac, input, inputLength); 3.62 + } 3.63 3.64 + @Override 3.65 + protected void convertUnicode() { 3.66 + if (ch == '\\' && unicodeConversionBp != bp) { 3.67 + bp++; ch = buf[bp]; col++; 3.68 + if (ch == 'u') { 3.69 + do { 3.70 + bp++; ch = buf[bp]; col++; 3.71 + } while (ch == 'u'); 3.72 + int limit = bp + 3; 3.73 + if (limit < buflen) { 3.74 + int d = digit(bp, 16); 3.75 + int code = d; 3.76 + while (bp < limit && d >= 0) { 3.77 + bp++; ch = buf[bp]; col++; 3.78 + d = digit(bp, 16); 3.79 + code = (code << 4) + d; 3.80 + } 3.81 + if (d >= 0) { 3.82 + ch = (char)code; 3.83 + unicodeConversionBp = bp; 3.84 + return; 3.85 + } 3.86 + } 3.87 + // "illegal.Unicode.esc", reported by base scanner 3.88 + } else { 3.89 + bp--; 3.90 + ch = '\\'; 3.91 + col--; 3.92 + } 3.93 + } 3.94 + } 3.95 3.96 - /** Unconditionally expand the comment buffer. 3.97 - */ 3.98 - private void expandCommentBuffer() { 3.99 - char[] newBuffer = new char[docCommentBuffer.length * 2]; 3.100 - System.arraycopy(docCommentBuffer, 0, newBuffer, 3.101 - 0, docCommentBuffer.length); 3.102 - docCommentBuffer = newBuffer; 3.103 - } 3.104 + @Override 3.105 + protected void scanCommentChar() { 3.106 + scanChar(); 3.107 + if (ch == '\\') { 3.108 + if (peekChar() == '\\' && !isUnicode()) { 3.109 + putChar(ch, false); 3.110 + bp++; col++; 3.111 + } else { 3.112 + convertUnicode(); 3.113 + } 3.114 + } 3.115 + } 3.116 3.117 - /** Convert an ASCII digit from its base (8, 10, or 16) 3.118 - * to its value. 3.119 - */ 3.120 - private int digit(int base) { 3.121 - char c = ch; 3.122 - int result = Character.digit(c, base); 3.123 - if (result >= 0 && c > 0x7f) { 3.124 - ch = "0123456789abcdef".charAt(result); 3.125 + @Override 3.126 + protected void scanChar() { 3.127 + bp++; 3.128 + ch = buf[bp]; 3.129 + switch (ch) { 3.130 + case '\r': // return 3.131 + col = 0; 3.132 + break; 3.133 + case '\n': // newline 3.134 + if (bp == 0 || buf[bp-1] != '\r') { 3.135 + col = 0; 3.136 + } 3.137 + break; 3.138 + case '\t': // tab 3.139 + col = (col / TabInc * TabInc) + TabInc; 3.140 + break; 3.141 + case '\\': // possible Unicode 3.142 + col++; 3.143 + convertUnicode(); 3.144 + break; 3.145 + default: 3.146 + col++; 3.147 + break; 3.148 + } 3.149 + } 3.150 + } 3.151 + 3.152 + protected class JavadocComment extends JavaTokenizer.BasicComment<ColReader> { 3.153 + 3.154 + /** 3.155 + * Translated and stripped contents of doc comment 3.156 + */ 3.157 + private String docComment = null; 3.158 + 3.159 + JavadocComment(ColReader comment_reader, CommentStyle cs) { 3.160 + super(comment_reader, cs); 3.161 } 3.162 - return result; 3.163 - } 3.164 3.165 - /** Convert Unicode escape; bp points to initial '\' character 3.166 - * (Spec 3.3). 3.167 - */ 3.168 - private void convertUnicode() { 3.169 - if (ch == '\\' && unicodeConversionBp != bp) { 3.170 - bp++; ch = buf[bp]; col++; 3.171 - if (ch == 'u') { 3.172 - do { 3.173 - bp++; ch = buf[bp]; col++; 3.174 - } while (ch == 'u'); 3.175 - int limit = bp + 3; 3.176 - if (limit < buflen) { 3.177 - int d = digit(16); 3.178 - int code = d; 3.179 - while (bp < limit && d >= 0) { 3.180 - bp++; ch = buf[bp]; col++; 3.181 - d = digit(16); 3.182 - code = (code << 4) + d; 3.183 - } 3.184 - if (d >= 0) { 3.185 - ch = (char)code; 3.186 - unicodeConversionBp = bp; 3.187 - return; 3.188 - } 3.189 + public String getText() { 3.190 + if (!scanned && cs == CommentStyle.JAVADOC) { 3.191 + scanDocComment(); 3.192 + } 3.193 + return docComment; 3.194 + } 3.195 + 3.196 + @Override 3.197 + @SuppressWarnings("fallthrough") 3.198 + protected void scanDocComment() { 3.199 + try { 3.200 + boolean firstLine = true; 3.201 + 3.202 + // Skip over first slash 3.203 + comment_reader.scanCommentChar(); 3.204 + // Skip over first star 3.205 + comment_reader.scanCommentChar(); 3.206 + 3.207 + // consume any number of stars 3.208 + while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '*') { 3.209 + comment_reader.scanCommentChar(); 3.210 + } 3.211 + // is the comment in the form /**/, /***/, /****/, etc. ? 3.212 + if (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '/') { 3.213 + docComment = ""; 3.214 + return; 3.215 + } 3.216 + 3.217 + // skip a newline on the first line of the comment. 3.218 + if (comment_reader.bp < comment_reader.buflen) { 3.219 + if (comment_reader.ch == LF) { 3.220 + comment_reader.scanCommentChar(); 3.221 + firstLine = false; 3.222 + } else if (comment_reader.ch == CR) { 3.223 + comment_reader.scanCommentChar(); 3.224 + if (comment_reader.ch == LF) { 3.225 + comment_reader.scanCommentChar(); 3.226 + firstLine = false; 3.227 + } 3.228 + } 3.229 + } 3.230 + 3.231 + outerLoop: 3.232 + 3.233 + // The outerLoop processes the doc comment, looping once 3.234 + // for each line. For each line, it first strips off 3.235 + // whitespace, then it consumes any stars, then it 3.236 + // puts the rest of the line into our buffer. 3.237 + while (comment_reader.bp < comment_reader.buflen) { 3.238 + 3.239 + // The wsLoop consumes whitespace from the beginning 3.240 + // of each line. 3.241 + wsLoop: 3.242 + 3.243 + while (comment_reader.bp < comment_reader.buflen) { 3.244 + switch(comment_reader.ch) { 3.245 + case ' ': 3.246 + comment_reader.scanCommentChar(); 3.247 + break; 3.248 + case '\t': 3.249 + comment_reader.col = ((comment_reader.col - 1) / TabInc * TabInc) + TabInc; 3.250 + comment_reader.scanCommentChar(); 3.251 + break; 3.252 + case FF: 3.253 + comment_reader.col = 0; 3.254 + comment_reader.scanCommentChar(); 3.255 + break; 3.256 + // Treat newline at beginning of line (blank line, no star) 3.257 + // as comment text. Old Javadoc compatibility requires this. 3.258 + /*---------------------------------* 3.259 + case CR: // (Spec 3.4) 3.260 + doc_reader.scanCommentChar(); 3.261 + if (ch == LF) { 3.262 + col = 0; 3.263 + doc_reader.scanCommentChar(); 3.264 + } 3.265 + break; 3.266 + case LF: // (Spec 3.4) 3.267 + doc_reader.scanCommentChar(); 3.268 + break; 3.269 + *---------------------------------*/ 3.270 + default: 3.271 + // we've seen something that isn't whitespace; 3.272 + // jump out. 3.273 + break wsLoop; 3.274 + } 3.275 + } 3.276 + 3.277 + // Are there stars here? If so, consume them all 3.278 + // and check for the end of comment. 3.279 + if (comment_reader.ch == '*') { 3.280 + // skip all of the stars 3.281 + do { 3.282 + comment_reader.scanCommentChar(); 3.283 + } while (comment_reader.ch == '*'); 3.284 + 3.285 + // check for the closing slash. 3.286 + if (comment_reader.ch == '/') { 3.287 + // We're done with the doc comment 3.288 + // scanChar() and breakout. 3.289 + break outerLoop; 3.290 + } 3.291 + } else if (! firstLine) { 3.292 + //The current line does not begin with a '*' so we will indent it. 3.293 + for (int i = 1; i < comment_reader.col; i++) { 3.294 + comment_reader.putChar(' ', false); 3.295 + } 3.296 + } 3.297 + // The textLoop processes the rest of the characters 3.298 + // on the line, adding them to our buffer. 3.299 + textLoop: 3.300 + while (comment_reader.bp < comment_reader.buflen) { 3.301 + switch (comment_reader.ch) { 3.302 + case '*': 3.303 + // Is this just a star? Or is this the 3.304 + // end of a comment? 3.305 + comment_reader.scanCommentChar(); 3.306 + if (comment_reader.ch == '/') { 3.307 + // This is the end of the comment, 3.308 + // set ch and return our buffer. 3.309 + break outerLoop; 3.310 + } 3.311 + // This is just an ordinary star. Add it to 3.312 + // the buffer. 3.313 + comment_reader.putChar('*', false); 3.314 + break; 3.315 + case ' ': 3.316 + case '\t': 3.317 + comment_reader.putChar(comment_reader.ch, false); 3.318 + comment_reader.scanCommentChar(); 3.319 + break; 3.320 + case FF: 3.321 + comment_reader.scanCommentChar(); 3.322 + break textLoop; // treat as end of line 3.323 + case CR: // (Spec 3.4) 3.324 + comment_reader.scanCommentChar(); 3.325 + if (comment_reader.ch != LF) { 3.326 + // Canonicalize CR-only line terminator to LF 3.327 + comment_reader.putChar((char)LF, false); 3.328 + break textLoop; 3.329 + } 3.330 + /* fall through to LF case */ 3.331 + case LF: // (Spec 3.4) 3.332 + // We've seen a newline. Add it to our 3.333 + // buffer and break out of this loop, 3.334 + // starting fresh on a new line. 3.335 + comment_reader.putChar(comment_reader.ch, false); 3.336 + comment_reader.scanCommentChar(); 3.337 + break textLoop; 3.338 + default: 3.339 + // Add the character to our buffer. 3.340 + comment_reader.putChar(comment_reader.ch, false); 3.341 + comment_reader.scanCommentChar(); 3.342 + } 3.343 + } // end textLoop 3.344 + firstLine = false; 3.345 + } // end outerLoop 3.346 + 3.347 + if (comment_reader.sp > 0) { 3.348 + int i = comment_reader.sp - 1; 3.349 + trailLoop: 3.350 + while (i > -1) { 3.351 + switch (comment_reader.sbuf[i]) { 3.352 + case '*': 3.353 + i--; 3.354 + break; 3.355 + default: 3.356 + break trailLoop; 3.357 + } 3.358 + } 3.359 + comment_reader.sp = i + 1; 3.360 + 3.361 + // Store the text of the doc comment 3.362 + docComment = comment_reader.chars(); 3.363 + } else { 3.364 + docComment = ""; 3.365 } 3.366 - // "illegal.Unicode.esc", reported by base scanner 3.367 - } else { 3.368 - bp--; 3.369 - ch = '\\'; 3.370 - col--; 3.371 + } finally { 3.372 + scanned = true; 3.373 + if (docComment != null && 3.374 + docComment.matches("(?sm).*^\\s*@deprecated( |$).*")) { 3.375 + deprecatedFlag = true; 3.376 + } 3.377 } 3.378 } 3.379 } 3.380 3.381 - 3.382 - /** Read next character. 3.383 - */ 3.384 - private void scanChar() { 3.385 - bp++; 3.386 - ch = buf[bp]; 3.387 - switch (ch) { 3.388 - case '\r': // return 3.389 - col = 0; 3.390 - break; 3.391 - case '\n': // newline 3.392 - if (bp == 0 || buf[bp-1] != '\r') { 3.393 - col = 0; 3.394 - } 3.395 - break; 3.396 - case '\t': // tab 3.397 - col = (col / TabInc * TabInc) + TabInc; 3.398 - break; 3.399 - case '\\': // possible Unicode 3.400 - col++; 3.401 - convertUnicode(); 3.402 - break; 3.403 - default: 3.404 - col++; 3.405 - break; 3.406 - } 3.407 - } 3.408 - 3.409 @Override 3.410 - public Token readToken() { 3.411 - docComment = null; 3.412 - Token tk = super.readToken(); 3.413 - tk.docComment = docComment; 3.414 - return tk; 3.415 - } 3.416 - 3.417 - /** 3.418 - * Read next character in doc comment, skipping over double '\' characters. 3.419 - * If a double '\' is skipped, put in the buffer and update buffer count. 3.420 - */ 3.421 - private void scanDocCommentChar() { 3.422 - scanChar(); 3.423 - if (ch == '\\') { 3.424 - if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { 3.425 - if (docCommentCount == docCommentBuffer.length) 3.426 - expandCommentBuffer(); 3.427 - docCommentBuffer[docCommentCount++] = ch; 3.428 - bp++; col++; 3.429 - } else { 3.430 - convertUnicode(); 3.431 - } 3.432 - } 3.433 - } 3.434 - 3.435 - /** 3.436 - * Process a doc comment and make the string content available. 3.437 - * Strips leading whitespace and stars. 3.438 - */ 3.439 - @SuppressWarnings("fallthrough") 3.440 - protected void processComment(int pos, int endPos, CommentStyle style) { 3.441 - if (style != CommentStyle.JAVADOC) { 3.442 - return; 3.443 - } 3.444 - 3.445 - buf = reader.getRawCharacters(pos, endPos); 3.446 - buflen = buf.length; 3.447 - bp = 0; 3.448 - col = 0; 3.449 - 3.450 - docCommentCount = 0; 3.451 - 3.452 - boolean firstLine = true; 3.453 - 3.454 - // Skip over first slash 3.455 - scanDocCommentChar(); 3.456 - // Skip over first star 3.457 - scanDocCommentChar(); 3.458 - 3.459 - // consume any number of stars 3.460 - while (bp < buflen && ch == '*') { 3.461 - scanDocCommentChar(); 3.462 - } 3.463 - // is the comment in the form /**/, /***/, /****/, etc. ? 3.464 - if (bp < buflen && ch == '/') { 3.465 - docComment = ""; 3.466 - return; 3.467 - } 3.468 - 3.469 - // skip a newline on the first line of the comment. 3.470 - if (bp < buflen) { 3.471 - if (ch == LF) { 3.472 - scanDocCommentChar(); 3.473 - firstLine = false; 3.474 - } else if (ch == CR) { 3.475 - scanDocCommentChar(); 3.476 - if (ch == LF) { 3.477 - scanDocCommentChar(); 3.478 - firstLine = false; 3.479 - } 3.480 - } 3.481 - } 3.482 - 3.483 - outerLoop: 3.484 - 3.485 - // The outerLoop processes the doc comment, looping once 3.486 - // for each line. For each line, it first strips off 3.487 - // whitespace, then it consumes any stars, then it 3.488 - // puts the rest of the line into our buffer. 3.489 - while (bp < buflen) { 3.490 - 3.491 - // The wsLoop consumes whitespace from the beginning 3.492 - // of each line. 3.493 - wsLoop: 3.494 - 3.495 - while (bp < buflen) { 3.496 - switch(ch) { 3.497 - case ' ': 3.498 - scanDocCommentChar(); 3.499 - break; 3.500 - case '\t': 3.501 - col = ((col - 1) / TabInc * TabInc) + TabInc; 3.502 - scanDocCommentChar(); 3.503 - break; 3.504 - case FF: 3.505 - col = 0; 3.506 - scanDocCommentChar(); 3.507 - break; 3.508 -// Treat newline at beginning of line (blank line, no star) 3.509 -// as comment text. Old Javadoc compatibility requires this. 3.510 -/*---------------------------------* 3.511 - case CR: // (Spec 3.4) 3.512 - scanDocCommentChar(); 3.513 - if (ch == LF) { 3.514 - col = 0; 3.515 - scanDocCommentChar(); 3.516 - } 3.517 - break; 3.518 - case LF: // (Spec 3.4) 3.519 - scanDocCommentChar(); 3.520 - break; 3.521 -*---------------------------------*/ 3.522 - default: 3.523 - // we've seen something that isn't whitespace; 3.524 - // jump out. 3.525 - break wsLoop; 3.526 - } 3.527 - } 3.528 - 3.529 - // Are there stars here? If so, consume them all 3.530 - // and check for the end of comment. 3.531 - if (ch == '*') { 3.532 - // skip all of the stars 3.533 - do { 3.534 - scanDocCommentChar(); 3.535 - } while (ch == '*'); 3.536 - 3.537 - // check for the closing slash. 3.538 - if (ch == '/') { 3.539 - // We're done with the doc comment 3.540 - // scanChar() and breakout. 3.541 - break outerLoop; 3.542 - } 3.543 - } else if (! firstLine) { 3.544 - //The current line does not begin with a '*' so we will indent it. 3.545 - for (int i = 1; i < col; i++) { 3.546 - if (docCommentCount == docCommentBuffer.length) 3.547 - expandCommentBuffer(); 3.548 - docCommentBuffer[docCommentCount++] = ' '; 3.549 - } 3.550 - } 3.551 - 3.552 - // The textLoop processes the rest of the characters 3.553 - // on the line, adding them to our buffer. 3.554 - textLoop: 3.555 - while (bp < buflen) { 3.556 - switch (ch) { 3.557 - case '*': 3.558 - // Is this just a star? Or is this the 3.559 - // end of a comment? 3.560 - scanDocCommentChar(); 3.561 - if (ch == '/') { 3.562 - // This is the end of the comment, 3.563 - // set ch and return our buffer. 3.564 - break outerLoop; 3.565 - } 3.566 - // This is just an ordinary star. Add it to 3.567 - // the buffer. 3.568 - if (docCommentCount == docCommentBuffer.length) 3.569 - expandCommentBuffer(); 3.570 - docCommentBuffer[docCommentCount++] = '*'; 3.571 - break; 3.572 - case ' ': 3.573 - case '\t': 3.574 - if (docCommentCount == docCommentBuffer.length) 3.575 - expandCommentBuffer(); 3.576 - docCommentBuffer[docCommentCount++] = ch; 3.577 - scanDocCommentChar(); 3.578 - break; 3.579 - case FF: 3.580 - scanDocCommentChar(); 3.581 - break textLoop; // treat as end of line 3.582 - case CR: // (Spec 3.4) 3.583 - scanDocCommentChar(); 3.584 - if (ch != LF) { 3.585 - // Canonicalize CR-only line terminator to LF 3.586 - if (docCommentCount == docCommentBuffer.length) 3.587 - expandCommentBuffer(); 3.588 - docCommentBuffer[docCommentCount++] = (char)LF; 3.589 - break textLoop; 3.590 - } 3.591 - /* fall through to LF case */ 3.592 - case LF: // (Spec 3.4) 3.593 - // We've seen a newline. Add it to our 3.594 - // buffer and break out of this loop, 3.595 - // starting fresh on a new line. 3.596 - if (docCommentCount == docCommentBuffer.length) 3.597 - expandCommentBuffer(); 3.598 - docCommentBuffer[docCommentCount++] = ch; 3.599 - scanDocCommentChar(); 3.600 - break textLoop; 3.601 - default: 3.602 - // Add the character to our buffer. 3.603 - if (docCommentCount == docCommentBuffer.length) 3.604 - expandCommentBuffer(); 3.605 - docCommentBuffer[docCommentCount++] = ch; 3.606 - scanDocCommentChar(); 3.607 - } 3.608 - } // end textLoop 3.609 - firstLine = false; 3.610 - } // end outerLoop 3.611 - 3.612 - if (docCommentCount > 0) { 3.613 - int i = docCommentCount - 1; 3.614 - trailLoop: 3.615 - while (i > -1) { 3.616 - switch (docCommentBuffer[i]) { 3.617 - case '*': 3.618 - i--; 3.619 - break; 3.620 - default: 3.621 - break trailLoop; 3.622 - } 3.623 - } 3.624 - docCommentCount = i + 1; 3.625 - 3.626 - // Store the text of the doc comment 3.627 - docComment = new String(docCommentBuffer, 0 , docCommentCount); 3.628 - } else { 3.629 - docComment = ""; 3.630 - } 3.631 - } 3.632 - 3.633 - /** Build a map for translating between line numbers and 3.634 - * positions in the input. 3.635 - * 3.636 - * @return a LineMap */ 3.637 public Position.LineMap getLineMap() { 3.638 char[] buf = reader.getRawCharacters(); 3.639 return Position.makeLineMap(buf, buf.length, true);
4.1 --- a/src/share/classes/com/sun/tools/javac/parser/Tokens.java Tue Nov 01 15:49:45 2011 -0700 4.2 +++ b/src/share/classes/com/sun/tools/javac/parser/Tokens.java Fri Nov 04 12:36:40 2011 +0000 4.3 @@ -30,8 +30,10 @@ 4.4 import com.sun.tools.javac.api.Formattable; 4.5 import com.sun.tools.javac.api.Messages; 4.6 import com.sun.tools.javac.parser.Tokens.Token.Tag; 4.7 +import com.sun.tools.javac.util.List; 4.8 import com.sun.tools.javac.util.Name; 4.9 import com.sun.tools.javac.util.Context; 4.10 +import com.sun.tools.javac.util.ListBuffer; 4.11 import com.sun.tools.javac.util.Names; 4.12 4.13 /** A class that defines codes/utilities for Java source tokens 4.14 @@ -281,6 +283,19 @@ 4.15 } 4.16 } 4.17 4.18 + public interface Comment { 4.19 + 4.20 + enum CommentStyle { 4.21 + LINE, 4.22 + BLOCK, 4.23 + JAVADOC, 4.24 + } 4.25 + 4.26 + String getText(); 4.27 + CommentStyle getStyle(); 4.28 + boolean isDeprecated(); 4.29 + } 4.30 + 4.31 /** 4.32 * This is the class representing a javac token. Each token has several fields 4.33 * that are set by the javac lexer (i.e. start/end position, string value, etc). 4.34 @@ -304,18 +319,14 @@ 4.35 /** The end position of this token */ 4.36 public final int endPos; 4.37 4.38 - /** Is this token preceeded by a deprecated comment? */ 4.39 - public final boolean deprecatedFlag; 4.40 + /** Comment reader associated with this token */ 4.41 + public final List<Comment> comments; 4.42 4.43 - /** Is this token preceeded by a deprecated comment? */ 4.44 - public String docComment; 4.45 - 4.46 - Token(TokenKind kind, int pos, int endPos, 4.47 - boolean deprecatedFlag) { 4.48 + Token(TokenKind kind, int pos, int endPos, List<Comment> comments) { 4.49 this.kind = kind; 4.50 this.pos = pos; 4.51 this.endPos = endPos; 4.52 - this.deprecatedFlag = deprecatedFlag; 4.53 + this.comments = comments; 4.54 checkKind(); 4.55 } 4.56 4.57 @@ -331,8 +342,8 @@ 4.58 throw new AssertionError("Cant split - bad subtokens"); 4.59 } 4.60 return new Token[] { 4.61 - new Token(t1, pos, pos + t1.name.length(), deprecatedFlag), 4.62 - new Token(t2, pos + t1.name.length(), endPos, false) 4.63 + new Token(t1, pos, pos + t1.name.length(), comments), 4.64 + new Token(t2, pos + t1.name.length(), endPos, null) 4.65 }; 4.66 } 4.67 4.68 @@ -353,14 +364,52 @@ 4.69 public int radix() { 4.70 throw new UnsupportedOperationException(); 4.71 } 4.72 + 4.73 + /** 4.74 + * Preserve classic semantics - if multiple javadocs are found on the token 4.75 + * the last one is returned 4.76 + */ 4.77 + public String comment(Comment.CommentStyle style) { 4.78 + List<Comment> readers = getReaders(Comment.CommentStyle.JAVADOC); 4.79 + return readers.isEmpty() ? 4.80 + null : 4.81 + readers.head.getText(); 4.82 + } 4.83 + 4.84 + /** 4.85 + * Preserve classic semantics - deprecated should be set if at least one 4.86 + * javadoc comment attached to this token contains the '@deprecated' string 4.87 + */ 4.88 + public boolean deprecatedFlag() { 4.89 + for (Comment r : getReaders(Comment.CommentStyle.JAVADOC)) { 4.90 + if (r.isDeprecated()) { 4.91 + return true; 4.92 + } 4.93 + } 4.94 + return false; 4.95 + } 4.96 + 4.97 + private List<Comment> getReaders(Comment.CommentStyle style) { 4.98 + if (comments == null) { 4.99 + return List.nil(); 4.100 + } else { 4.101 + ListBuffer<Comment> buf = ListBuffer.lb(); 4.102 + for (Comment r : comments) { 4.103 + if (r.getStyle() == style) { 4.104 + buf.add(r); 4.105 + } 4.106 + } 4.107 + return buf.toList(); 4.108 + } 4.109 + } 4.110 } 4.111 4.112 final static class NamedToken extends Token { 4.113 /** The name of this token */ 4.114 public final Name name; 4.115 4.116 - public NamedToken(TokenKind kind, int pos, int endPos, Name name, boolean deprecatedFlag) { 4.117 - super(kind, pos, endPos, deprecatedFlag); 4.118 + public NamedToken(TokenKind kind, int pos, int endPos, Name name, List<Comment> comments) { 4.119 + super(kind, pos, endPos, comments); 4.120 this.name = name; 4.121 } 4.122 4.123 @@ -380,8 +429,8 @@ 4.124 /** The string value of this token */ 4.125 public final String stringVal; 4.126 4.127 - public StringToken(TokenKind kind, int pos, int endPos, String stringVal, boolean deprecatedFlag) { 4.128 - super(kind, pos, endPos, deprecatedFlag); 4.129 + public StringToken(TokenKind kind, int pos, int endPos, String stringVal, List<Comment> comments) { 4.130 + super(kind, pos, endPos, comments); 4.131 this.stringVal = stringVal; 4.132 } 4.133 4.134 @@ -401,8 +450,8 @@ 4.135 /** The 'radix' value of this token */ 4.136 public final int radix; 4.137 4.138 - public NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, boolean deprecatedFlag) { 4.139 - super(kind, pos, endPos, stringVal, deprecatedFlag); 4.140 + public NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, List<Comment> comments) { 4.141 + super(kind, pos, endPos, stringVal, comments); 4.142 this.radix = radix; 4.143 } 4.144 4.145 @@ -419,5 +468,5 @@ 4.146 } 4.147 4.148 public static final Token DUMMY = 4.149 - new Token(TokenKind.ERROR, 0, 0, false); 4.150 + new Token(TokenKind.ERROR, 0, 0, null); 4.151 }
5.1 --- a/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java Tue Nov 01 15:49:45 2011 -0700 5.2 +++ b/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java Fri Nov 04 12:36:40 2011 +0000 5.3 @@ -26,8 +26,12 @@ 5.4 package com.sun.tools.javac.parser; 5.5 5.6 import com.sun.tools.javac.file.JavacFileManager; 5.7 +import com.sun.tools.javac.util.Log; 5.8 +import com.sun.tools.javac.util.Name; 5.9 +import com.sun.tools.javac.util.Names; 5.10 + 5.11 import java.nio.CharBuffer; 5.12 -import com.sun.tools.javac.util.Log; 5.13 + 5.14 import static com.sun.tools.javac.util.LayoutCharacters.*; 5.15 5.16 /** The char reader used by the javac lexer/tokenizer. Returns the sequence of 5.17 @@ -58,6 +62,12 @@ 5.18 protected int unicodeConversionBp = -1; 5.19 5.20 protected Log log; 5.21 + protected Names names; 5.22 + 5.23 + /** A character buffer for saved chars. 5.24 + */ 5.25 + protected char[] sbuf = new char[128]; 5.26 + protected int sp; 5.27 5.28 /** 5.29 * Create a scanner from the input array. This method might 5.30 @@ -76,6 +86,7 @@ 5.31 5.32 protected UnicodeReader(ScannerFactory sf, char[] input, int inputLength) { 5.33 log = sf.log; 5.34 + names = sf.names; 5.35 if (inputLength == input.length) { 5.36 if (input.length > 0 && Character.isWhitespace(input[input.length - 1])) { 5.37 inputLength--; 5.38 @@ -103,6 +114,48 @@ 5.39 } 5.40 } 5.41 5.42 + /** Read next character in comment, skipping over double '\' characters. 5.43 + */ 5.44 + protected void scanCommentChar() { 5.45 + scanChar(); 5.46 + if (ch == '\\') { 5.47 + if (peekChar() == '\\' && !isUnicode()) { 5.48 + skipChar(); 5.49 + } else { 5.50 + convertUnicode(); 5.51 + } 5.52 + } 5.53 + } 5.54 + 5.55 + /** Append a character to sbuf. 5.56 + */ 5.57 + protected void putChar(char ch, boolean scan) { 5.58 + if (sp == sbuf.length) { 5.59 + char[] newsbuf = new char[sbuf.length * 2]; 5.60 + System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length); 5.61 + sbuf = newsbuf; 5.62 + } 5.63 + sbuf[sp++] = ch; 5.64 + if (scan) 5.65 + scanChar(); 5.66 + } 5.67 + 5.68 + protected void putChar(char ch) { 5.69 + putChar(ch, false); 5.70 + } 5.71 + 5.72 + protected void putChar(boolean scan) { 5.73 + putChar(ch, scan); 5.74 + } 5.75 + 5.76 + Name name() { 5.77 + return names.fromChars(sbuf, 0, sp); 5.78 + } 5.79 + 5.80 + String chars() { 5.81 + return new String(sbuf, 0, sp); 5.82 + } 5.83 + 5.84 /** Convert unicode escape; bp points to initial '\' character 5.85 * (Spec 3.3). 5.86 */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/tools/javac/depDocComment/DeprecatedDocComment4.java Fri Nov 04 12:36:40 2011 +0000 6.3 @@ -0,0 +1,20 @@ 6.4 +/** 6.5 + * @test /nodynamiccopyright/ 6.6 + * @bug 7104201 6.7 + * @summary Refactor DocCommentScanner 6.8 + * @compile/fail/ref=DeprecatedDocComment4.out -XDrawDiagnostics -Werror -Xlint:dep-ann DeprecatedDocComment4.java 6.9 + */ 6.10 + 6.11 +class DeprecatedDocComment4 { 6.12 + /** @deprecated **/ 6.13 + /* block */ 6.14 + void test1() {}; 6.15 + 6.16 + /** @deprecated **/ 6.17 + /** double javadoc */ 6.18 + void test2() {}; 6.19 + 6.20 + /** @deprecated **/ 6.21 + //line comment 6.22 + void test3() {}; 6.23 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/tools/javac/depDocComment/DeprecatedDocComment4.out Fri Nov 04 12:36:40 2011 +0000 7.3 @@ -0,0 +1,6 @@ 7.4 +DeprecatedDocComment4.java:11:10: compiler.warn.missing.deprecated.annotation 7.5 +DeprecatedDocComment4.java:15:10: compiler.warn.missing.deprecated.annotation 7.6 +DeprecatedDocComment4.java:19:10: compiler.warn.missing.deprecated.annotation 7.7 +- compiler.err.warnings.and.werror 7.8 +1 error 7.9 +3 warnings