DocFinder.java revision 2571:10fc81ac75b4
1/*
2 * Copyright (c) 2003, 2014, 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 com.sun.tools.doclets.internal.toolkit.util;
27
28import java.util.*;
29
30import com.sun.javadoc.*;
31import com.sun.tools.doclets.internal.toolkit.Configuration;
32import com.sun.tools.doclets.internal.toolkit.taglets.*;
33
34/**
35 * Search for the requested documentation.  Inherit documentation if necessary.
36 *
37 *  <p><b>This is NOT part of any supported API.
38 *  If you write code that depends on this, you do so at your own risk.
39 *  This code and its internal interfaces are subject to change or
40 *  deletion without notice.</b>
41 *
42 * @author Jamie Ho
43 * @since 1.5
44 */
45public class DocFinder {
46
47    /**
48     * The class that encapsulates the input.
49     */
50    public static class Input {
51        /**
52         * The element to search documentation from.
53         */
54        public ProgramElementDoc element;
55        /**
56         * The taglet to search for documentation on behalf of. Null if we want
57         * to search for overall documentation.
58         */
59        public InheritableTaglet taglet = null;
60
61        /**
62         * The id of the tag to retrieve documentation for.
63         */
64        public String tagId = null;
65
66        /**
67         * The tag to retrieve documentation for.  This is only used for the
68         * inheritDoc tag.
69         */
70        public Tag tag = null;
71
72        /**
73         * True if we only want to search for the first sentence.
74         */
75        public boolean isFirstSentence = false;
76
77        /**
78         * True if we are looking for documentation to replace the inheritDocTag.
79         */
80        public boolean isInheritDocTag = false;
81
82        /**
83         * Used to distinguish between type variable param tags and regular
84         * param tags.
85         */
86        public boolean isTypeVariableParamTag = false;
87
88        public Input(ProgramElementDoc element, InheritableTaglet taglet, Tag tag,
89                boolean isFirstSentence, boolean isInheritDocTag) {
90            this(element);
91            this.taglet = taglet;
92            this.tag = tag;
93            this.isFirstSentence = isFirstSentence;
94            this.isInheritDocTag = isInheritDocTag;
95        }
96
97        public Input(ProgramElementDoc element, InheritableTaglet taglet, String tagId) {
98            this(element);
99            this.taglet = taglet;
100            this.tagId = tagId;
101        }
102
103        public Input(ProgramElementDoc element, InheritableTaglet taglet, String tagId,
104            boolean isTypeVariableParamTag) {
105            this(element);
106            this.taglet = taglet;
107            this.tagId = tagId;
108            this.isTypeVariableParamTag = isTypeVariableParamTag;
109        }
110
111        public Input(ProgramElementDoc element, InheritableTaglet taglet) {
112            this(element);
113            this.taglet = taglet;
114        }
115
116        public Input(ProgramElementDoc element) {
117            if (element == null)
118                throw new NullPointerException();
119            this.element = element;
120        }
121
122        public Input(ProgramElementDoc element, boolean isFirstSentence) {
123            this(element);
124            this.isFirstSentence = isFirstSentence;
125        }
126
127        public Input copy() {
128            Input clone = new Input(this.element);
129            clone.taglet = this.taglet;
130            clone.tagId = this.tagId;
131            clone.tag = this.tag;
132            clone.isFirstSentence = this.isFirstSentence;
133            clone.isInheritDocTag = this.isInheritDocTag;
134            clone.isTypeVariableParamTag = this.isTypeVariableParamTag;
135            if (clone.element == null)
136                throw new NullPointerException();
137            return clone;
138
139        }
140    }
141
142    /**
143     * The class that encapsulates the output.
144     */
145    public static class Output {
146        /**
147         * The tag that holds the documentation.  Null if documentation
148         * is not held by a tag.
149         */
150        public Tag holderTag;
151
152        /**
153         * The Doc object that holds the documentation.
154         */
155        public Doc holder;
156
157        /**
158         * The inherited documentation.
159         */
160        public Tag[] inlineTags = new Tag[] {};
161
162        /**
163         * False if documentation could not be inherited.
164         */
165        public boolean isValidInheritDocTag = true;
166
167        /**
168         * When automatically inheriting throws tags, you sometime must inherit
169         * more than one tag.  For example if the element declares that it throws
170         * IOException and the overridden element has throws tags for IOException and
171         * ZipException, both tags would be inherited because ZipException is a
172         * subclass of IOException.  This subclass of DocFinder.Output allows
173         * multiple tag inheritence.
174         */
175        public List<Tag> tagList  = new ArrayList<>();
176    }
177
178    /**
179     * Search for the requested comments in the given element.  If it does not
180     * have comments, return documentation from the overriden element if possible.
181     * If the overriden element does not exist or does not have documentation to
182     * inherit, search for documentation to inherit from implemented methods.
183     *
184     * @param input the input object used to perform the search.
185     *
186     * @return an Output object representing the documentation that was found.
187     */
188    public static Output search(Configuration configuration, Input input) {
189        Output output = new Output();
190        if (input.isInheritDocTag) {
191            //Do nothing because "element" does not have any documentation.
192            //All it has it {@inheritDoc}.
193        } else if (input.taglet == null) {
194            //We want overall documentation.
195            output.inlineTags = input.isFirstSentence ?
196                input.element.firstSentenceTags() :
197                input.element.inlineTags();
198            output.holder = input.element;
199        } else {
200            input.taglet.inherit(input, output);
201        }
202
203        if (output.inlineTags != null && output.inlineTags.length > 0) {
204            return output;
205        }
206        output.isValidInheritDocTag = false;
207        Input inheritedSearchInput = input.copy();
208        inheritedSearchInput.isInheritDocTag = false;
209        if (input.element instanceof MethodDoc) {
210            MethodDoc overriddenMethod = ((MethodDoc) input.element).overriddenMethod();
211            if (overriddenMethod != null) {
212                inheritedSearchInput.element = overriddenMethod;
213                output = search(configuration, inheritedSearchInput);
214                output.isValidInheritDocTag = true;
215                if (output.inlineTags.length > 0) {
216                    return output;
217                }
218            }
219            //NOTE:  When we fix the bug where ClassDoc.interfaceTypes() does
220            //       not pass all implemented interfaces, we will use the
221            //       appropriate element here.
222            MethodDoc[] implementedMethods =
223                (new ImplementedMethods((MethodDoc) input.element, configuration)).build(false);
224            for (MethodDoc implementedMethod : implementedMethods) {
225                inheritedSearchInput.element = implementedMethod;
226                output = search(configuration, inheritedSearchInput);
227                output.isValidInheritDocTag = true;
228                if (output.inlineTags.length > 0) {
229                    return output;
230                }
231            }
232        } else if (input.element instanceof ClassDoc) {
233            ProgramElementDoc superclass = ((ClassDoc) input.element).superclass();
234            if (superclass != null) {
235                inheritedSearchInput.element = superclass;
236                output = search(configuration, inheritedSearchInput);
237                output.isValidInheritDocTag = true;
238                if (output.inlineTags.length > 0) {
239                    return output;
240                }
241            }
242        }
243        return output;
244    }
245}
246