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

Mon, 25 Mar 2013 16:55:14 -0700

author
mfang
date
Mon, 25 Mar 2013 16:55:14 -0700
changeset 1658
fdf30b225e1c
parent 1359
25e14ad23cef
child 1722
38c4bade0ec1
permissions
-rw-r--r--

8010521: jdk8 l10n resource file translation update 2
Reviewed-by: naoto, yhuang

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

mercurial