001    /*
002     * Copyright 2003-2008 Sun Microsystems, Inc.  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.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.doclets.internal.toolkit.util;
027    
028    import com.sun.javadoc.*;
029    import com.sun.tools.doclets.internal.toolkit.taglets.*;
030    import java.util.*;
031    
032    /**
033     * Search for the requested documentation.  Inherit documentation if necessary.
034     *
035     * @author Jamie Ho
036     * @since 1.5
037     */
038    public class DocFinder {
039    
040        /**
041         * The class that encapsulates the input.
042         */
043        public static class Input {
044            /**
045             * The method to search documentation from.
046             */
047            public MethodDoc method = null;
048            /**
049             * The taglet to search for documentation on behalf of. Null if we want
050             * to search for overall documentation.
051             */
052            public InheritableTaglet taglet = null;
053    
054            /**
055             * The id of the tag to retrieve documentation for.
056             */
057            public String tagId = null;
058    
059            /**
060             * The tag to retrieve documentation for.  This is only used for the
061             * inheritDoc tag.
062             */
063            public Tag tag = null;
064    
065            /**
066             * True if we only want to search for the first sentence.
067             */
068            public boolean isFirstSentence = false;
069    
070            /**
071             * True if we are looking for documentation to replace the inheritDocTag.
072             */
073            public boolean isInheritDocTag = false;
074    
075            /**
076             * Used to distinguish between type variable param tags and regular
077             * param tags.
078             */
079            public boolean isTypeVariableParamTag = false;
080    
081            public Input() {}
082    
083            public Input(MethodDoc method, InheritableTaglet taglet, Tag tag,
084                    boolean isFirstSentence, boolean isInheritDocTag) {
085                this.method = method;
086                this.taglet = taglet;
087                this.tag = tag;
088                this.isFirstSentence = isFirstSentence;
089                this.isInheritDocTag = isInheritDocTag;
090            }
091    
092            public Input(MethodDoc method, InheritableTaglet taglet, String tagId) {
093                this.method = method;
094                this.taglet = taglet;
095                this.tagId = tagId;
096            }
097    
098            public Input(MethodDoc method, InheritableTaglet taglet, String tagId,
099                boolean isTypeVariableParamTag) {
100                this.method = method;
101                this.taglet = taglet;
102                this.tagId = tagId;
103                this.isTypeVariableParamTag = isTypeVariableParamTag;
104            }
105    
106            public Input(MethodDoc method, InheritableTaglet taglet) {
107                this.method = method;
108                this.taglet = taglet;
109            }
110    
111            public Input(MethodDoc method) {
112                this.method = method;
113            }
114    
115            public Input(MethodDoc method, boolean isFirstSentence) {
116                this.method = method;
117                this.isFirstSentence = isFirstSentence;
118            }
119    
120            public Input copy() {
121                Input clone = new Input();
122                clone.method = this.method;
123                clone.taglet = this.taglet;
124                clone.tagId = this.tagId;
125                clone.tag = this.tag;
126                clone.isFirstSentence = this.isFirstSentence;
127                clone.isInheritDocTag = this.isInheritDocTag;
128                clone.isTypeVariableParamTag = this.isTypeVariableParamTag;
129                return clone;
130    
131            }
132        }
133    
134        /**
135         * The class that encapsulates the output.
136         */
137        public static class Output {
138            /**
139             * The tag that holds the documentation.  Null if documentation
140             * is not held by a tag.
141             */
142            public Tag holderTag;
143    
144            /**
145             * The Doc object that holds the documentation.
146             */
147            public Doc holder;
148    
149            /**
150             * The inherited documentation.
151             */
152            public Tag[] inlineTags = new Tag[] {};
153    
154            /**
155             * False if documentation could not be inherited.
156             */
157            public boolean isValidInheritDocTag = true;
158    
159            /**
160             * When automatically inheriting throws tags, you sometime must inherit
161             * more than one tag.  For example if the method declares that it throws
162             * IOException and the overidden method has throws tags for IOException and
163             * ZipException, both tags would be inherited because ZipException is a
164             * subclass of IOException.  This subclass of DocFinder.Output allows
165             * multiple tag inheritence.
166             */
167            public List<Tag> tagList  = new ArrayList<Tag>();
168        }
169    
170        /**
171         * Search for the requested comments in the given method.  If it does not
172         * have comments, return documentation from the overriden method if possible.
173         * If the overriden method does not exist or does not have documentation to
174         * inherit, search for documentation to inherit from implemented methods.
175         *
176         * @param input the input object used to perform the search.
177         *
178         * @return an Output object representing the documentation that was found.
179         */
180        public static Output search(Input input) {
181            Output output = new Output();
182            if (input.isInheritDocTag) {
183                //Do nothing because "method" does not have any documentation.
184                //All it has it {@inheritDoc}.
185            } else if (input.taglet == null) {
186                //We want overall documentation.
187                output.inlineTags = input.isFirstSentence ?
188                    input.method.firstSentenceTags() :
189                    input.method.inlineTags();
190                output.holder = input.method;
191            } else {
192                input.taglet.inherit(input, output);
193            }
194    
195            if (output.inlineTags != null && output.inlineTags.length > 0) {
196                return output;
197            }
198            output.isValidInheritDocTag = false;
199            Input inheritedSearchInput = input.copy();
200            inheritedSearchInput.isInheritDocTag = false;
201            if (input.method.overriddenMethod() != null) {
202                inheritedSearchInput.method = input.method.overriddenMethod();
203                output = search(inheritedSearchInput);
204                output.isValidInheritDocTag = true;
205                if (output != null && output.inlineTags.length > 0) {
206                    return output;
207                }
208            }
209            //NOTE:  When we fix the bug where ClassDoc.interfaceTypes() does
210            //       not pass all implemented interfaces, we will use the
211            //       appropriate method here.
212            MethodDoc[] implementedMethods =
213                (new ImplementedMethods(input.method, null)).build(false);
214            for (int i = 0; i < implementedMethods.length; i++) {
215                inheritedSearchInput.method = implementedMethods[i];
216                output = search(inheritedSearchInput);
217                output.isValidInheritDocTag = true;
218                if (output != null && output.inlineTags.length > 0) {
219                    return output;
220                }
221            }
222            return output;
223        }
224    }