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.List;
  29 
  30 import javax.lang.model.element.AnnotationMirror;
  31 import javax.lang.model.element.Element;
  32 import javax.lang.model.element.ElementKind;
  33 import javax.lang.model.element.ExecutableElement;
  34 import javax.lang.model.element.TypeElement;
  35 import javax.lang.model.element.VariableElement;
  36 import javax.lang.model.type.ArrayType;
  37 import javax.lang.model.type.DeclaredType;
  38 import javax.lang.model.type.TypeMirror;
  39 import javax.lang.model.type.TypeVariable;
  40 import javax.lang.model.util.SimpleTypeVisitor9;
  41 
  42 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
  43 import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
  44 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  45 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  46 import jdk.javadoc.internal.doclets.toolkit.Content;
  47 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
  48 
  49 import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.EXECUTABLE_MEMBER_PARAM;
  50 import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.MEMBER;
  51 import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.MEMBER_TYPE_PARAMS;
  52 import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.RECEIVER_TYPE;
  53 
  54 /**
  55  * Print method and constructor info.
  56  *
  57  *  <p><b>This is NOT part of any supported API.
  58  *  If you write code that depends on this, you do so at your own risk.
  59  *  This code and its internal interfaces are subject to change or
  60  *  deletion without notice.</b>
  61  *
  62  * @author Robert Field
  63  * @author Atul M Dambalkar
  64  * @author Bhavesh Patel (Modified)
  65  */
  66 public abstract class AbstractExecutableMemberWriter extends AbstractMemberWriter {
  67 
  68     public AbstractExecutableMemberWriter(SubWriterHolderWriter writer, TypeElement typeElement) {
  69         super(writer, typeElement);
  70     }
  71 
  72     public AbstractExecutableMemberWriter(SubWriterHolderWriter writer) {
  73         super(writer);
  74     }
  75 
  76 
  77     /**
  78      * Get the type parameters for the executable member.
  79      *
  80      * @param member the member for which to get the type parameters.
  81      * @return the type parameters.
  82      */
  83     protected Content getTypeParameters(ExecutableElement member) {
  84         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, MEMBER_TYPE_PARAMS, member);
  85         return writer.getTypeParameterLinks(linkInfo);
  86     }
  87 
  88     /**
  89      * {@inheritDoc}
  90      */
  91     @Override
  92     protected Content getDeprecatedLink(Element member) {
  93         Content deprecatedLinkContent = new ContentBuilder();
  94         deprecatedLinkContent.add(utils.getFullyQualifiedName(member));
  95         if (!utils.isConstructor(member)) {
  96             deprecatedLinkContent.add(".");
  97             deprecatedLinkContent.add(member.getSimpleName());
  98         }
  99         String signature = utils.flatSignature((ExecutableElement) member);
 100         if (signature.length() > 2) {
 101             deprecatedLinkContent.add(Entity.ZERO_WIDTH_SPACE);
 102         }
 103         deprecatedLinkContent.add(signature);
 104 
 105         return writer.getDocLink(MEMBER, utils.getEnclosingTypeElement(member), member, deprecatedLinkContent);
 106     }
 107 
 108     /**
 109      * Add the summary link for the member.
 110      *
 111      * @param context the id of the context where the link will be printed
 112      * @param te the type element being linked to
 113      * @param member the member being linked to
 114      * @param tdSummary the content tree to which the link will be added
 115      */
 116     @Override
 117     protected void addSummaryLink(LinkInfoImpl.Kind context, TypeElement te, Element member,
 118             Content tdSummary) {
 119         ExecutableElement ee = (ExecutableElement)member;
 120         Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink,
 121                 writer.getDocLink(context, te, ee,
 122                 name(ee), false));
 123         Content code = HtmlTree.CODE(memberLink);
 124         addParameters(ee, code);
 125         tdSummary.add(code);
 126     }
 127 
 128     /**
 129      * Add the inherited summary link for the member.
 130      *
 131      * @param te the type element that we should link to
 132      * @param member the member being linked to
 133      * @param linksTree the content tree to which the link will be added
 134      */
 135     @Override
 136     protected void addInheritedSummaryLink(TypeElement te, Element member, Content linksTree) {
 137         linksTree.add(writer.getDocLink(MEMBER, te, member, name(member), false));
 138     }
 139 
 140     /**
 141      * Add the parameter for the executable member.
 142      *
 143      * @param member the member to write parameter for.
 144      * @param param the parameter that needs to be written.
 145      * @param isVarArg true if this is a link to var arg.
 146      * @param tree the content tree to which the parameter information will be added.
 147      */
 148     protected void addParam(ExecutableElement member, VariableElement param,
 149             boolean isVarArg, Content tree) {
 150         Content link = writer.getLink(new LinkInfoImpl(configuration, EXECUTABLE_MEMBER_PARAM,
 151                 param.asType()).varargs(isVarArg));
 152         tree.add(link);
 153         if(name(param).length() > 0) {
 154             tree.add(Entity.NO_BREAK_SPACE);
 155             tree.add(name(param));
 156         }
 157     }
 158 
 159     /**
 160      * Add the receiver annotations information.
 161      *
 162      * @param member the member to write receiver annotations for.
 163      * @param rcvrType the receiver type.
 164      * @param annotationMirrors list of annotation descriptions.
 165      * @param tree the content tree to which the information will be added.
 166      */
 167     protected void addReceiverAnnotations(ExecutableElement member, TypeMirror rcvrType,
 168             List<? extends AnnotationMirror> annotationMirrors, Content tree) {
 169         writer.addReceiverAnnotationInfo(member, rcvrType, annotationMirrors, tree);
 170         tree.add(Entity.NO_BREAK_SPACE);
 171         tree.add(utils.getTypeName(rcvrType, false));
 172         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, RECEIVER_TYPE, rcvrType);
 173         tree.add(writer.getTypeParameterLinks(linkInfo));
 174         tree.add(Entity.NO_BREAK_SPACE);
 175         tree.add("this");
 176     }
 177 
 178 
 179     /**
 180      * Add all the parameters for the executable member.
 181      *
 182      * @param member the member to write parameters for.
 183      * @param htmltree the content tree to which the parameters information will be added.
 184      */
 185     protected void addParameters(ExecutableElement member, Content htmltree) {
 186         Content paramTree = getParameters(member, false);
 187         if (paramTree.isEmpty()) {
 188             htmltree.add("()");
 189         } else {
 190             htmltree.add(Entity.ZERO_WIDTH_SPACE);
 191             htmltree.add("(");
 192             htmltree.add(paramTree);
 193             paramTree.add(")");
 194         }
 195     }
 196 
 197     /**
 198      * Add all the parameters for the executable member.
 199      *
 200      * @param member the member to write parameters for.
 201      * @param includeAnnotations true if annotation information needs to be added.
 202      * @return the content tree containing the parameter information
 203      */
 204     protected Content getParameters(ExecutableElement member, boolean includeAnnotations) {
 205         Content paramTree = new ContentBuilder();
 206         String sep = "";
 207         List<? extends VariableElement> parameters = member.getParameters();
 208         TypeMirror rcvrType = member.getReceiverType();
 209         if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
 210             List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
 211             addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
 212             sep = "," + DocletConstants.NL;
 213         }
 214         int paramstart;
 215         for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
 216             paramTree.add(sep);
 217             VariableElement param = parameters.get(paramstart);
 218 
 219             if (param.getKind() != ElementKind.INSTANCE_INIT) {
 220                 if (includeAnnotations) {
 221                     boolean foundAnnotations =
 222                             writer.addAnnotationInfo(param, paramTree);
 223                     if (foundAnnotations) {
 224                         paramTree.add(DocletConstants.NL);
 225                     }
 226                 }
 227                 addParam(member, param,
 228                     (paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
 229                 break;
 230             }
 231         }
 232 
 233         for (int i = paramstart + 1; i < parameters.size(); i++) {
 234             paramTree.add(",");
 235             paramTree.add(DocletConstants.NL);
 236             if (includeAnnotations) {
 237                 boolean foundAnnotations =
 238                         writer.addAnnotationInfo(parameters.get(i),
 239                         paramTree);
 240                 if (foundAnnotations) {
 241                     paramTree.add(DocletConstants.NL);
 242                 }
 243             }
 244             addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
 245                     paramTree);
 246         }
 247 
 248         return paramTree;
 249     }
 250 
 251     /**
 252      * Get a content tree containing the exception information for the executable member.
 253      *
 254      * @param member the member to write exceptions for.
 255      * @return the content tree containing the exceptions information.
 256      */
 257     protected Content getExceptions(ExecutableElement member) {
 258         List<? extends TypeMirror> exceptions = member.getThrownTypes();
 259         Content htmltree = new ContentBuilder();
 260         if (!exceptions.isEmpty()) {
 261             Content link = writer.getLink(new LinkInfoImpl(configuration, MEMBER, exceptions.get(0)));
 262             htmltree.add(link);
 263             for(int i = 1; i < exceptions.size(); i++) {
 264                 htmltree.add(",");
 265                 htmltree.add(DocletConstants.NL);
 266                 Content exceptionLink = writer.getLink(new LinkInfoImpl(configuration, MEMBER,
 267                         exceptions.get(i)));
 268                 htmltree.add(exceptionLink);
 269             }
 270         }
 271         return htmltree;
 272     }
 273 
 274     protected TypeElement implementsMethodInIntfac(ExecutableElement method,
 275                                                 List<TypeElement> intfacs) {
 276         for (TypeElement intf : intfacs) {
 277             List<ExecutableElement> methods = utils.getMethods(intf);
 278             if (!methods.isEmpty()) {
 279                 for (ExecutableElement md : methods) {
 280                     if (name(md).equals(name(method)) &&
 281                         md.toString().equals(method.toString())) {
 282                         return intf;
 283                     }
 284                 }
 285             }
 286         }
 287         return null;
 288     }
 289 
 290     /**
 291      * For backward compatibility, include an anchor using the erasures of the
 292      * parameters.  NOTE:  We won't need this method anymore after we fix
 293      * see tags so that they use the type instead of the erasure.
 294      *
 295      * @param executableElement the ExecutableElement to anchor to.
 296      * @return the 1.4.x style anchor for the executable element.
 297      */
 298     protected String getErasureAnchor(ExecutableElement executableElement) {
 299         final StringBuilder buf = new StringBuilder(writer.anchorName(executableElement));
 300         buf.append("(");
 301         List<? extends VariableElement> parameters = executableElement.getParameters();
 302         boolean foundTypeVariable = false;
 303         for (int i = 0; i < parameters.size(); i++) {
 304             if (i > 0) {
 305                 buf.append(",");
 306             }
 307             TypeMirror t = parameters.get(i).asType();
 308             SimpleTypeVisitor9<Boolean, Void> stv = new SimpleTypeVisitor9<Boolean, Void>() {
 309                 boolean foundTypeVariable = false;
 310 
 311                 @Override
 312                 public Boolean visitArray(ArrayType t, Void p) {
 313                     visit(t.getComponentType());
 314                     buf.append(utils.getDimension(t));
 315                     return foundTypeVariable;
 316                 }
 317 
 318                 @Override
 319                 public Boolean visitTypeVariable(TypeVariable t, Void p) {
 320                     buf.append(utils.asTypeElement(t).getQualifiedName());
 321                     foundTypeVariable = true;
 322                     return foundTypeVariable;
 323                 }
 324 
 325                 @Override
 326                 public Boolean visitDeclared(DeclaredType t, Void p) {
 327                     buf.append(utils.getQualifiedTypeName(t));
 328                     return foundTypeVariable;
 329                 }
 330 
 331                 @Override
 332                 protected Boolean defaultAction(TypeMirror e, Void p) {
 333                     buf.append(e);
 334                     return foundTypeVariable;
 335                 }
 336             };
 337 
 338             boolean isTypeVariable = stv.visit(t);
 339             if (!foundTypeVariable) {
 340                 foundTypeVariable = isTypeVariable;
 341             }
 342         }
 343         buf.append(")");
 344         return foundTypeVariable ? writer.links.getName(buf.toString()) : null;
 345     }
 346 }