001/*
002 * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package org.jdrupes.mdoclet.internal.doclets.toolkit.builders;
027
028import static org.jdrupes.mdoclet.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
029
030import java.util.*;
031
032import javax.lang.model.element.Element;
033import javax.lang.model.element.ExecutableElement;
034import javax.lang.model.element.TypeElement;
035import javax.lang.model.type.TypeMirror;
036
037import org.jdrupes.mdoclet.internal.doclets.toolkit.BaseOptions;
038import org.jdrupes.mdoclet.internal.doclets.toolkit.Content;
039import org.jdrupes.mdoclet.internal.doclets.toolkit.DocletException;
040import org.jdrupes.mdoclet.internal.doclets.toolkit.MethodWriter;
041import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFinder;
042import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFinder.Result;
043
044import com.sun.source.doctree.DocTree;
045
046/**
047 * Builds documentation for a method.
048 */
049public class MethodBuilder extends AbstractMemberBuilder {
050
051    /**
052     * The index of the current field that is being documented at this point
053     * in time.
054     */
055    private ExecutableElement currentMethod;
056
057    /**
058     * The writer to output the method documentation.
059     */
060    private final MethodWriter writer;
061
062    /**
063     * The methods being documented.
064     */
065    private final List<? extends Element> methods;
066
067    /**
068     * Construct a new MethodBuilder.
069     *
070     * @param context       the build context.
071     * @param typeElement the class whose members are being documented.
072     * @param writer the doclet specific writer.
073     */
074    private MethodBuilder(Context context,
075            TypeElement typeElement,
076            MethodWriter writer) {
077        super(context, typeElement);
078        this.writer = Objects.requireNonNull(writer);
079        methods = getVisibleMembers(METHODS);
080    }
081
082    /**
083     * Construct a new MethodBuilder.
084     *
085     * @param context       the build context.
086     * @param typeElement the class whose members are being documented.
087     * @param writer the doclet specific writer.
088     *
089     * @return an instance of a MethodBuilder.
090     */
091    public static MethodBuilder getInstance(Context context,
092            TypeElement typeElement, MethodWriter writer) {
093        return new MethodBuilder(context, typeElement, writer);
094    }
095
096    @Override
097    public boolean hasMembersToDocument() {
098        return !methods.isEmpty();
099    }
100
101    @Override
102    public void build(Content target) throws DocletException {
103        buildMethodDoc(target);
104    }
105
106    /**
107     * Build the method documentation.
108     *
109     * @param detailsList the content to which the documentation will be added
110     * @throws DocletException if there is a problem while building the documentation
111     */
112    protected void buildMethodDoc(Content detailsList) throws DocletException {
113        if (hasMembersToDocument()) {
114            Content methodDetailsHeader
115                = writer.getMethodDetailsHeader(detailsList);
116            Content memberList = writer.getMemberList();
117
118            for (Element method : methods) {
119                currentMethod = (ExecutableElement) method;
120                Content methodContent = writer.getMethodHeader(currentMethod);
121
122                buildSignature(methodContent);
123                buildDeprecationInfo(methodContent);
124                buildPreviewInfo(methodContent);
125                buildMethodComments(methodContent);
126                buildTagInfo(methodContent);
127
128                memberList.add(writer.getMemberListItem(methodContent));
129            }
130            Content methodDetails
131                = writer.getMethodDetails(methodDetailsHeader, memberList);
132            detailsList.add(methodDetails);
133        }
134    }
135
136    /**
137     * Build the signature.
138     *
139     * @param methodContent the content to which the documentation will be added
140     */
141    protected void buildSignature(Content methodContent) {
142        methodContent.add(writer.getSignature(currentMethod));
143    }
144
145    /**
146     * Build the deprecation information.
147     *
148     * @param methodContent the content to which the documentation will be added
149     */
150    protected void buildDeprecationInfo(Content methodContent) {
151        writer.addDeprecated(currentMethod, methodContent);
152    }
153
154    /**
155     * Build the preview information.
156     *
157     * @param methodContent the content to which the documentation will be added
158     */
159    protected void buildPreviewInfo(Content methodContent) {
160        writer.addPreview(currentMethod, methodContent);
161    }
162
163    /**
164     * Build the comments for the method.  Do nothing if
165     * {@link BaseOptions#noComment()} is set to true.
166     *
167     * @param methodContent the content to which the documentation will be added
168     */
169    protected void buildMethodComments(Content methodContent) {
170        if (!options.noComment()) {
171            assert utils.isMethod(currentMethod); // not all executables are
172                                                  // methods
173            var docFinder = utils.docFinder();
174            Optional<ExecutableElement> r = docFinder.search(currentMethod,
175                m -> Result.fromOptional(
176                    utils.getFullBody(m).isEmpty() ? Optional.empty()
177                        : Optional.of(m)))
178                .toOptional();
179            ExecutableElement method = r.orElse(currentMethod);
180            TypeMirror containingType = method.getEnclosingElement().asType();
181            writer.addComments(containingType, method, methodContent);
182        }
183    }
184
185    /**
186     * Build the tag information.
187     *
188     * @param methodContent the content to which the documentation will be added
189     */
190    protected void buildTagInfo(Content methodContent) {
191        writer.addTags(currentMethod, methodContent);
192    }
193
194    /**
195     * Return the method writer for this builder.
196     *
197     * @return the method writer for this builder.
198     */
199    public MethodWriter getWriter() {
200        return writer;
201    }
202}