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