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