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