001: /*
002: * Copyright 2001-2003 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.taglets;
027:
028: import com.sun.javadoc.*;
029: import com.sun.tools.doclets.internal.toolkit.util.*;
030: import java.util.*;
031:
032: /**
033: * A taglet that represents the @param tag.
034: *
035: * This code is not part of an API.
036: * It is implementation that is subject to change.
037: * Do not use it as an API
038: *
039: * @author Jamie Ho
040: * @since 1.4
041: */
042: public class ParamTaglet extends BaseTaglet implements
043: InheritableTaglet {
044:
045: /**
046: * Construct a ParamTaglet.
047: */
048: public ParamTaglet() {
049: name = "param";
050: }
051:
052: /**
053: * Given an array of <code>Parameter</code>s, return
054: * a name/rank number map. If the array is null, then
055: * null is returned.
056: * @param params The array of parmeters (from type or executable member) to
057: * check.
058: * @return a name-rank number map.
059: */
060: private static Map getRankMap(Object[] params) {
061: if (params == null) {
062: return null;
063: }
064: HashMap result = new HashMap();
065: for (int i = 0; i < params.length; i++) {
066: String name = params[i] instanceof Parameter ? ((Parameter) params[i])
067: .name()
068: : ((TypeVariable) params[i]).typeName();
069: result.put(name, String.valueOf(i));
070: }
071: return result;
072: }
073:
074: /**
075: * {@inheritDoc}
076: */
077: public void inherit(DocFinder.Input input, DocFinder.Output output) {
078: if (input.tagId == null) {
079: input.isTypeVariableParamTag = ((ParamTag) input.tag)
080: .isTypeParameter();
081: Object[] parameters = input.isTypeVariableParamTag ? (Object[]) ((MethodDoc) input.tag
082: .holder()).typeParameters()
083: : (Object[]) ((MethodDoc) input.tag.holder())
084: .parameters();
085: String target = ((ParamTag) input.tag).parameterName();
086: int i;
087: for (i = 0; i < parameters.length; i++) {
088: String name = parameters[i] instanceof Parameter ? ((Parameter) parameters[i])
089: .name()
090: : ((TypeVariable) parameters[i]).typeName();
091: if (name.equals(target)) {
092: input.tagId = String.valueOf(i);
093: break;
094: }
095: }
096: if (i == parameters.length) {
097: //Someone used {@inheritDoc} on an invalid @param tag.
098: //We don't know where to inherit from.
099: //XXX: in the future when Configuration is available here,
100: //print a warning for this mistake.
101: return;
102: }
103: }
104: ParamTag[] tags = input.isTypeVariableParamTag ? input.method
105: .typeParamTags() : input.method.paramTags();
106: Map rankMap = getRankMap(input.isTypeVariableParamTag ? (Object[]) input.method
107: .typeParameters()
108: : (Object[]) input.method.parameters());
109: for (int i = 0; i < tags.length; i++) {
110: if (rankMap.containsKey(tags[i].parameterName())
111: && rankMap.get(tags[i].parameterName()).equals(
112: (input.tagId))) {
113: output.holder = input.method;
114: output.holderTag = tags[i];
115: output.inlineTags = input.isFirstSentence ? tags[i]
116: .firstSentenceTags() : tags[i].inlineTags();
117: return;
118: }
119: }
120: }
121:
122: /**
123: * {@inheritDoc}
124: */
125: public boolean inField() {
126: return false;
127: }
128:
129: /**
130: * {@inheritDoc}
131: */
132: public boolean inMethod() {
133: return true;
134: }
135:
136: /**
137: * {@inheritDoc}
138: */
139: public boolean inOverview() {
140: return false;
141: }
142:
143: /**
144: * {@inheritDoc}
145: */
146: public boolean inPackage() {
147: return false;
148: }
149:
150: /**
151: * {@inheritDoc}
152: */
153: public boolean inType() {
154: return true;
155: }
156:
157: /**
158: * {@inheritDoc}
159: */
160: public boolean isInlineTag() {
161: return false;
162: }
163:
164: /**
165: * Given an array of <code>ParamTag</code>s,return its string representation.
166: * @param holder the member that holds the param tags.
167: * @param writer the TagletWriter that will write this tag.
168: * @return the TagletOutput representation of these <code>ParamTag</code>s.
169: */
170: public TagletOutput getTagletOutput(Doc holder, TagletWriter writer) {
171: if (holder instanceof ExecutableMemberDoc) {
172: ExecutableMemberDoc member = (ExecutableMemberDoc) holder;
173: TagletOutput output = getTagletOutput(false, member,
174: writer, member.typeParameters(), member
175: .typeParamTags());
176: output.appendOutput(getTagletOutput(true, member, writer,
177: member.parameters(), member.paramTags()));
178: return output;
179: } else {
180: ClassDoc classDoc = (ClassDoc) holder;
181: return getTagletOutput(false, classDoc, writer, classDoc
182: .typeParameters(), classDoc.typeParamTags());
183: }
184: }
185:
186: /**
187: * Given an array of <code>ParamTag</code>s,return its string representation.
188: * Try to inherit the param tags that are missing.
189: *
190: * @param doc the doc that holds the param tags.
191: * @param writer the TagletWriter that will write this tag.
192: * @param formalParameters The array of parmeters (from type or executable
193: * member) to check.
194: *
195: * @return the TagletOutput representation of these <code>ParamTag</code>s.
196: */
197: private TagletOutput getTagletOutput(boolean isNonTypeParams,
198: Doc holder, TagletWriter writer, Object[] formalParameters,
199: ParamTag[] paramTags) {
200: TagletOutput result = writer.getOutputInstance();
201: Set alreadyDocumented = new HashSet();
202: if (paramTags.length > 0) {
203: result.appendOutput(processParamTags(isNonTypeParams,
204: paramTags, getRankMap(formalParameters), writer,
205: alreadyDocumented));
206: }
207: if (alreadyDocumented.size() != formalParameters.length) {
208: //Some parameters are missing corresponding @param tags.
209: //Try to inherit them.
210: result.appendOutput(getInheritedTagletOutput(
211: isNonTypeParams, holder, writer, formalParameters,
212: alreadyDocumented));
213: }
214: return result;
215: }
216:
217: /**
218: * Loop through each indivitual parameter. It it does not have a
219: * corresponding param tag, try to inherit it.
220: */
221: private TagletOutput getInheritedTagletOutput(
222: boolean isNonTypeParams, Doc holder, TagletWriter writer,
223: Object[] formalParameters, Set alreadyDocumented) {
224: TagletOutput result = writer.getOutputInstance();
225: if ((!alreadyDocumented.contains(null))
226: && holder instanceof MethodDoc) {
227: for (int i = 0; i < formalParameters.length; i++) {
228: if (alreadyDocumented.contains(String.valueOf(i))) {
229: continue;
230: }
231: //This parameter does not have any @param documentation.
232: //Try to inherit it.
233: DocFinder.Output inheritedDoc = DocFinder
234: .search(new DocFinder.Input((MethodDoc) holder,
235: this , String.valueOf(i),
236: !isNonTypeParams));
237: if (inheritedDoc.inlineTags != null
238: && inheritedDoc.inlineTags.length > 0) {
239: result
240: .appendOutput(processParamTag(
241: isNonTypeParams,
242: writer,
243: (ParamTag) inheritedDoc.holderTag,
244: isNonTypeParams ? ((Parameter) formalParameters[i])
245: .name()
246: : ((TypeVariable) formalParameters[i])
247: .typeName(),
248: alreadyDocumented.size() == 0));
249: }
250: alreadyDocumented.add(String.valueOf(i));
251: }
252: }
253: return result;
254: }
255:
256: /**
257: * Given an array of <code>Tag</code>s representing this custom
258: * tag, return its string representation. Print a warning for param
259: * tags that do not map to parameters. Print a warning for param
260: * tags that are duplicated.
261: *
262: * @param paramTags the array of <code>ParamTag</code>s to convert.
263: * @param writer the TagletWriter that will write this tag.
264: * @param alreadyDocumented the set of exceptions that have already
265: * been documented.
266: * @param rankMap a {@link java.util.Map} which holds ordering
267: * information about the parameters.
268: * @param nameMap a {@link java.util.Map} which holds a mapping
269: * of a rank of a parameter to its name. This is
270: * used to ensure that the right name is used
271: * when parameter documentation is inherited.
272: * @return the TagletOutput representation of this <code>Tag</code>.
273: */
274: private TagletOutput processParamTags(boolean isNonTypeParams,
275: ParamTag[] paramTags, Map rankMap, TagletWriter writer,
276: Set alreadyDocumented) {
277: TagletOutput result = writer.getOutputInstance();
278: if (paramTags.length > 0) {
279: for (int i = 0; i < paramTags.length; ++i) {
280: ParamTag pt = paramTags[i];
281: String paramName = isNonTypeParams ? pt.parameterName()
282: : "<" + pt.parameterName() + ">";
283: if (!rankMap.containsKey(pt.parameterName())) {
284: writer.getMsgRetriever().warning(
285: pt.position(),
286: isNonTypeParams ? "doclet.Parameters_warn"
287: : "doclet.Type_Parameters_warn",
288: paramName);
289: }
290: String rank = (String) rankMap.get(pt.parameterName());
291: if (rank != null && alreadyDocumented.contains(rank)) {
292: writer
293: .getMsgRetriever()
294: .warning(
295: pt.position(),
296: isNonTypeParams ? "doclet.Parameters_dup_warn"
297: : "doclet.Type_Parameters_dup_warn",
298: paramName);
299: }
300: result.appendOutput(processParamTag(isNonTypeParams,
301: writer, pt, pt.parameterName(),
302: alreadyDocumented.size() == 0));
303: alreadyDocumented.add(rank);
304: }
305: }
306: return result;
307: }
308:
309: /**
310: * Convert the individual ParamTag into TagletOutput.
311: *
312: * @param isNonTypeParams true if this is just a regular param tag. False
313: * if this is a type param tag.
314: * @param writer the taglet writer for output writing.
315: * @param paramTag the tag whose inline tags will be printed.
316: * @param name the name of the parameter. We can't rely on
317: * the name in the param tag because we might be
318: * inheriting documentation.
319: * @param isFirstParam true if this is the first param tag being printed.
320: *
321: */
322: private TagletOutput processParamTag(boolean isNonTypeParams,
323: TagletWriter writer, ParamTag paramTag, String name,
324: boolean isFirstParam) {
325: TagletOutput result = writer.getOutputInstance();
326: String header = writer.configuration().getText(
327: isNonTypeParams ? "doclet.Parameters"
328: : "doclet.TypeParameters");
329: if (isFirstParam) {
330: result.appendOutput(writer.getParamHeader(header));
331: }
332: result.appendOutput(writer.paramTagOutput(paramTag, name));
333: return result;
334: }
335: }
|