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

Tue, 25 May 2010 15:54:51 -0700

author
ohair
date
Tue, 25 May 2010 15:54:51 -0700
changeset 554
9d9f26857129
parent 229
03bcd66bd8e7
child 1065
e9f118c2bd3c
permissions
-rw-r--r--

6943119: Rebrand source copyright notices
Reviewed-by: darcy

     1 /*
     2  * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.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         @SuppressWarnings("fallthrough")
    78         class CommentStringParser {
    79             /**
    80              * The entry point to the comment string parser
    81              */
    82             void parseCommentStateMachine() {
    83                 final int IN_TEXT = 1;
    84                 final int TAG_GAP = 2;
    85                 final int TAG_NAME = 3;
    86                 int state = TAG_GAP;
    87                 boolean newLine = true;
    88                 String tagName = null;
    89                 int tagStart = 0;
    90                 int textStart = 0;
    91                 int lastNonWhite = -1;
    92                 int len = commentString.length();
    93                 for (int inx = 0; inx < len; ++inx) {
    94                     char ch = commentString.charAt(inx);
    95                     boolean isWhite = Character.isWhitespace(ch);
    96                     switch (state)  {
    97                         case TAG_NAME:
    98                             if (isWhite) {
    99                                 tagName = commentString.substring(tagStart, inx);
   100                                 state = TAG_GAP;
   101                             }
   102                             break;
   103                         case TAG_GAP:
   104                             if (isWhite) {
   105                                 break;
   106                             }
   107                             textStart = inx;
   108                             state = IN_TEXT;
   109                             /* fall thru */
   110                         case IN_TEXT:
   111                             if (newLine && ch == '@') {
   112                                 parseCommentComponent(tagName, textStart,
   113                                                       lastNonWhite+1);
   114                                 tagStart = inx;
   115                                 state = TAG_NAME;
   116                             }
   117                             break;
   118                     };
   119                     if (ch == '\n') {
   120                         newLine = true;
   121                     } else if (!isWhite) {
   122                         lastNonWhite = inx;
   123                         newLine = false;
   124                     }
   125                 }
   126                 // Finish what's currently being processed
   127                 switch (state)  {
   128                     case TAG_NAME:
   129                         tagName = commentString.substring(tagStart, len);
   130                         /* fall thru */
   131                     case TAG_GAP:
   132                         textStart = len;
   133                         /* fall thru */
   134                     case IN_TEXT:
   135                         parseCommentComponent(tagName, textStart, lastNonWhite+1);
   136                         break;
   137                 };
   138             }
   140             /**
   141              * Save away the last parsed item.
   142              */
   143             void parseCommentComponent(String tagName,
   144                                        int from, int upto) {
   145                 String tx = upto <= from ? "" : commentString.substring(from, upto);
   146                 if (tagName == null) {
   147                     text = tx;
   148                 } else {
   149                     TagImpl tag;
   150                     if (tagName.equals("@exception") || tagName.equals("@throws")) {
   151                         warnIfEmpty(tagName, tx);
   152                         tag = new ThrowsTagImpl(holder, tagName, tx);
   153                     } else if (tagName.equals("@param")) {
   154                         warnIfEmpty(tagName, tx);
   155                         tag = new ParamTagImpl(holder, tagName, tx);
   156                     } else if (tagName.equals("@see")) {
   157                         warnIfEmpty(tagName, tx);
   158                         tag = new SeeTagImpl(holder, tagName, tx);
   159                     } else if (tagName.equals("@serialField")) {
   160                         warnIfEmpty(tagName, tx);
   161                         tag = new SerialFieldTagImpl(holder, tagName, tx);
   162                     } else if (tagName.equals("@return")) {
   163                         warnIfEmpty(tagName, tx);
   164                         tag = new TagImpl(holder, tagName, tx);
   165                     } else if (tagName.equals("@author")) {
   166                         warnIfEmpty(tagName, tx);
   167                         tag = new TagImpl(holder, tagName, tx);
   168                     } else if (tagName.equals("@version")) {
   169                         warnIfEmpty(tagName, tx);
   170                         tag = new TagImpl(holder, tagName, tx);
   171                     } else {
   172                         tag = new TagImpl(holder, tagName, tx);
   173                     }
   174                     tagList.append(tag);
   175                 }
   176             }
   178             void warnIfEmpty(String tagName, String tx) {
   179                 if (tx.length() == 0) {
   180                     docenv.warning(holder, "tag.tag_has_no_arguments", tagName);
   181                 }
   182             }
   184         }
   186         new CommentStringParser().parseCommentStateMachine();
   187     }
   189     /**
   190      * Return the text of the comment.
   191      */
   192     String commentText() {
   193         return text;
   194     }
   196     /**
   197      * Return all tags in this comment.
   198      */
   199     Tag[] tags() {
   200         return tagList.toArray(new Tag[tagList.length()]);
   201     }
   203     /**
   204      * Return tags of the specified kind in this comment.
   205      */
   206     Tag[] tags(String tagname) {
   207         ListBuffer<Tag> found = new ListBuffer<Tag>();
   208         String target = tagname;
   209         if (target.charAt(0) != '@') {
   210             target = "@" + target;
   211         }
   212         for (Tag tag : tagList) {
   213             if (tag.kind().equals(target)) {
   214                 found.append(tag);
   215             }
   216         }
   217         return found.toArray(new Tag[found.length()]);
   218     }
   220     /**
   221      * Return throws tags in this comment.
   222      */
   223     ThrowsTag[] throwsTags() {
   224         ListBuffer<ThrowsTag> found = new ListBuffer<ThrowsTag>();
   225         for (Tag next : tagList) {
   226             if (next instanceof ThrowsTag) {
   227                 found.append((ThrowsTag)next);
   228             }
   229         }
   230         return found.toArray(new ThrowsTag[found.length()]);
   231     }
   233     /**
   234      * Return param tags (excluding type param tags) in this comment.
   235      */
   236     ParamTag[] paramTags() {
   237         return paramTags(false);
   238     }
   240     /**
   241      * Return type param tags in this comment.
   242      */
   243     ParamTag[] typeParamTags() {
   244         return paramTags(true);
   245     }
   247     /**
   248      * Return param tags in this comment.  If typeParams is true
   249      * include only type param tags, otherwise include only ordinary
   250      * param tags.
   251      */
   252     private ParamTag[] paramTags(boolean typeParams) {
   253         ListBuffer<ParamTag> found = new ListBuffer<ParamTag>();
   254         for (Tag next : tagList) {
   255             if (next instanceof ParamTag) {
   256                 ParamTag p = (ParamTag)next;
   257                 if (typeParams == p.isTypeParameter()) {
   258                     found.append(p);
   259                 }
   260             }
   261         }
   262         return found.toArray(new ParamTag[found.length()]);
   263     }
   265     /**
   266      * Return see also tags in this comment.
   267      */
   268     SeeTag[] seeTags() {
   269         ListBuffer<SeeTag> found = new ListBuffer<SeeTag>();
   270         for (Tag next : tagList) {
   271             if (next instanceof SeeTag) {
   272                 found.append((SeeTag)next);
   273             }
   274         }
   275         return found.toArray(new SeeTag[found.length()]);
   276     }
   278     /**
   279      * Return serialField tags in this comment.
   280      */
   281     SerialFieldTag[] serialFieldTags() {
   282         ListBuffer<SerialFieldTag> found = new ListBuffer<SerialFieldTag>();
   283         for (Tag next : tagList) {
   284             if (next instanceof SerialFieldTag) {
   285                 found.append((SerialFieldTag)next);
   286             }
   287         }
   288         return found.toArray(new SerialFieldTag[found.length()]);
   289     }
   291     /**
   292      * Return array of tags with text and inline See Tags for a Doc comment.
   293      */
   294     static Tag[] getInlineTags(DocImpl holder, String inlinetext) {
   295         ListBuffer<Tag> taglist = new ListBuffer<Tag>();
   296         int delimend = 0, textstart = 0, len = inlinetext.length();
   297         DocEnv docenv = holder.env;
   299         if (len == 0) {
   300             return taglist.toArray(new Tag[taglist.length()]);
   301         }
   302         while (true) {
   303             int linkstart;
   304             if ((linkstart = inlineTagFound(holder, inlinetext,
   305                                             textstart)) == -1) {
   306                 taglist.append(new TagImpl(holder, "Text",
   307                                            inlinetext.substring(textstart)));
   308                 break;
   309             } else {
   310                 int seetextstart = linkstart;
   311                 for (int i = linkstart; i < inlinetext.length(); i++) {
   312                     char c = inlinetext.charAt(i);
   313                     if (Character.isWhitespace(c) ||
   314                         c == '}') {
   315                         seetextstart = i;
   316                         break;
   317                      }
   318                 }
   319                 String linkName = inlinetext.substring(linkstart+2, seetextstart);
   320                 //Move past the white space after the inline tag name.
   321                 while (Character.isWhitespace(inlinetext.
   322                                                   charAt(seetextstart))) {
   323                     if (inlinetext.length() <= seetextstart) {
   324                         taglist.append(new TagImpl(holder, "Text",
   325                                                    inlinetext.substring(textstart, seetextstart)));
   326                         docenv.warning(holder,
   327                                        "tag.Improper_Use_Of_Link_Tag",
   328                                        inlinetext);
   329                         return taglist.toArray(new Tag[taglist.length()]);
   330                     } else {
   331                         seetextstart++;
   332                     }
   333                 }
   334                 taglist.append(new TagImpl(holder, "Text",
   335                                            inlinetext.substring(textstart, linkstart)));
   336                 textstart = seetextstart;   // this text is actually seetag
   337                 if ((delimend = findInlineTagDelim(inlinetext, textstart)) == -1) {
   338                     //Missing closing '}' character.
   339                     // store the text as it is with the {@link.
   340                     taglist.append(new TagImpl(holder, "Text",
   341                                                inlinetext.substring(textstart)));
   342                     docenv.warning(holder,
   343                                    "tag.End_delimiter_missing_for_possible_SeeTag",
   344                                    inlinetext);
   345                     return taglist.toArray(new Tag[taglist.length()]);
   346                 } else {
   347                     //Found closing '}' character.
   348                     if (linkName.equals("see")
   349                            || linkName.equals("link")
   350                            || linkName.equals("linkplain")) {
   351                         taglist.append( new SeeTagImpl(holder, "@" + linkName,
   352                               inlinetext.substring(textstart, delimend)));
   353                     } else {
   354                         taglist.append( new TagImpl(holder, "@" + linkName,
   355                               inlinetext.substring(textstart, delimend)));
   356                     }
   357                     textstart = delimend + 1;
   358                 }
   359             }
   360             if (textstart == inlinetext.length()) {
   361                 break;
   362             }
   363         }
   364         return taglist.toArray(new Tag[taglist.length()]);
   365     }
   367     /**
   368      * Recursively find the index of the closing '}' character for an inline tag
   369      * and return it.  If it can't be found, return -1.
   370      * @param inlineText the text to search in.
   371      * @param searchStart the index of the place to start searching at.
   372      * @return the index of the closing '}' character for an inline tag.
   373      * If it can't be found, return -1.
   374      */
   375     private static int findInlineTagDelim(String inlineText, int searchStart) {
   376         int delimEnd, nestedOpenBrace;
   377         if ((delimEnd = inlineText.indexOf("}", searchStart)) == -1) {
   378             return -1;
   379         } else if (((nestedOpenBrace = inlineText.indexOf("{", searchStart)) != -1) &&
   380             nestedOpenBrace < delimEnd){
   381             //Found a nested open brace.
   382             int nestedCloseBrace = findInlineTagDelim(inlineText, nestedOpenBrace + 1);
   383             return (nestedCloseBrace != -1) ?
   384                 findInlineTagDelim(inlineText, nestedCloseBrace + 1) :
   385                 -1;
   386         } else {
   387             return delimEnd;
   388         }
   389     }
   391     /**
   392      * Recursively search for the string "{@" followed by
   393      * name of inline tag and white space,
   394      * if found
   395      *    return the index of the text following the white space.
   396      * else
   397      *    return -1.
   398      */
   399     private static int inlineTagFound(DocImpl holder,  String inlinetext, int start) {
   400         DocEnv docenv = holder.env;
   401         int linkstart;
   402         if (start == inlinetext.length() ||
   403               (linkstart = inlinetext.indexOf("{@", start)) == -1) {
   404             return -1;
   405         } else if(inlinetext.indexOf('}', start) == -1) {
   406             //Missing '}'.
   407             docenv.warning(holder, "tag.Improper_Use_Of_Link_Tag",
   408                           inlinetext.substring(linkstart, inlinetext.length()));
   409             return -1;
   410         } else {
   411             return linkstart;
   412         }
   413     }
   416     /**
   417      * Return array of tags for the locale specific first sentence in the text.
   418      */
   419     static Tag[] firstSentenceTags(DocImpl holder, String text) {
   420         DocLocale doclocale = holder.env.doclocale;
   421         return getInlineTags(holder,
   422                              doclocale.localeSpecificFirstSentence(holder, text));
   423     }
   425     /**
   426      * Return text for this Doc comment.
   427      */
   428     public String toString() {
   429         return text;
   430     }
   431 }

mercurial