001: /*
002: * Copyright 2003-2005 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:
084: public Input(MethodDoc method, InheritableTaglet taglet,
085: Tag tag, boolean isFirstSentence,
086: boolean isInheritDocTag) {
087: this .method = method;
088: this .taglet = taglet;
089: this .tag = tag;
090: this .isFirstSentence = isFirstSentence;
091: this .isInheritDocTag = isInheritDocTag;
092: }
093:
094: public Input(MethodDoc method, InheritableTaglet taglet,
095: String tagId) {
096: this .method = method;
097: this .taglet = taglet;
098: this .tagId = tagId;
099: }
100:
101: public Input(MethodDoc method, InheritableTaglet taglet,
102: String tagId, boolean isTypeVariableParamTag) {
103: this .method = method;
104: this .taglet = taglet;
105: this .tagId = tagId;
106: this .isTypeVariableParamTag = isTypeVariableParamTag;
107: }
108:
109: public Input(MethodDoc method, InheritableTaglet taglet) {
110: this .method = method;
111: this .taglet = taglet;
112: }
113:
114: public Input(MethodDoc method) {
115: this .method = method;
116: }
117:
118: public Input(MethodDoc method, boolean isFirstSentence) {
119: this .method = method;
120: this .isFirstSentence = isFirstSentence;
121: }
122:
123: public Input copy() {
124: Input clone = new Input();
125: clone.method = this .method;
126: clone.taglet = this .taglet;
127: clone.tagId = this .tagId;
128: clone.tag = this .tag;
129: clone.isFirstSentence = this .isFirstSentence;
130: clone.isInheritDocTag = this .isInheritDocTag;
131: clone.isTypeVariableParamTag = this .isTypeVariableParamTag;
132: return clone;
133:
134: }
135: }
136:
137: /**
138: * The class that encapsulates the output.
139: */
140: public static class Output {
141: /**
142: * The tag that holds the documentation. Null if documentation
143: * is not held by a tag.
144: */
145: public Tag holderTag;
146:
147: /**
148: * The Doc object that holds the documentation.
149: */
150: public Doc holder;
151:
152: /**
153: * The inherited documentation.
154: */
155: public Tag[] inlineTags = new Tag[] {};
156:
157: /**
158: * False if documentation could not be inherited.
159: */
160: public boolean isValidInheritDocTag = true;
161:
162: /**
163: * When automatically inheriting throws tags, you sometime must inherit
164: * more than one tag. For example if the method declares that it throws
165: * IOException and the overidden method has throws tags for IOException and
166: * ZipException, both tags would be inherited because ZipException is a
167: * subclass of IOException. This subclass of DocFinder.Output allows
168: * multiple tag inheritence.
169: */
170: public List tagList = new ArrayList();
171: }
172:
173: /**
174: * Search for the requested comments in the given method. If it does not
175: * have comments, return documentation from the overriden method if possible.
176: * If the overriden method does not exist or does not have documentation to
177: * inherit, search for documentation to inherit from implemented methods.
178: *
179: * @param input the input object used to perform the search.
180: *
181: * @return an Output object representing the documentation that was found.
182: */
183: public static Output search(Input input) {
184: Output output = new Output();
185: if (input.isInheritDocTag) {
186: //Do nothing because "method" does not have any documentation.
187: //All it has it {@inheritDoc}.
188: } else if (input.taglet == null) {
189: //We want overall documentation.
190: output.inlineTags = input.isFirstSentence ? input.method
191: .firstSentenceTags() : input.method.inlineTags();
192: output.holder = input.method;
193: } else {
194: input.taglet.inherit(input, output);
195: }
196:
197: if (output.inlineTags != null && output.inlineTags.length > 0) {
198: return output;
199: }
200: output.isValidInheritDocTag = false;
201: Input inheritedSearchInput = input.copy();
202: inheritedSearchInput.isInheritDocTag = false;
203: if (input.method.overriddenMethod() != null) {
204: inheritedSearchInput.method = input.method
205: .overriddenMethod();
206: output = search(inheritedSearchInput);
207: output.isValidInheritDocTag = true;
208: if (output != null && output.inlineTags.length > 0) {
209: return output;
210: }
211: }
212: //NOTE: When we fix the bug where ClassDoc.interfaceTypes() does
213: // not pass all implemented interfaces, we will use the
214: // appropriate method here.
215: MethodDoc[] implementedMethods = (new ImplementedMethods(
216: input.method, null)).build(false);
217: for (int i = 0; i < implementedMethods.length; i++) {
218: inheritedSearchInput.method = implementedMethods[i];
219: output = search(inheritedSearchInput);
220: output.isValidInheritDocTag = true;
221: if (output != null && output.inlineTags.length > 0) {
222: return output;
223: }
224: }
225: return output;
226: }
227: }
|