1 /*
   2  * Copyright (c) 1997, 2015, 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  */
  25 
  26 package com.sun.tools.doclets.formats.html;
  27 
  28 import java.io.*;
  29 
  30 import com.sun.javadoc.*;
  31 import com.sun.tools.doclets.formats.html.markup.*;
  32 import com.sun.tools.doclets.internal.toolkit.*;
  33 import com.sun.tools.doclets.internal.toolkit.util.*;
  34 import com.sun.tools.javac.util.StringUtils;
  35 
  36 /**
  37  * Writes method documentation in HTML format.
  38  *
  39  *  <p><b>This is NOT part of any supported API.
  40  *  If you write code that depends on this, you do so at your own risk.
  41  *  This code and its internal interfaces are subject to change or
  42  *  deletion without notice.</b>
  43  *
  44  * @author Robert Field
  45  * @author Atul M Dambalkar
  46  * @author Jamie Ho (rewrite)
  47  * @author Bhavesh Patel (Modified)
  48  */
  49 public class MethodWriterImpl extends AbstractExecutableMemberWriter
  50         implements MethodWriter, MemberSummaryWriter {
  51 
  52     /**
  53      * Construct a new MethodWriterImpl.
  54      *
  55      * @param writer the writer for the class that the methods belong to.
  56      * @param classDoc the class being documented.
  57      */
  58     public MethodWriterImpl(SubWriterHolderWriter writer, ClassDoc classDoc) {
  59         super(writer, classDoc);
  60     }
  61 
  62     /**
  63      * Construct a new MethodWriterImpl.
  64      *
  65      * @param writer The writer for the class that the methods belong to.
  66      */
  67     public MethodWriterImpl(SubWriterHolderWriter writer) {
  68         super(writer);
  69     }
  70 
  71     /**
  72      * {@inheritDoc}
  73      */
  74     public Content getMemberSummaryHeader(ClassDoc classDoc,
  75             Content memberSummaryTree) {
  76         memberSummaryTree.addContent(HtmlConstants.START_OF_METHOD_SUMMARY);
  77         Content memberTree = writer.getMemberTreeHeader();
  78         writer.addSummaryHeader(this, classDoc, memberTree);
  79         return memberTree;
  80     }
  81 
  82     /**
  83      * {@inheritDoc}
  84      */
  85     public void addMemberTree(Content memberSummaryTree, Content memberTree) {
  86         writer.addMemberTree(memberSummaryTree, memberTree);
  87     }
  88 
  89     /**
  90      * {@inheritDoc}
  91      */
  92     public Content getMethodDetailsTreeHeader(ClassDoc classDoc,
  93             Content memberDetailsTree) {
  94         memberDetailsTree.addContent(HtmlConstants.START_OF_METHOD_DETAILS);
  95         Content methodDetailsTree = writer.getMemberTreeHeader();
  96         methodDetailsTree.addContent(writer.getMarkerAnchor(
  97                 SectionName.METHOD_DETAIL));
  98         Content heading = HtmlTree.HEADING(HtmlConstants.DETAILS_HEADING,
  99                 writer.methodDetailsLabel);
 100         methodDetailsTree.addContent(heading);
 101         return methodDetailsTree;
 102     }
 103 
 104     /**
 105      * {@inheritDoc}
 106      */
 107     public Content getMethodDocTreeHeader(MethodDoc method,
 108             Content methodDetailsTree) {
 109         String erasureAnchor;
 110         if ((erasureAnchor = getErasureAnchor(method)) != null) {
 111             methodDetailsTree.addContent(writer.getMarkerAnchor((erasureAnchor)));
 112         }
 113         methodDetailsTree.addContent(
 114                 writer.getMarkerAnchor(writer.getAnchor(method)));
 115         Content methodDocTree = writer.getMemberTreeHeader();
 116         Content heading = new HtmlTree(HtmlConstants.MEMBER_HEADING);
 117         heading.addContent(method.name());
 118         methodDocTree.addContent(heading);
 119         return methodDocTree;
 120     }
 121 
 122     /**
 123      * Get the signature for the given method.
 124      *
 125      * @param method the method being documented.
 126      * @return a content object for the signature
 127      */
 128     public Content getSignature(MethodDoc method) {
 129         Content pre = new HtmlTree(HtmlTag.PRE);
 130         writer.addAnnotationInfo(method, pre);
 131         int annotationLength = pre.charCount();
 132         addModifiers(method, pre);
 133         addTypeParameters(method, pre);
 134         addReturnType(method, pre);
 135         if (configuration.linksource) {
 136             Content methodName = new StringContent(method.name());
 137             writer.addSrcLink(method, methodName, pre);
 138         } else {
 139             addName(method.name(), pre);
 140         }
 141         int indent = pre.charCount() - annotationLength;
 142         addParameters(method, pre, indent);
 143         addExceptions(method, pre, indent);
 144         return pre;
 145     }
 146 
 147     /**
 148      * {@inheritDoc}
 149      */
 150     public void addDeprecated(MethodDoc method, Content methodDocTree) {
 151         addDeprecatedInfo(method, methodDocTree);
 152     }
 153 
 154     /**
 155      * {@inheritDoc}
 156      */
 157     public void addComments(Type holder, MethodDoc method, Content methodDocTree) {
 158         ClassDoc holderClassDoc = holder.asClassDoc();
 159         if (method.inlineTags().length > 0) {
 160             if (holder.asClassDoc().equals(classdoc) ||
 161                     (! (holderClassDoc.isPublic() ||
 162                     utils.isLinkable(holderClassDoc, configuration)))) {
 163                 writer.addInlineComment(method, methodDocTree);
 164             } else {
 165                 Content link =
 166                         writer.getDocLink(LinkInfoImpl.Kind.METHOD_DOC_COPY,
 167                         holder.asClassDoc(), method,
 168                         holder.asClassDoc().isIncluded() ?
 169                             holder.typeName() : holder.qualifiedTypeName(),
 170                             false);
 171                 Content codelLink = HtmlTree.CODE(link);
 172                 Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, holder.asClassDoc().isClass()?
 173                     writer.descfrmClassLabel : writer.descfrmInterfaceLabel);
 174                 descfrmLabel.addContent(writer.getSpace());
 175                 descfrmLabel.addContent(codelLink);
 176                 methodDocTree.addContent(HtmlTree.DIV(HtmlStyle.block, descfrmLabel));
 177                 writer.addInlineComment(method, methodDocTree);
 178             }
 179         }
 180     }
 181 
 182     /**
 183      * {@inheritDoc}
 184      */
 185     public void addTags(MethodDoc method, Content methodDocTree) {
 186         writer.addTagsInfo(method, methodDocTree);
 187     }
 188 
 189     /**
 190      * {@inheritDoc}
 191      */
 192     public Content getMethodDetails(Content methodDetailsTree) {
 193         if (configuration.allowTag(HtmlTag.SECTION)) {
 194             HtmlTree htmlTree = HtmlTree.SECTION(getMemberTree(methodDetailsTree));
 195             return htmlTree;
 196         }
 197         return getMemberTree(methodDetailsTree);
 198     }
 199 
 200     /**
 201      * {@inheritDoc}
 202      */
 203     public Content getMethodDoc(Content methodDocTree,
 204             boolean isLastContent) {
 205         return getMemberTree(methodDocTree, isLastContent);
 206     }
 207 
 208     /**
 209      * Close the writer.
 210      */
 211     public void close() throws IOException {
 212         writer.close();
 213     }
 214 
 215     public int getMemberKind() {
 216         return VisibleMemberMap.METHODS;
 217     }
 218 
 219     /**
 220      * {@inheritDoc}
 221      */
 222     public void addSummaryLabel(Content memberTree) {
 223         Content label = HtmlTree.HEADING(HtmlConstants.SUMMARY_HEADING,
 224                 writer.getResource("doclet.Method_Summary"));
 225         memberTree.addContent(label);
 226     }
 227 
 228     /**
 229      * {@inheritDoc}
 230      */
 231     public String getTableSummary() {
 232         return configuration.getText("doclet.Member_Table_Summary",
 233                 configuration.getText("doclet.Method_Summary"),
 234                 configuration.getText("doclet.methods"));
 235     }
 236 
 237     /**
 238      * {@inheritDoc}
 239      */
 240     public Content getCaption() {
 241         return configuration.getResource("doclet.Methods");
 242     }
 243 
 244     /**
 245      * {@inheritDoc}
 246      */
 247     public String[] getSummaryTableHeader(ProgramElementDoc member) {
 248         String[] header = new String[] {
 249             writer.getModifierTypeHeader(),
 250             configuration.getText("doclet.0_and_1",
 251                     configuration.getText("doclet.Method"),
 252                     configuration.getText("doclet.Description"))
 253         };
 254         return header;
 255     }
 256 
 257     /**
 258      * {@inheritDoc}
 259      */
 260     public void addSummaryAnchor(ClassDoc cd, Content memberTree) {
 261         memberTree.addContent(writer.getMarkerAnchor(
 262                 SectionName.METHOD_SUMMARY));
 263     }
 264 
 265     /**
 266      * {@inheritDoc}
 267      */
 268     public void addInheritedSummaryAnchor(ClassDoc cd, Content inheritedTree) {
 269         inheritedTree.addContent(writer.getMarkerAnchor(
 270                 SectionName.METHODS_INHERITANCE, configuration.getClassName(cd)));
 271     }
 272 
 273     /**
 274      * {@inheritDoc}
 275      */
 276     public void addInheritedSummaryLabel(ClassDoc cd, Content inheritedTree) {
 277         Content classLink = writer.getPreQualifiedClassLink(
 278                 LinkInfoImpl.Kind.MEMBER, cd, false);
 279         Content label = new StringContent(cd.isClass() ?
 280             configuration.getText("doclet.Methods_Inherited_From_Class") :
 281             configuration.getText("doclet.Methods_Inherited_From_Interface"));
 282         Content labelHeading = HtmlTree.HEADING(HtmlConstants.INHERITED_SUMMARY_HEADING,
 283                 label);
 284         labelHeading.addContent(writer.getSpace());
 285         labelHeading.addContent(classLink);
 286         inheritedTree.addContent(labelHeading);
 287     }
 288 
 289     /**
 290      * {@inheritDoc}
 291      */
 292     protected void addSummaryType(ProgramElementDoc member, Content tdSummaryType) {
 293         MethodDoc meth = (MethodDoc)member;
 294         addModifierAndType(meth, meth.returnType(), tdSummaryType);
 295     }
 296 
 297     /**
 298      * {@inheritDoc}
 299      */
 300     protected static void addOverridden(HtmlDocletWriter writer,
 301             Type overriddenType, MethodDoc method, Content dl) {
 302         if (writer.configuration.nocomment) {
 303             return;
 304         }
 305         ClassDoc holderClassDoc = overriddenType.asClassDoc();
 306         if (! (holderClassDoc.isPublic() ||
 307             writer.configuration.utils.isLinkable(holderClassDoc, writer.configuration))) {
 308             //This is an implementation detail that should not be documented.
 309             return;
 310         }
 311         if (overriddenType.asClassDoc().isIncluded() && ! method.isIncluded()) {
 312             //The class is included but the method is not.  That means that it
 313             //is not visible so don't document this.
 314             return;
 315         }
 316         Content label = writer.overridesLabel;
 317         LinkInfoImpl.Kind context = LinkInfoImpl.Kind.METHOD_OVERRIDES;
 318 
 319         if (method != null) {
 320             if (overriddenType.asClassDoc().isAbstract() && method.isAbstract()){
 321                 //Abstract method is implemented from abstract class,
 322                 //not overridden
 323                 label = writer.specifiedByLabel;
 324                 context = LinkInfoImpl.Kind.METHOD_SPECIFIED_BY;
 325             }
 326             Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, label));
 327             dl.addContent(dt);
 328             Content overriddenTypeLink =
 329                     writer.getLink(new LinkInfoImpl(writer.configuration, context, overriddenType));
 330             Content codeOverridenTypeLink = HtmlTree.CODE(overriddenTypeLink);
 331             String name = method.name();
 332             Content methlink = writer.getLink(
 333                     new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER,
 334                     overriddenType.asClassDoc())
 335                     .where(writer.getName(writer.getAnchor(method))).label(name));
 336             Content codeMethLink = HtmlTree.CODE(methlink);
 337             Content dd = HtmlTree.DD(codeMethLink);
 338             dd.addContent(writer.getSpace());
 339             dd.addContent(writer.getResource("doclet.in_class"));
 340             dd.addContent(writer.getSpace());
 341             dd.addContent(codeOverridenTypeLink);
 342             dl.addContent(dd);
 343         }
 344     }
 345 
 346     /**
 347      * {@inheritDoc}
 348      */
 349     protected static void addImplementsInfo(HtmlDocletWriter writer,
 350             MethodDoc method, Content dl) {
 351         if(writer.configuration.nocomment){
 352             return;
 353         }
 354         ImplementedMethods implementedMethodsFinder =
 355                 new ImplementedMethods(method, writer.configuration);
 356         MethodDoc[] implementedMethods = implementedMethodsFinder.build();
 357         for (MethodDoc implementedMeth : implementedMethods) {
 358             Type intfac = implementedMethodsFinder.getMethodHolder(implementedMeth);
 359             Content intfaclink = writer.getLink(new LinkInfoImpl(
 360                     writer.configuration, LinkInfoImpl.Kind.METHOD_SPECIFIED_BY, intfac));
 361             Content codeIntfacLink = HtmlTree.CODE(intfaclink);
 362             Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, writer.specifiedByLabel));
 363             dl.addContent(dt);
 364             Content methlink = writer.getDocLink(
 365                     LinkInfoImpl.Kind.MEMBER, implementedMeth,
 366                     implementedMeth.name(), false);
 367             Content codeMethLink = HtmlTree.CODE(methlink);
 368             Content dd = HtmlTree.DD(codeMethLink);
 369             dd.addContent(writer.getSpace());
 370             dd.addContent(writer.getResource("doclet.in_interface"));
 371             dd.addContent(writer.getSpace());
 372             dd.addContent(codeIntfacLink);
 373             dl.addContent(dd);
 374         }
 375     }
 376 
 377     /**
 378      * Add the return type.
 379      *
 380      * @param method the method being documented.
 381      * @param htmltree the content tree to which the return type will be added
 382      */
 383     protected void addReturnType(MethodDoc method, Content htmltree) {
 384         Type type = method.returnType();
 385         if (type != null) {
 386             Content linkContent = writer.getLink(
 387                     new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RETURN_TYPE, type));
 388             htmltree.addContent(linkContent);
 389             htmltree.addContent(writer.getSpace());
 390         }
 391     }
 392 
 393     /**
 394      * {@inheritDoc}
 395      */
 396     protected Content getNavSummaryLink(ClassDoc cd, boolean link) {
 397         if (link) {
 398             if (cd == null) {
 399                 return writer.getHyperLink(
 400                         SectionName.METHOD_SUMMARY,
 401                         writer.getResource("doclet.navMethod"));
 402             } else {
 403                 return writer.getHyperLink(
 404                         SectionName.METHODS_INHERITANCE,
 405                         configuration.getClassName(cd), writer.getResource("doclet.navMethod"));
 406             }
 407         } else {
 408             return writer.getResource("doclet.navMethod");
 409         }
 410     }
 411 
 412     /**
 413      * {@inheritDoc}
 414      */
 415     protected void addNavDetailLink(boolean link, Content liNav) {
 416         if (link) {
 417             liNav.addContent(writer.getHyperLink(
 418                     SectionName.METHOD_DETAIL, writer.getResource("doclet.navMethod")));
 419         } else {
 420             liNav.addContent(writer.getResource("doclet.navMethod"));
 421         }
 422     }
 423 }