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 }