diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index 23fc4076caf..e2bbf7ec4e8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -307,6 +307,15 @@ public class JavaTokenizer extends UnicodeReader { return false; } + /** + * Test if the current character is a line terminator. + * + * @return true if current character is a line terminator. + */ + private boolean isEOLN() { + return isOneOf('\n', '\r'); + } + /** * Skip and process a line terminator sequence. */ @@ -1085,7 +1094,7 @@ public class JavaTokenizer extends UnicodeReader { if (scannerDebug) { System.out.println("nextToken(" + pos + "," + endPos + ")=|" + - getRawString(pos, endPos) + new String(getRawCharacters(pos, endPos)) + "|"); } } @@ -1137,11 +1146,13 @@ public class JavaTokenizer extends UnicodeReader { if (scannerDebug) { System.out.println("processComment(" + pos + "," + endPos + "," + style + ")=|" - + getRawString(pos, endPos) + + new String(getRawCharacters(pos, endPos)) + "|"); } - return new BasicComment(style,this, pos, endPos); + char[] buf = getRawCharacters(pos, endPos); + + return new BasicComment(style, fac, buf, pos); } /** @@ -1156,8 +1167,8 @@ public class JavaTokenizer extends UnicodeReader { protected void processWhiteSpace(int pos, int endPos) { if (scannerDebug) { System.out.println("processWhitespace(" + pos - + "," + endPos + ")=|" - + getRawString(pos, endPos) + + "," + endPos + ")=|" + + new String(getRawCharacters(pos, endPos)) + "|"); } } @@ -1171,8 +1182,8 @@ public class JavaTokenizer extends UnicodeReader { protected void processLineTerminator(int pos, int endPos) { if (scannerDebug) { System.out.println("processTerminator(" + pos - + "," + endPos + ")=|" - + getRawString(pos, endPos) + + "," + endPos + ")=|" + + new String(getRawCharacters(pos, endPos)) + "|"); } } @@ -1195,6 +1206,9 @@ public class JavaTokenizer extends UnicodeReader { protected static class BasicComment extends PositionTrackingReader implements Comment { /** * Style of comment + * LINE starting with // + * BLOCK starting with /* + * JAVADOC starting with /** */ CommentStyle cs; @@ -1211,13 +1225,13 @@ public class JavaTokenizer extends UnicodeReader { /** * Constructor. * - * @param cs comment style - * @param reader existing reader - * @param pos start of meaningful content in buffer. - * @param endPos end of meaningful content in buffer. + * @param cs comment style + * @param sf Scan factory. + * @param array Array containing contents of source. + * @param offset Position offset in original source buffer. */ - protected BasicComment(CommentStyle cs, UnicodeReader reader, int pos, int endPos) { - super(reader, pos, endPos); + protected BasicComment(CommentStyle cs, ScannerFactory sf, char[] array, int offset) { + super(sf, array, offset); this.cs = cs; } @@ -1233,7 +1247,8 @@ public class JavaTokenizer extends UnicodeReader { /** * Return buffer position in original buffer mapped from buffer position in comment. * - * @param pos buffer position in comment. + * @param pos buffer position in comment. + * * @return buffer position in original buffer. */ public int getSourcePos(int pos) { @@ -1242,8 +1257,11 @@ public class JavaTokenizer extends UnicodeReader { /** * Return style of comment. + * LINE starting with // + * BLOCK starting with /* + * JAVADOC starting with /** * - * @return style of comment. + * @return */ public CommentStyle getStyle() { return cs; @@ -1255,110 +1273,76 @@ public class JavaTokenizer extends UnicodeReader { * @return true if comment contains @deprecated. */ public boolean isDeprecated() { - if (!scanned) { + if (!scanned && cs == CommentStyle.JAVADOC) { scanDocComment(); } + return deprecatedFlag; } /** - * Remove closing star(s) slash from comment. - * - * @param line line reader - * - * @return new line reader if detected otherwise original line reader. + * Scan JAVADOC comment for details. */ - UnicodeReader trimEndOfComment(UnicodeReader line) { - int pos = line.position(); - boolean allWhitespace = true; - - while (line.isAvailable()) { - int endPos = line.position(); + protected void scanDocComment() { + try { + boolean deprecatedPrefix = false; + accept("/**"); - if (line.skip('*') != 0 && line.is('/')) { - return line.lineReader(allWhitespace ? endPos : pos, endPos); - } else { - allWhitespace = allWhitespace && line.isWhitespace(); - line.next(); - } - } + forEachLine: + while (isAvailable()) { + // Skip optional WhiteSpace at beginning of line + skipWhitespace(); - line.reset(pos); + // Skip optional consecutive Stars + while (accept('*')) { + if (is('/')) { + return; + } + } - return line; - } + // Skip optional WhiteSpace after Stars + skipWhitespace(); - /** - * Trim the first part of the JavaDoc comment. - * - * @param line line reader - * - * @return modified line reader - */ - UnicodeReader trimJavadocComment(UnicodeReader line) { - line = trimEndOfComment(line); - int pos = line.position(); - line.skipWhitespace(); + // At beginning of line in the JavaDoc sense. + deprecatedPrefix = deprecatedFlag || accept("@deprecated"); - if (!line.isAvailable()) { - return line; - } + if (deprecatedPrefix && isAvailable()) { + if (Character.isWhitespace(get())) { + deprecatedFlag = true; + } else if (accept('*')) { + if (is('/')) { + deprecatedFlag = true; + return; + } + } + } - if (line.skip('*') == 0) { - line.reset(pos); - } + // Skip rest of line + while (isAvailable()) { + switch (get()) { + case '*': + next(); - return line; - } + if (is('/')) { + return; + } - /** - * Put the line into the buffer. - * - * @param line line reader - */ - protected void putLine(UnicodeReader line) { - // ignore, overridden in subclass - } + break; + case '\r': // (Spec 3.4) + case '\n': // (Spec 3.4) + accept('\r'); + accept('\n'); + continue forEachLine; - /** - * Scan document comment for content. - */ - protected void scanDocComment() { - if (!scanned) { - deprecatedFlag = false; + default: + next(); + break; + } + } // rest of line + } // forEachLine + return; + } finally { scanned = true; - - if (!accept("/**")) { - return; - } - - skip('*'); - skipWhitespace(); - - if (isEOLN()) { - accept('\r'); - accept('\n'); - } - - while (isAvailable()) { - UnicodeReader line = lineReader(); - line = trimJavadocComment(line); - - // If standalone @deprecated tag - int pos = line.position(); - line.skipWhitespace(); - - if (line.accept("@deprecated") && - (!line.isAvailable() || - line.isWhitespace() || - line.isEOLN() || - line.get() == EOI)) { - deprecatedFlag = true; - } - - line.reset(pos); - putLine(line); - } } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java index 4cd0e1c2fcd..748f0d9875e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java @@ -79,7 +79,8 @@ public class JavadocTokenizer extends JavaTokenizer { @Override protected Comment processComment(int pos, int endPos, CommentStyle style) { - return new JavadocComment(style, this, pos, endPos); + char[] buf = getRawCharacters(pos, endPos); + return new JavadocComment(style, fac, buf, pos); } /** @@ -87,6 +88,13 @@ public class JavadocTokenizer extends JavaTokenizer { * of a Javadoc comment. */ protected static class JavadocComment extends BasicComment { + /** + * Pattern used to detect a well formed @deprecated tag in a Javadoc + * comment. + */ + private static final Pattern DEPRECATED_PATTERN = + Pattern.compile("(?sm).*^\\s*@deprecated( |$).*"); + /** * The relevant portion of the comment that is of interest to Javadoc. * Produced by invoking scanDocComment. @@ -98,50 +106,51 @@ public class JavadocTokenizer extends JavaTokenizer { */ private final StringBuilder sb; - /** - * Indicates if newline is required. - */ - private boolean firstLine = true; - /** * Map used to map the extracted Javadoc comment's character positions back to * the original source. */ OffsetMap offsetMap = new OffsetMap(); - JavadocComment(CommentStyle cs, UnicodeReader reader, int pos, int endPos) { - super(cs, reader, pos, endPos); + JavadocComment(CommentStyle cs, ScannerFactory sf, char[] array, int offset) { + super( cs, sf, array, offset); this.sb = new StringBuilder(); } /** - * Add current character or code point from line to the extraction buffer. + * Add a character to the extraction buffer. * - * @param line line reader + * @param ch character to add. */ - protected void putLine(UnicodeReader line) { - if (firstLine) { - firstLine = false; - } else { - sb.append('\n'); - offsetMap.add(sb.length(), line.position()); - } - while (line.isAvailable()) { - offsetMap.add(sb.length(), line.position()); + protected void put(char ch) { + offsetMap.add(sb.length(), offsetPosition()); + sb.append(ch); + } - if (line.isSurrogate()) { - sb.appendCodePoint(line.getCodepoint()); - } else { - sb.append(line.get()); - } + /** + * Add a code point to the extraction buffer. + * + * @param codePoint code point to add. + */ + protected void putCodePoint(int codePoint) { + offsetMap.add(sb.length(), offsetPosition()); + sb.appendCodePoint(codePoint); + } - line.next(); + /** + * Add current character or code point to the extraction buffer. + */ + protected void put() { + if (isSurrogate()) { + putCodePoint(getCodepoint()); + } else { + put(get()); } } @Override public String getText() { - if (!scanned) { + if (!scanned && cs == CommentStyle.JAVADOC) { scanDocComment(); } return docComment; @@ -162,10 +171,104 @@ public class JavadocTokenizer extends JavaTokenizer { @Override protected void scanDocComment() { - try { - super.scanDocComment(); + try { + boolean firstLine = true; + + // Skip over /* + accept("/*"); + + // Consume any number of stars + skip('*'); + + // Is the comment in the form /**/, /***/, /****/, etc. ? + if (is('/')) { + docComment = ""; + return; + } + + // Skip line terminator on the first line of the comment. + if (isOneOf('\n', '\r')) { + accept('\r'); + accept('\n'); + firstLine = false; + } + + outerLoop: + // The outerLoop processes the doc comment, looping once + // for each line. For each line, it first strips off + // whitespace, then it consumes any stars, then it + // puts the rest of the line into the extraction buffer. + while (isAvailable()) { + int begin_pos = position(); + // Consume whitespace from the beginning of each line. + skipWhitespace(); + // Are there stars here? If so, consume them all + // and check for the end of comment. + if (is('*')) { + // skip all of the stars + skip('*'); + + // check for the closing slash. + if (accept('/')) { + // We're done with the Javadoc comment + break outerLoop; + } + } else if (!firstLine) { + // The current line does not begin with a '*' so we will + // treat it as comment + reset(begin_pos); + } + + textLoop: + // The textLoop processes the rest of the characters + // on the line, adding them to the extraction buffer. + while (isAvailable()) { + if (accept("*/")) { + // This is the end of the comment, return + // the contents of the extraction buffer. + break outerLoop; + } else if (isOneOf('\n', '\r')) { + // We've seen a newline. Add it to our + // buffer and break out of this loop, + // starting fresh on a new line. + put('\n'); + accept('\r'); + accept('\n'); + break textLoop; + } else if (is('\f')){ + next(); + break textLoop; // treat as end of line + + } else { + // Add the character to our buffer. + put(); + next(); + } + } // end textLoop + firstLine = false; + } // end outerLoop + + // If extraction buffer is not empty. + if (sb.length() > 0) { + // Remove trailing asterisks. + int i = sb.length() - 1; + while (i > -1 && sb.charAt(i) == '*') { + i--; + } + sb.setLength(i + 1) ; + + // Store the text of the doc comment + docComment = sb.toString(); + } else { + docComment = ""; + } } finally { - docComment = sb.toString(); + scanned = true; + + // Check if comment contains @deprecated comment. + if (docComment != null && DEPRECATED_PATTERN.matcher(docComment).matches()) { + deprecatedFlag = true; + } } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java index e513cab734c..c5924c44aa3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java @@ -273,9 +273,9 @@ public class Tokens { public interface Comment { enum CommentStyle { - LINE, // Starting with // - BLOCK, // starting with /* - JAVADOC, // starting with /** + LINE, + BLOCK, + JAVADOC, } String getText(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java index 62a0b224927..c21d08e9d86 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/UnicodeReader.java @@ -104,39 +104,15 @@ public class UnicodeReader { */ @SuppressWarnings("this-escape") protected UnicodeReader(ScannerFactory sf, char[] array, int length) { - this(sf.log, array, length); - } - - /** - * Constructor. - * - * @param log Log for error reporting. - * @param array array containing contents of source. - * @param length length of meaningful content in buffer. - */ - protected UnicodeReader(Log log, char[] array, int length) { - this(log, array, 0, length); - } - - /** - * Constructor. - * - * @param log Log for error reporting. - * @param array array containing contents of source. - * @param pos start of meaningful content in buffer. - * @param endPos end of meaningful content in buffer. - */ - @SuppressWarnings("this-escape") - protected UnicodeReader(Log log, char[] array, int pos, int endPos) { this.buffer = array; - this.length = endPos; - this.position = pos; + this.length = length; + this.position = 0; this.width = 0; this.character = '\0'; this.codepoint = 0; this.wasBackslash = false; this.wasUnicodeEscape = false; - this.log = log; + this.log = sf.log; nextCodePoint(); } @@ -450,68 +426,25 @@ public class UnicodeReader { return false; } - /** - * Match one of the arguments and advance if a match. Returns true if a match. - */ protected boolean acceptOneOf(char ch1, char ch2, char ch3) { if (isOneOf(ch1, ch2, ch3)) { next(); return true; } - return false; - } - - /** - * Return a reader which is bracketed by the currect position - * and the next line terminator. - * - * @return a new reader - */ - protected UnicodeReader lineReader() { - int pos = position; - skipToEOLN(); - int endPos = position; - accept('\r'); - accept('\n'); - return lineReader(pos, endPos); - } - /** - * Return a reader which is bracketed by the {@code pos} - * and {@code endPos}. - * - * @param pos initial position - * @param endPos end position - * - * @return a new reader - */ - protected UnicodeReader lineReader(int pos, int endPos) { - return new UnicodeReader(log, buffer, pos, endPos); + return false; } /** * Skip over all occurrences of character. * * @param ch character to accept. - * - * @return number of characters skipped */ - protected int skip(char ch) { - int count = 0; + protected void skip(char ch) { while (accept(ch)) { - count++; + // next } - return count; - } - - /** - * Is ASCII white space character. - * - * @return true if is ASCII white space character - */ - protected boolean isWhitespace() { - return isOneOf(' ', '\t', '\f'); } /** @@ -523,26 +456,18 @@ public class UnicodeReader { } } - /** - * Is ASCII line terminator. - * - * @return true if is ASCII line terminator. - */ - protected boolean isEOLN() { - return isOneOf('\r', '\n'); - } - /** * Skip to end of line. */ protected void skipToEOLN() { while (isAvailable()) { - if (isEOLN()) { + if (isOneOf('\r', '\n')) { break; } next(); } + } /** @@ -640,41 +565,6 @@ public class UnicodeReader { return Arrays.copyOfRange(buffer, beginIndex, endIndex); } - /** - * Returns a string subset of the input buffer. - * The returned string begins at the {@code beginIndex} and - * extends to the character at index {@code endIndex - 1}. - * Thus the length of the substring is {@code endIndex-beginIndex}. - * This behavior is like - * {@code String.substring(beginIndex, endIndex)}. - * Unicode escape sequences are not translated. - * - * @param beginIndex the beginning index, inclusive. - * @param endIndex the ending index, exclusive. - * - * @throws ArrayIndexOutOfBoundsException if either offset is outside of the - * array bounds - */ - public String getRawString(int beginIndex, int endIndex) { - return new String(buffer, beginIndex, endIndex - beginIndex); - } - - /** - * Returns a string subset of the input buffer. - * The returned string begins at the {@code position} and - * extends to the character at index {@code length - 1}. - * Thus the length of the substring is {@code length-position}. - * This behavior is like - * {@code String.substring(position, length)}. - * Unicode escape sequences are not translated. - * - * @throws ArrayIndexOutOfBoundsException if either offset is outside of the - * array bounds - */ - public String getRawString() { - return getRawString(position, length); - } - /** * This is a specialized version of UnicodeReader that keeps track of the * column position within a given character stream. Used for Javadoc @@ -682,6 +572,11 @@ public class UnicodeReader { * to positions in the source file. */ static class PositionTrackingReader extends UnicodeReader { + /** + * Offset from the beginning of the original reader buffer. + */ + private final int offset; + /** * Current column in the comment. */ @@ -690,12 +585,13 @@ public class UnicodeReader { /** * Constructor. * - * @param reader existing reader - * @param pos start of meaningful content in buffer. - * @param endPos end of meaningful content in buffer. + * @param sf Scan factory. + * @param array Array containing contents of source. + * @param offset Position offset in original source buffer. */ - protected PositionTrackingReader(UnicodeReader reader, int pos, int endPos) { - super(reader.log, reader.buffer, pos, endPos); + protected PositionTrackingReader(ScannerFactory sf, char[] array, int offset) { + super(sf, array, array.length); + this.offset = offset; this.column = 0; } @@ -727,6 +623,15 @@ public class UnicodeReader { protected int column() { return column; } + + /** + * Returns position relative to the original source buffer. + * + * @return + */ + protected int offsetPosition() { + return position() + offset; + } } }