src/share/classes/com/sun/tools/javadoc/Comment.java

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
9a66ca7c79fa
child 198
b4b1f7732289
permissions
-rw-r--r--

Initial load

     1 /*
     2  * Copyright 1997-2003 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any questions.
    24  */
    26 package com.sun.tools.javadoc;
    28 import java.util.Locale;
    30 import com.sun.javadoc.*;
    32 import com.sun.tools.javac.util.ListBuffer;
    34 /**
    35  * Comment contains all information in comment part.
    36  *      It allows users to get first sentence of this comment, get
    37  *      comment for different tags...
    38  *
    39  * @author Kaiyang Liu (original)
    40  * @author Robert Field (rewrite)
    41  * @author Atul M Dambalkar
    42  * @author Neal Gafter (rewrite)
    43  */
    44 class Comment {
    46     /**
    47      * sorted comments with different tags.
    48      */
    49     private final ListBuffer<Tag> tagList = new ListBuffer<Tag>();
    51     /**
    52      * text minus any tags.
    53      */
    54     private String text;
    56     /**
    57      * Doc environment
    58      */
    59     private final DocEnv docenv;
    61     /**
    62      * constructor of Comment.
    63      */
    64     Comment(final DocImpl holder, final String commentString) {
    65         this.docenv = holder.env;
    67         /**
    68          * Separate the comment into the text part and zero to N tags.
    69          * Simple state machine is in one of three states:
    70          * <pre>
    71          * IN_TEXT: parsing the comment text or tag text.
    72          * TAG_NAME: parsing the name of a tag.
    73          * TAG_GAP: skipping through the gap between the tag name and
    74          * the tag text.
    75          * </pre>
    76          */
    77         class CommentStringParser {
    78             /**
    79              * The entry point to the comment string parser
    80              */
    81             void parseCommentStateMachine() {
    82                 final int IN_TEXT = 1;
    83                 final int TAG_GAP = 2;
    84                 final int TAG_NAME = 3;
    85                 int state = TAG_GAP;
    86                 boolean newLine = true;
    87                 String tagName = null;
    88                 int tagStart = 0;
    89                 int textStart = 0;
    90                 int lastNonWhite = -1;
    91                 int len = commentString.length();
    92                 for (int inx = 0; inx < len; ++inx) {
    93                     char ch = commentString.charAt(inx);
    94                     boolean isWhite = Character.isWhitespace(ch);
    95                     switch (state)  {
    96                         case TAG_NAME:
    97                             if (isWhite) {
    98                                 tagName = commentString.substring(tagStart, inx);
    99                                 state = TAG_GAP;
   100                             }
   101                             break;
   102                         case TAG_GAP:
   103                             if (isWhite) {
   104                                 break;
   105                             }
   106                             textStart = inx;
   107                             state = IN_TEXT;
   108                             /* fall thru */
   109                         case IN_TEXT:
   110                             if (newLine && ch == '@') {
   111                                 parseCommentComponent(tagName, textStart,
   112                                                       lastNonWhite+1);
   113                                 tagStart = inx;
   114                                 state = TAG_NAME;
   115                             }
   116                             break;
   117                     };
   118                     if (ch == '\n') {
   119                         newLine = true;
   120                     } else if (!isWhite) {
   121                         lastNonWhite = inx;
   122                         newLine = false;
   123                     }
   124                 }
   125                 // Finish what's currently being processed
   126                 switch (state)  {
   127                     case TAG_NAME:
   128                         tagName = commentString.substring(tagStart, len);
   129                         /* fall thru */
   130                     case TAG_GAP:
   131                         textStart = len;
   132                         /* fall thru */
   133                     case IN_TEXT:
   134                         parseCommentComponent(tagName, textStart, lastNonWhite+1);
   135                         break;
   136                 };
   137             }
   139             /**
   140              * Save away the last parsed item.
   141              */
   142             void parseCommentComponent(String tagName,
   143                                        int from, int upto) {
   144                 String tx = upto <= from ? "" : commentString.substring(from, upto);
   145                 if (tagName == null) {
   146                     text = tx;
   147                 } else {
   148                     TagImpl tag;
   149                     if (tagName.equals("@exception") || tagName.equals("@throws")) {
   150                         warnIfEmpty(tagName, tx);
   151                         tag = new ThrowsTagImpl(holder, tagName, tx);
   152                     } else if (tagName.equals("@param")) {
   153                         warnIfEmpty(tagName, tx);
   154                         tag = new ParamTagImpl(holder, tagName, tx);
   155                     } else if (tagName.equals("@see")) {
   156                         warnIfEmpty(tagName, tx);
   157                         tag = new SeeTagImpl(holder, tagName, tx);
   158                     } else if (tagName.equals("@serialField")) {
   159                         warnIfEmpty(tagName, tx);
   160                         tag = new SerialFieldTagImpl(holder, tagName, tx);
   161                     } else if (tagName.equals("@return")) {
   162                         warnIfEmpty(tagName, tx);
   163                         tag = new TagImpl(holder, tagName, tx);
   164                     } else if (tagName.equals("@author")) {
   165                         warnIfEmpty(tagName, tx);
   166                         tag = new TagImpl(holder, tagName, tx);
   167                     } else if (tagName.equals("@version")) {
   168                         warnIfEmpty(tagName, tx);
   169                         tag = new TagImpl(holder, tagName, tx);
   170                     } else {
   171                         tag = new TagImpl(holder, tagName, tx);
   172                     }
   173                     tagList.append(tag);
   174                 }
   175             }
   177             void warnIfEmpty(String tagName, String tx) {
   178                 if (tx.length() == 0) {
   179                     docenv.warning(holder, "tag.tag_has_no_arguments", tagName);
   180                 }
   181             }
   183         }
   185         new CommentStringParser().parseCommentStateMachine();
   186     }
   188     /**
   189      * Return the text of the comment.
   190      */
   191     String commentText() {
   192         return text;
   193     }
   195     /**
   196      * Return all tags in this comment.
   197      */
   198     Tag[] tags() {
   199         return tagList.toArray(new Tag[tagList.length()]);
   200     }
   202     /**
   203      * Return tags of the specified kind in this comment.
   204      */
   205     Tag[] tags(String tagname) {
   206         ListBuffer<Tag> found = new ListBuffer<Tag>();
   207         String target = tagname;
   208         if (target.charAt(0) != '@') {
   209             target = "@" + target;
   210         }
   211         for (Tag tag : tagList) {
   212             if (tag.kind().equals(target)) {
   213                 found.append(tag);
   214             }
   215         }
   216         return found.toArray(new Tag[found.length()]);
   217     }
   219     /**
   220      * Return throws tags in this comment.
   221      */
   222     ThrowsTag[] throwsTags() {
   223         ListBuffer<ThrowsTag> found = new ListBuffer<ThrowsTag>();
   224         for (Tag next : tagList) {
   225             if (next instanceof ThrowsTag) {
   226                 found.append((ThrowsTag)next);
   227             }
   228         }
   229         return found.toArray(new ThrowsTag[found.length()]);
   230     }
   232     /**
   233      * Return param tags (excluding type param tags) in this comment.
   234      */
   235     ParamTag[] paramTags() {
   236         return paramTags(false);
   237     }
   239     /**
   240      * Return type param tags in this comment.
   241      */
   242     ParamTag[] typeParamTags() {
   243         return paramTags(true);
   244     }
   246     /**
   247      * Return param tags in this comment.  If typeParams is true
   248      * include only type param tags, otherwise include only ordinary
   249      * param tags.
   250      */
   251     private ParamTag[] paramTags(boolean typeParams) {
   252         ListBuffer<ParamTag> found = new ListBuffer<ParamTag>();
   253         for (Tag next : tagList) {
   254             if (next instanceof ParamTag) {
   255                 ParamTag p = (ParamTag)next;
   256                 if (typeParams == p.isTypeParameter()) {
   257                     found.append(p);
   258                 }
   259             }
   260         }
   261         return found.toArray(new ParamTag[found.length()]);
   262     }
   264     /**
   265      * Return see also tags in this comment.
   266      */
   267     SeeTag[] seeTags() {
   268         ListBuffer<SeeTag> found = new ListBuffer<SeeTag>();
   269         for (Tag next : tagList) {
   270             if (next instanceof SeeTag) {
   271                 found.append((SeeTag)next);
   272             }
   273         }
   274         return found.toArray(new SeeTag[found.length()]);
   275     }
   277     /**
   278      * Return serialField tags in this comment.
   279      */
   280     SerialFieldTag[] serialFieldTags() {
   281         ListBuffer<SerialFieldTag> found = new ListBuffer<SerialFieldTag>();
   282         for (Tag next : tagList) {
   283             if (next instanceof SerialFieldTag) {
   284                 found.append((SerialFieldTag)next);
   285             }
   286         }
   287         return found.toArray(new SerialFieldTag[found.length()]);
   288     }
   290     /**
   291      * Return array of tags with text and inline See Tags for a Doc comment.
   292      */
   293     static Tag[] getInlineTags(DocImpl holder, String inlinetext) {
   294         ListBuffer<Tag> taglist = new ListBuffer<Tag>();
   295         int delimend = 0, textstart = 0, len = inlinetext.length();
   296         DocEnv docenv = holder.env;
   298         if (len == 0) {
   299             return taglist.toArray(new Tag[taglist.length()]);
   300         }
   301         while (true) {
   302             int linkstart;
   303             if ((linkstart = inlineTagFound(holder, inlinetext,
   304                                             textstart)) == -1) {
   305                 taglist.append(new TagImpl(holder, "Text",
   306                                            inlinetext.substring(textstart)));
   307                 break;
   308             } else {
   309                 int seetextstart = linkstart;
   310                 for (int i = linkstart; i < inlinetext.length(); i++) {
   311                     char c = inlinetext.charAt(i);
   312                     if (Character.isWhitespace(c) ||
   313                         c == '}') {
   314                         seetextstart = i;
   315                         break;
   316                      }
   317                 }
   318                 String linkName = inlinetext.substring(linkstart+2, seetextstart);
   319                 //Move past the white space after the inline tag name.
   320                 while (Character.isWhitespace(inlinetext.
   321                                                   charAt(seetextstart))) {
   322                     if (inlinetext.length() <= seetextstart) {
   323                         taglist.append(new TagImpl(holder, "Text",
   324                                                    inlinetext.substring(textstart, seetextstart)));
   325                         docenv.warning(holder,
   326                                        "tag.Improper_Use_Of_Link_Tag",
   327                                        inlinetext);
   328                         return taglist.toArray(new Tag[taglist.length()]);
   329                     } else {
   330                         seetextstart++;
   331                     }
   332                 }
   333                 taglist.append(new TagImpl(holder, "Text",
   334                                            inlinetext.substring(textstart, linkstart)));
   335                 textstart = seetextstart;   // this text is actually seetag
   336                 if ((delimend = findInlineTagDelim(inlinetext, textstart)) == -1) {
   337                     //Missing closing '}' character.
   338                     // store the text as it is with the {@link.
   339                     taglist.append(new TagImpl(holder, "Text",
   340                                                inlinetext.substring(textstart)));
   341                     docenv.warning(holder,
   342                                    "tag.End_delimiter_missing_for_possible_SeeTag",
   343                                    inlinetext);
   344                     return taglist.toArray(new Tag[taglist.length()]);
   345                 } else {
   346                     //Found closing '}' character.
   347                     if (linkName.equals("see")
   348                            || linkName.equals("link")
   349                            || linkName.equals("linkplain")) {
   350                         taglist.append( new SeeTagImpl(holder, "@" + linkName,
   351                               inlinetext.substring(textstart, delimend)));
   352                     } else {
   353                         taglist.append( new TagImpl(holder, "@" + linkName,
   354                               inlinetext.substring(textstart, delimend)));
   355                     }
   356                     textstart = delimend + 1;
   357                 }
   358             }
   359             if (textstart == inlinetext.length()) {
   360                 break;
   361             }
   362         }
   363         return taglist.toArray(new Tag[taglist.length()]);
   364     }
   366     /**
   367      * Recursively find the index of the closing '}' character for an inline tag
   368      * and return it.  If it can't be found, return -1.
   369      * @param inlineText the text to search in.
   370      * @param searchStart the index of the place to start searching at.
   371      * @return the index of the closing '}' character for an inline tag.
   372      * If it can't be found, return -1.
   373      */
   374     private static int findInlineTagDelim(String inlineText, int searchStart) {
   375         int delimEnd, nestedOpenBrace;
   376         if ((delimEnd = inlineText.indexOf("}", searchStart)) == -1) {
   377             return -1;
   378         } else if (((nestedOpenBrace = inlineText.indexOf("{", searchStart)) != -1) &&
   379             nestedOpenBrace < delimEnd){
   380             //Found a nested open brace.
   381             int nestedCloseBrace = findInlineTagDelim(inlineText, nestedOpenBrace + 1);
   382             return (nestedCloseBrace != -1) ?
   383                 findInlineTagDelim(inlineText, nestedCloseBrace + 1) :
   384                 -1;
   385         } else {
   386             return delimEnd;
   387         }
   388     }
   390     /**
   391      * Recursively search for the string "{@" followed by
   392      * name of inline tag and white space,
   393      * if found
   394      *    return the index of the text following the white space.
   395      * else
   396      *    return -1.
   397      */
   398     private static int inlineTagFound(DocImpl holder,  String inlinetext, int start) {
   399         DocEnv docenv = holder.env;
   400         int linkstart;
   401         if (start == inlinetext.length() ||
   402               (linkstart = inlinetext.indexOf("{@", start)) == -1) {
   403             return -1;
   404         } else if(inlinetext.indexOf('}', start) == -1) {
   405             //Missing '}'.
   406             docenv.warning(holder, "tag.Improper_Use_Of_Link_Tag",
   407                           inlinetext.substring(linkstart, inlinetext.length()));
   408             return -1;
   409         } else {
   410             return linkstart;
   411         }
   412     }
   415     /**
   416      * Return array of tags for the locale specific first sentence in the text.
   417      */
   418     static Tag[] firstSentenceTags(DocImpl holder, String text) {
   419         DocLocale doclocale = holder.env.doclocale;
   420         return getInlineTags(holder,
   421                              doclocale.localeSpecificFirstSentence(holder, text));
   422     }
   424     /**
   425      * Return text for this Doc comment.
   426      */
   427     public String toString() {
   428         return text;
   429     }
   430 }

mercurial