/* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.javadoc; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javadoc.*; import com.sun.tools.javac.util.ListBuffer; /** * Comment contains all information in comment part. * It allows users to get first sentence of this comment, get * comment for different tags... * *
This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.
*
* @author Kaiyang Liu (original)
* @author Robert Field (rewrite)
* @author Atul M Dambalkar
* @author Neal Gafter (rewrite)
*/
class Comment {
/**
* sorted comments with different tags.
*/
private final ListBuffer
* IN_TEXT: parsing the comment text or tag text.
* TAG_NAME: parsing the name of a tag.
* TAG_GAP: skipping through the gap between the tag name and
* the tag text.
*
*/
@SuppressWarnings("fallthrough")
class CommentStringParser {
/**
* The entry point to the comment string parser
*/
void parseCommentStateMachine() {
final int IN_TEXT = 1;
final int TAG_GAP = 2;
final int TAG_NAME = 3;
int state = TAG_GAP;
boolean newLine = true;
String tagName = null;
int tagStart = 0;
int textStart = 0;
int lastNonWhite = -1;
int len = commentString.length();
for (int inx = 0; inx < len; ++inx) {
char ch = commentString.charAt(inx);
boolean isWhite = Character.isWhitespace(ch);
switch (state) {
case TAG_NAME:
if (isWhite) {
tagName = commentString.substring(tagStart, inx);
state = TAG_GAP;
}
break;
case TAG_GAP:
if (isWhite) {
break;
}
textStart = inx;
state = IN_TEXT;
/* fall thru */
case IN_TEXT:
if (newLine && ch == '@') {
parseCommentComponent(tagName, textStart,
lastNonWhite+1);
tagStart = inx;
state = TAG_NAME;
}
break;
}
if (ch == '\n') {
newLine = true;
} else if (!isWhite) {
lastNonWhite = inx;
newLine = false;
}
}
// Finish what's currently being processed
switch (state) {
case TAG_NAME:
tagName = commentString.substring(tagStart, len);
/* fall thru */
case TAG_GAP:
textStart = len;
/* fall thru */
case IN_TEXT:
parseCommentComponent(tagName, textStart, lastNonWhite+1);
break;
}
}
/**
* Save away the last parsed item.
*/
void parseCommentComponent(String tagName,
int from, int upto) {
String tx = upto <= from ? "" : commentString.substring(from, upto);
if (tagName == null) {
text = tx;
} else {
TagImpl tag;
if (tagName.equals("@exception") || tagName.equals("@throws")) {
warnIfEmpty(tagName, tx);
tag = new ThrowsTagImpl(holder, tagName, tx);
} else if (tagName.equals("@param")) {
warnIfEmpty(tagName, tx);
tag = new ParamTagImpl(holder, tagName, tx);
} else if (tagName.equals("@see")) {
warnIfEmpty(tagName, tx);
tag = new SeeTagImpl(holder, tagName, tx);
} else if (tagName.equals("@serialField")) {
warnIfEmpty(tagName, tx);
tag = new SerialFieldTagImpl(holder, tagName, tx);
} else if (tagName.equals("@return")) {
warnIfEmpty(tagName, tx);
tag = new TagImpl(holder, tagName, tx);
} else if (tagName.equals("@author")) {
warnIfEmpty(tagName, tx);
tag = new TagImpl(holder, tagName, tx);
} else if (tagName.equals("@version")) {
warnIfEmpty(tagName, tx);
tag = new TagImpl(holder, tagName, tx);
} else {
tag = new TagImpl(holder, tagName, tx);
}
tagList.append(tag);
}
}
void warnIfEmpty(String tagName, String tx) {
if (tx.length() == 0) {
docenv.warning(holder, "tag.tag_has_no_arguments", tagName);
}
}
}
new CommentStringParser().parseCommentStateMachine();
}
/**
* Return the text of the comment.
*/
String commentText() {
return text;
}
/**
* Return all tags in this comment.
*/
Tag[] tags() {
return tagList.toArray(new Tag[tagList.length()]);
}
/**
* Return tags of the specified kind in this comment.
*/
Tag[] tags(String tagname) {
ListBuffer } and {@literal
}. */
private static final Pattern prePat = Pattern.compile("(?i)<(/?)pre>");
private static boolean scanForPre(String inlinetext, int start, int end, boolean inPre) {
Matcher m = prePat.matcher(inlinetext).region(start, end);
while (m.find()) {
inPre = m.group(1).isEmpty();
}
return inPre;
}
/**
* Recursively find the index of the closing '}' character for an inline tag
* and return it. If it can't be found, return -1.
* @param inlineText the text to search in.
* @param searchStart the index of the place to start searching at.
* @return the index of the closing '}' character for an inline tag.
* If it can't be found, return -1.
*/
private static int findInlineTagDelim(String inlineText, int searchStart) {
int delimEnd, nestedOpenBrace;
if ((delimEnd = inlineText.indexOf("}", searchStart)) == -1) {
return -1;
} else if (((nestedOpenBrace = inlineText.indexOf("{", searchStart)) != -1) &&
nestedOpenBrace < delimEnd){
//Found a nested open brace.
int nestedCloseBrace = findInlineTagDelim(inlineText, nestedOpenBrace + 1);
return (nestedCloseBrace != -1) ?
findInlineTagDelim(inlineText, nestedCloseBrace + 1) :
-1;
} else {
return delimEnd;
}
}
/**
* Recursively search for the characters '{', '@', followed by
* name of inline tag and white space,
* if found
* return the index of the text following the white space.
* else
* return -1.
*/
private static int inlineTagFound(DocImpl holder, String inlinetext, int start) {
DocEnv docenv = holder.env;
int linkstart = inlinetext.indexOf("{@", start);
if (start == inlinetext.length() || linkstart == -1) {
return -1;
} else if (inlinetext.indexOf('}', linkstart) == -1) {
//Missing '}'.
docenv.warning(holder, "tag.Improper_Use_Of_Link_Tag",
inlinetext.substring(linkstart, inlinetext.length()));
return -1;
} else {
return linkstart;
}
}
/**
* Return array of tags for the locale specific first sentence in the text.
*/
static Tag[] firstSentenceTags(DocImpl holder, String text) {
DocLocale doclocale = holder.env.doclocale;
return getInlineTags(holder,
doclocale.localeSpecificFirstSentence(holder, text));
}
/**
* Return text for this Doc comment.
*/
@Override
public String toString() {
return text;
}
}