1 /*
   2  * Copyright (c) 1997, 2019, 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 jdk.javadoc.internal.doclets.formats.html;
  27 
  28 import java.util.SortedSet;
  29 import java.util.TreeSet;
  30 
  31 import javax.lang.model.element.Element;
  32 import javax.lang.model.element.ExecutableElement;
  33 import javax.lang.model.element.TypeElement;
  34 import javax.lang.model.type.TypeMirror;
  35 
  36 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
  37 import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
  38 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  39 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  40 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  41 import jdk.javadoc.internal.doclets.formats.html.markup.Table;
  42 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader;
  43 import jdk.javadoc.internal.doclets.toolkit.Content;
  44 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
  45 import jdk.javadoc.internal.doclets.toolkit.MethodWriter;
  46 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  47 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
  48 
  49 /**
  50  * Writes method documentation in HTML format.
  51  *
  52  *  <p><b>This is NOT part of any supported API.
  53  *  If you write code that depends on this, you do so at your own risk.
  54  *  This code and its internal interfaces are subject to change or
  55  *  deletion without notice.</b>
  56  */
  57 public class MethodWriterImpl extends AbstractExecutableMemberWriter
  58         implements MethodWriter, MemberSummaryWriter {
  59 
  60     /**
  61      * Construct a new MethodWriterImpl.
  62      *
  63      * @param writer the writer for the class that the methods belong to.
  64      * @param typeElement the class being documented.
  65      */
  66     public MethodWriterImpl(SubWriterHolderWriter writer, TypeElement typeElement) {
  67         super(writer, typeElement);
  68     }
  69 
  70     /**
  71      * Construct a new MethodWriterImpl.
  72      *
  73      * @param writer The writer for the class that the methods belong to.
  74      */
  75     public MethodWriterImpl(SubWriterHolderWriter writer) {
  76         super(writer);
  77     }
  78 
  79     /**
  80      * {@inheritDoc}
  81      */
  82     @Override
  83     public Content getMemberSummaryHeader(TypeElement typeElement, Content memberSummaryTree) {
  84         memberSummaryTree.add(MarkerComments.START_OF_METHOD_SUMMARY);
  85         Content memberTree = new ContentBuilder();
  86         writer.addSummaryHeader(this, memberTree);
  87         return memberTree;
  88     }
  89 
  90     /**
  91      * {@inheritDoc}
  92      */
  93     @Override
  94     public void addMemberTree(Content memberSummaryTree, Content memberTree) {
  95         writer.addMemberTree(HtmlStyle.methodSummary,
  96                 SectionName.METHOD_SUMMARY, memberSummaryTree, memberTree);
  97     }
  98 
  99     /**
 100      * {@inheritDoc}
 101      */
 102     @Override
 103     public Content getMethodDetailsTreeHeader(Content memberDetailsTree) {
 104         memberDetailsTree.add(MarkerComments.START_OF_METHOD_DETAILS);
 105         Content methodDetailsTree = new ContentBuilder();
 106         Content heading = HtmlTree.HEADING(Headings.TypeDeclaration.DETAILS_HEADING,
 107                 contents.methodDetailLabel);
 108         methodDetailsTree.add(heading);
 109         return methodDetailsTree;
 110     }
 111 
 112     /**
 113      * {@inheritDoc}
 114      */
 115     @Override
 116     public Content getMethodDocTreeHeader(ExecutableElement method) {
 117         String erasureAnchor;
 118         Content methodDocTree = new ContentBuilder();
 119         HtmlTree heading = new HtmlTree(Headings.TypeDeclaration.MEMBER_HEADING,
 120                 new StringContent(name(method)));
 121         if ((erasureAnchor = getErasureAnchor(method)) != null) {
 122             heading.setId(erasureAnchor);
 123         }
 124         methodDocTree.add(heading);
 125         return HtmlTree.SECTION(HtmlStyle.detail, methodDocTree)
 126                 .setId(links.getName(writer.getAnchor(method)));
 127     }
 128 
 129     /**
 130      * Get the signature for the given method.
 131      *
 132      * @param method the method being documented.
 133      * @return a content object for the signature
 134      */
 135     @Override
 136     public Content getSignature(ExecutableElement method) {
 137         return new MemberSignature(method)
 138                 .addTypeParameters(getTypeParameters(method))
 139                 .addReturnType(getReturnType(method))
 140                 .addParameters(getParameters(method, true))
 141                 .addExceptions(getExceptions(method))
 142                 .toContent();
 143     }
 144 
 145     /**
 146      * {@inheritDoc}
 147      */
 148     @Override
 149     public void addDeprecated(ExecutableElement method, Content methodDocTree) {
 150         addDeprecatedInfo(method, methodDocTree);
 151     }
 152 
 153     /**
 154      * {@inheritDoc}
 155      */
 156     @Override
 157     public void addComments(TypeMirror holderType, ExecutableElement method, Content methodDocTree) {
 158         TypeElement holder = utils.asTypeElement(holderType);
 159         if (!utils.getFullBody(method).isEmpty()) {
 160             if (holder.equals(typeElement) ||
 161                     !(utils.isPublic(holder) ||
 162                     utils.isLinkable(holder))) {
 163                 writer.addInlineComment(method, methodDocTree);
 164             } else {
 165                 Content link =
 166                         writer.getDocLink(LinkInfoImpl.Kind.EXECUTABLE_ELEMENT_COPY,
 167                         holder, method,
 168                         utils.isIncluded(holder)
 169                                 ? utils.getSimpleName(holder)
 170                                 : utils.getFullyQualifiedName(holder),
 171                             false);
 172                 Content codeLink = HtmlTree.CODE(link);
 173                 Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel,
 174                         utils.isClass(holder)
 175                                 ? contents.descfrmClassLabel
 176                                 : contents.descfrmInterfaceLabel);
 177                 descfrmLabel.add(Entity.NO_BREAK_SPACE);
 178                 descfrmLabel.add(codeLink);
 179                 methodDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel));
 180                 writer.addInlineComment(method, methodDocTree);
 181             }
 182         }
 183     }
 184 
 185     /**
 186      * {@inheritDoc}
 187      */
 188     @Override
 189     public void addTags(ExecutableElement method, Content methodDocTree) {
 190         writer.addTagsInfo(method, methodDocTree);
 191     }
 192 
 193     /**
 194      * {@inheritDoc}
 195      */
 196     @Override
 197     public Content getMethodDetails(Content methodDetailsTreeHeader, Content methodDetailsTree) {
 198         Content methodDetails = new ContentBuilder(methodDetailsTreeHeader, methodDetailsTree);
 199         return getMemberTree(HtmlTree.SECTION(HtmlStyle.methodDetails, methodDetails)
 200                 .setId(SectionName.METHOD_DETAIL.getName()));
 201     }
 202 
 203     /**
 204      * {@inheritDoc}
 205      */
 206     @Override
 207     public Content getMethodDoc(Content methodDocTree) {
 208         return getMemberTree(methodDocTree);
 209     }
 210 
 211     /**
 212      * {@inheritDoc}
 213      */
 214     @Override
 215     public void addSummaryLabel(Content memberTree) {
 216         Content label = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING,
 217                 contents.methodSummary);
 218         memberTree.add(label);
 219     }
 220 
 221     /**
 222      * {@inheritDoc}
 223      */
 224     @Override
 225     public TableHeader getSummaryTableHeader(Element member) {
 226         return new TableHeader(contents.modifierAndTypeLabel, contents.methodLabel,
 227                 contents.descriptionLabel);
 228     }
 229 
 230     @Override
 231     protected Table createSummaryTable() {
 232         return new Table(HtmlStyle.memberSummary)
 233                 .setHeader(getSummaryTableHeader(typeElement))
 234                 .setRowScopeColumn(1)
 235                 .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast)
 236                 .setDefaultTab(resources.getText("doclet.All_Methods"))
 237                 .addTab(resources.getText("doclet.Static_Methods"), utils::isStatic)
 238                 .addTab(resources.getText("doclet.Instance_Methods"), e -> !utils.isStatic(e))
 239                 .addTab(resources.getText("doclet.Abstract_Methods"), utils::isAbstract)
 240                 .addTab(resources.getText("doclet.Concrete_Methods"),
 241                         e -> !utils.isAbstract(e) && !utils.isInterface(e.getEnclosingElement()))
 242                 .addTab(resources.getText("doclet.Default_Methods"), utils::isDefault)
 243                 .addTab(resources.getText("doclet.Deprecated_Methods"),
 244                         e -> utils.isDeprecated(e) || utils.isDeprecated(typeElement))
 245                 .setTabScript(i -> "show(" + i + ");");
 246     }
 247 
 248     /**
 249      * {@inheritDoc}
 250      */
 251     @Override
 252     public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedTree) {
 253         Content classLink = writer.getPreQualifiedClassLink(
 254                 LinkInfoImpl.Kind.MEMBER, typeElement, false);
 255         Content label;
 256         if (configuration.summarizeOverriddenMethods) {
 257             label = new StringContent(utils.isClass(typeElement)
 258                     ? resources.getText("doclet.Methods_Declared_In_Class")
 259                     : resources.getText("doclet.Methods_Declared_In_Interface"));
 260         } else {
 261             label = new StringContent(utils.isClass(typeElement)
 262                     ? resources.getText("doclet.Methods_Inherited_From_Class")
 263                     : resources.getText("doclet.Methods_Inherited_From_Interface"));
 264         }
 265         HtmlTree labelHeading = HtmlTree.HEADING(Headings.TypeDeclaration.INHERITED_SUMMARY_HEADING,
 266                 label);
 267         labelHeading.setId(SectionName.METHODS_INHERITANCE.getName()
 268                 + links.getName(configuration.getClassName(typeElement)));
 269         labelHeading.add(Entity.NO_BREAK_SPACE);
 270         labelHeading.add(classLink);
 271         inheritedTree.add(labelHeading);
 272     }
 273 
 274     /**
 275      * {@inheritDoc}
 276      */
 277     @Override
 278     protected void addSummaryType(Element member, Content tdSummaryType) {
 279         ExecutableElement meth = (ExecutableElement)member;
 280         addModifierAndType(meth, utils.getReturnType(typeElement, meth), tdSummaryType);
 281     }
 282 
 283     /**
 284      * {@inheritDoc}
 285      */
 286     protected static void addOverridden(HtmlDocletWriter writer,
 287             TypeMirror overriddenType, ExecutableElement method, Content dl) {
 288         if (writer.configuration.nocomment) {
 289             return;
 290         }
 291         Utils utils = writer.utils;
 292         Contents contents = writer.contents;
 293         TypeElement holder = utils.getEnclosingTypeElement(method);
 294         if (!(utils.isPublic(holder) ||
 295             utils.isLinkable(holder))) {
 296             //This is an implementation detail that should not be documented.
 297             return;
 298         }
 299         if (utils.isIncluded(holder) && ! utils.isIncluded(method)) {
 300             //The class is included but the method is not.  That means that it
 301             //is not visible so don't document this.
 302             return;
 303         }
 304         Content label = contents.overridesLabel;
 305         LinkInfoImpl.Kind context = LinkInfoImpl.Kind.METHOD_OVERRIDES;
 306 
 307         if (method != null) {
 308             if (utils.isAbstract(holder) && utils.isAbstract(method)){
 309                 //Abstract method is implemented from abstract class,
 310                 //not overridden
 311                 label = contents.specifiedByLabel;
 312                 context = LinkInfoImpl.Kind.METHOD_SPECIFIED_BY;
 313             }
 314             Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, label));
 315             dl.add(dt);
 316             Content overriddenTypeLink =
 317                     writer.getLink(new LinkInfoImpl(writer.configuration, context, overriddenType));
 318             Content codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink);
 319             Content methlink = writer.getLink(
 320                     new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, holder)
 321                             .where(writer.links.getName(writer.getAnchor(method)))
 322                             .label(method.getSimpleName()));
 323             Content codeMethLink = HtmlTree.CODE(methlink);
 324             Content dd = HtmlTree.DD(codeMethLink);
 325             dd.add(Entity.NO_BREAK_SPACE);
 326             dd.add(writer.contents.inClass);
 327             dd.add(Entity.NO_BREAK_SPACE);
 328             dd.add(codeOverriddenTypeLink);
 329             dl.add(dd);
 330         }
 331     }
 332 
 333     /**
 334      * {@inheritDoc}
 335      */
 336     protected static void addImplementsInfo(HtmlDocletWriter writer,
 337             ExecutableElement method, Content dl) {
 338         Utils utils = writer.utils;
 339         if (utils.isStatic(method) || writer.configuration.nocomment) {
 340             return;
 341         }
 342         Contents contents = writer.contents;
 343         VisibleMemberTable vmt = writer.configuration
 344                 .getVisibleMemberTable(utils.getEnclosingTypeElement(method));
 345         SortedSet<ExecutableElement> implementedMethods =
 346                 new TreeSet<>(utils.makeOverrideUseComparator());
 347         implementedMethods.addAll(vmt.getImplementedMethods(method));
 348         for (ExecutableElement implementedMeth : implementedMethods) {
 349             TypeMirror intfac = vmt.getImplementedMethodHolder(method, implementedMeth);
 350             intfac = utils.getDeclaredType(utils.getEnclosingTypeElement(method), intfac);
 351             Content intfaclink = writer.getLink(new LinkInfoImpl(
 352                     writer.configuration, LinkInfoImpl.Kind.METHOD_SPECIFIED_BY, intfac));
 353             Content codeIntfacLink = HtmlTree.CODE(intfaclink);
 354             Content dt = HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.overrideSpecifyLabel, contents.specifiedByLabel));
 355             dl.add(dt);
 356             Content methlink = writer.getDocLink(
 357                     LinkInfoImpl.Kind.MEMBER, implementedMeth,
 358                     implementedMeth.getSimpleName(), false);
 359             Content codeMethLink = HtmlTree.CODE(methlink);
 360             Content dd = HtmlTree.DD(codeMethLink);
 361             dd.add(Entity.NO_BREAK_SPACE);
 362             dd.add(contents.inInterface);
 363             dd.add(Entity.NO_BREAK_SPACE);
 364             dd.add(codeIntfacLink);
 365             dl.add(dd);
 366         }
 367     }
 368 
 369     /**
 370      * Get the return type for the given method.
 371      *
 372      * @param method the method being documented.
 373      * @return content containing the return type
 374      */
 375     protected Content getReturnType(ExecutableElement method) {
 376         TypeMirror type = utils.getReturnType(typeElement, method);
 377         if (type != null) {
 378             return writer.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RETURN_TYPE, type));
 379         }
 380         return new ContentBuilder();
 381     }
 382 
 383     @Override
 384     public Content getMemberTreeHeader(){
 385         return writer.getMemberTreeHeader();
 386     }
 387 }