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

Fri, 05 Aug 2011 19:41:05 -0700

author
ksrini
date
Fri, 05 Aug 2011 19:41:05 -0700
changeset 1065
e9f118c2bd3c
parent 554
9d9f26857129
child 1326
30c36e23f154
permissions
-rw-r--r--

7064544: (javadoc) miscellaneous fixes requested by netbeans
Summary: Contributed by netbeans team, modified to suit by the langtools team.
Reviewed-by: jjg, bpatel

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

mercurial