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, name(ee), false));
 122         Content code = HtmlTree.CODE(memberLink);
 123         addParameters(ee, code);
 124         tdSummary.add(code);
 125     }
 126 
 127     /**
 128      * Add the inherited summary link for the member.
 129      *
 130      * @param te the type element that we should link to
 131      * @param member the member being linked to
 132      * @param linksTree the content tree to which the link will be added
 133      */
 134     @Override
 135     protected void addInheritedSummaryLink(TypeElement te, Element member, Content linksTree) {
 136         linksTree.add(writer.getDocLink(MEMBER, te, member, name(member), false));
 137     }
 138 
 139     /**
 140      * Add the parameter for the executable member.
 141      *
 142      * @param member the member to write parameter for.
 143      * @param param the parameter that needs to be written.
 144      * @param isVarArg true if this is a link to var arg.
 145      * @param tree the content tree to which the parameter information will be added.
 146      */
 147     protected void addParam(ExecutableElement member, VariableElement param,
 148             boolean isVarArg, Content tree) {
 149         Content link = writer.getLink(new LinkInfoImpl(configuration, EXECUTABLE_MEMBER_PARAM,
 150                 param.asType()).varargs(isVarArg));
 151         tree.add(link);
 152         if(name(param).length() > 0) {
 153             tree.add(Entity.NO_BREAK_SPACE);
 154             tree.add(name(param));
 155         }
 156     }
 157 
 158     /**
 159      * Add the receiver annotations information.
 160      *
 161      * @param member the member to write receiver annotations for.
 162      * @param rcvrType the receiver type.
 163      * @param annotationMirrors list of annotation descriptions.
 164      * @param tree the content tree to which the information will be added.
 165      */
 166     protected void addReceiverAnnotations(ExecutableElement member, TypeMirror rcvrType,
 167             List<? extends AnnotationMirror> annotationMirrors, Content tree) {
 168         writer.addReceiverAnnotationInfo(member, rcvrType, annotationMirrors, tree);
 169         tree.add(Entity.NO_BREAK_SPACE);
 170         tree.add(utils.getTypeName(rcvrType, false));
 171         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, RECEIVER_TYPE, rcvrType);
 172         tree.add(writer.getTypeParameterLinks(linkInfo));
 173         tree.add(Entity.NO_BREAK_SPACE);
 174         tree.add("this");
 175     }
 176 
 177 
 178     /**
 179      * Add all the parameters for the executable member.
 180      *
 181      * @param member the member to write parameters for.
 182      * @param htmltree the content tree to which the parameters information will be added.
 183      */
 184     protected void addParameters(ExecutableElement member, Content htmltree) {
 185         Content paramTree = getParameters(member, false);
 186         if (paramTree.isEmpty()) {
 187             htmltree.add("()");
 188         } else {
 189             htmltree.add(Entity.ZERO_WIDTH_SPACE);
 190             htmltree.add("(");
 191             htmltree.add(paramTree);
 192             paramTree.add(")");
 193         }
 194     }
 195 
 196     /**
 197      * Add all the parameters for the executable member.
 198      *
 199      * @param member the member to write parameters for.
 200      * @param includeAnnotations true if annotation information needs to be added.
 201      * @return the content tree containing the parameter information
 202      */
 203     protected Content getParameters(ExecutableElement member, boolean includeAnnotations) {
 204         Content paramTree = new ContentBuilder();
 205         String sep = "";
 206         List<? extends VariableElement> parameters = member.getParameters();
 207         TypeMirror rcvrType = member.getReceiverType();
 208         if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
 209             List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
 210             addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
 211             sep = "," + DocletConstants.NL;
 212         }
 213         int paramstart;
 214         for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
 215             paramTree.add(sep);
 216             VariableElement param = parameters.get(paramstart);
 217 
 218             if (param.getKind() != ElementKind.INSTANCE_INIT) {
 219                 if (includeAnnotations) {
 220                     boolean foundAnnotations =
 221                             writer.addAnnotationInfo(param, paramTree);
 222                     if (foundAnnotations) {
 223                         paramTree.add(DocletConstants.NL);
 224                     }
 225                 }
 226                 addParam(member, param,
 227                     (paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
 228                 break;
 229             }
 230         }
 231 
 232         for (int i = paramstart + 1; i < parameters.size(); i++) {
 233             paramTree.add(",");
 234             paramTree.add(DocletConstants.NL);
 235             if (includeAnnotations) {
 236                 boolean foundAnnotations =
 237                         writer.addAnnotationInfo(parameters.get(i),
 238                         paramTree);
 239                 if (foundAnnotations) {
 240                     paramTree.add(DocletConstants.NL);
 241                 }
 242             }
 243             addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
 244                     paramTree);
 245         }
 246 
 247         return paramTree;
 248     }
 249 
 250     /**
 251      * Get a content tree containing the exception information for the executable member.
 252      *
 253      * @param member the member to write exceptions for.
 254      * @return the content tree containing the exceptions information.
 255      */
 256     protected Content getExceptions(ExecutableElement member) {
 257         List<? extends TypeMirror> exceptions = member.getThrownTypes();
 258         Content htmltree = new ContentBuilder();
 259         if (!exceptions.isEmpty()) {
 260             Content link = writer.getLink(new LinkInfoImpl(configuration, MEMBER, exceptions.get(0)));
 261             htmltree.add(link);
 262             for(int i = 1; i < exceptions.size(); i++) {
 263                 htmltree.add(",");
 264                 htmltree.add(DocletConstants.NL);
 265                 Content exceptionLink = writer.getLink(new LinkInfoImpl(configuration, MEMBER,
 266                         exceptions.get(i)));
 267                 htmltree.add(exceptionLink);
 268             }
 269         }
 270         return htmltree;
 271     }
 272 
 273     protected TypeElement implementsMethodInIntfac(ExecutableElement method,
 274                                                 List<TypeElement> intfacs) {
 275         for (TypeElement intf : intfacs) {
 276             List<ExecutableElement> methods = utils.getMethods(intf);
 277             if (!methods.isEmpty()) {
 278                 for (ExecutableElement md : methods) {
 279                     if (name(md).equals(name(method)) &&
 280                         md.toString().equals(method.toString())) {
 281                         return intf;
 282                     }
 283                 }
 284             }
 285         }
 286         return null;
 287     }
 288 
 289     /**
 290      * For backward compatibility, include an anchor using the erasures of the
 291      * parameters.  NOTE:  We won't need this method anymore after we fix
 292      * see tags so that they use the type instead of the erasure.
 293      *
 294      * @param executableElement the ExecutableElement to anchor to.
 295      * @return the 1.4.x style anchor for the executable element.
 296      */
 297     protected String getErasureAnchor(ExecutableElement executableElement) {
 298         final StringBuilder buf = new StringBuilder(writer.anchorName(executableElement));
 299         buf.append("(");
 300         List<? extends VariableElement> parameters = executableElement.getParameters();
 301         boolean foundTypeVariable = false;
 302         for (int i = 0; i < parameters.size(); i++) {
 303             if (i > 0) {
 304                 buf.append(",");
 305             }
 306             TypeMirror t = parameters.get(i).asType();
 307             SimpleTypeVisitor9<Boolean, Void> stv = new SimpleTypeVisitor9<Boolean, Void>() {
 308                 boolean foundTypeVariable = false;
 309 
 310                 @Override
 311                 public Boolean visitArray(ArrayType t, Void p) {
 312                     visit(t.getComponentType());
 313                     buf.append(utils.getDimension(t));
 314                     return foundTypeVariable;
 315                 }
 316 
 317                 @Override
 318                 public Boolean visitTypeVariable(TypeVariable t, Void p) {
 319                     buf.append(utils.asTypeElement(t).getQualifiedName());
 320                     foundTypeVariable = true;
 321                     return foundTypeVariable;
 322                 }
 323 
 324                 @Override
 325                 public Boolean visitDeclared(DeclaredType t, Void p) {
 326                     buf.append(utils.getQualifiedTypeName(t));
 327                     return foundTypeVariable;
 328                 }
 329 
 330                 @Override
 331                 protected Boolean defaultAction(TypeMirror e, Void p) {
 332                     buf.append(e);
 333                     return foundTypeVariable;
 334                 }
 335             };
 336 
 337             boolean isTypeVariable = stv.visit(t);
 338             if (!foundTypeVariable) {
 339                 foundTypeVariable = isTypeVariable;
 340             }
 341         }
 342         buf.append(")");
 343         return foundTypeVariable ? writer.links.getName(buf.toString()) : null;
 344     }
 345 }