/* * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.doclets.internal.toolkit.taglets; import java.util.*; import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.Content; import com.sun.tools.doclets.internal.toolkit.util.*; /** * A taglet that represents the @param tag. * * <p><b>This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> * * @author Jamie Ho * @since 1.4 */ @Deprecated public class ParamTaglet extends BaseTaglet implements InheritableTaglet { /** * Construct a ParamTaglet. */ public ParamTaglet() { name = "param"; } /** * Given an array of <code>Parameter</code>s, return * a name/rank number map. If the array is null, then * null is returned. * @param params The array of parmeters (from type or executable member) to * check. * @return a name-rank number map. */ private static Map<String,String> getRankMap(Object[] params){ if (params == null) { return null; } HashMap<String,String> result = new HashMap<>(); for (int i = 0; i < params.length; i++) { String name = params[i] instanceof Parameter ? ((Parameter) params[i]).name() : ((TypeVariable) params[i]).typeName(); result.put(name, String.valueOf(i)); } return result; } /** * {@inheritDoc} */ public void inherit(DocFinder.Input input, DocFinder.Output output) { if (input.tagId == null) { input.isTypeVariableParamTag = ((ParamTag) input.tag).isTypeParameter(); Object[] parameters = input.isTypeVariableParamTag ? (Object[]) ((MethodDoc) input.tag.holder()).typeParameters() : (Object[]) ((MethodDoc) input.tag.holder()).parameters(); String target = ((ParamTag) input.tag).parameterName(); int i; for (i = 0; i < parameters.length; i++) { String name = parameters[i] instanceof Parameter ? ((Parameter) parameters[i]).name() : ((TypeVariable) parameters[i]).typeName(); if (name.equals(target)) { input.tagId = String.valueOf(i); break; } } if (i == parameters.length) { //Someone used {@inheritDoc} on an invalid @param tag. //We don't know where to inherit from. //XXX: in the future when Configuration is available here, //print a warning for this mistake. return; } } ParamTag[] tags = input.isTypeVariableParamTag ? ((MethodDoc)input.element).typeParamTags() : ((MethodDoc)input.element).paramTags(); Map<String, String> rankMap = getRankMap(input.isTypeVariableParamTag ? (Object[]) ((MethodDoc)input.element).typeParameters() : (Object[]) ((MethodDoc)input.element).parameters()); for (ParamTag tag : tags) { if (rankMap.containsKey(tag.parameterName()) && rankMap.get(tag.parameterName()).equals((input.tagId))) { output.holder = input.element; output.holderTag = tag; output.inlineTags = input.isFirstSentence ? tag.firstSentenceTags() : tag.inlineTags(); return; } } } /** * {@inheritDoc} */ public boolean inField() { return false; } /** * {@inheritDoc} */ public boolean inMethod() { return true; } /** * {@inheritDoc} */ public boolean inOverview() { return false; } /** * {@inheritDoc} */ public boolean inPackage() { return false; } /** * {@inheritDoc} */ public boolean inType() { return true; } /** * {@inheritDoc} */ public boolean isInlineTag() { return false; } /** * Given an array of <code>ParamTag</code>s,return its string representation. * @param holder the member that holds the param tags. * @param writer the TagletWriter that will write this tag. * @return the TagletOutput representation of these <code>ParamTag</code>s. */ public Content getTagletOutput(Doc holder, TagletWriter writer) { if (holder instanceof ExecutableMemberDoc) { ExecutableMemberDoc member = (ExecutableMemberDoc) holder; Content output = getTagletOutput(false, member, writer, member.typeParameters(), member.typeParamTags()); output.addContent(getTagletOutput(true, member, writer, member.parameters(), member.paramTags())); return output; } else { ClassDoc classDoc = (ClassDoc) holder; return getTagletOutput(false, classDoc, writer, classDoc.typeParameters(), classDoc.typeParamTags()); } } /** * Given an array of <code>ParamTag</code>s,return its string representation. * Try to inherit the param tags that are missing. * * @param holder the doc that holds the param tags. * @param writer the TagletWriter that will write this tag. * @param formalParameters The array of parmeters (from type or executable * member) to check. * * @return the TagletOutput representation of these <code>ParamTag</code>s. */ private Content getTagletOutput(boolean isNonTypeParams, Doc holder, TagletWriter writer, Object[] formalParameters, ParamTag[] paramTags) { Content result = writer.getOutputInstance(); Set<String> alreadyDocumented = new HashSet<>(); if (paramTags.length > 0) { result.addContent( processParamTags(isNonTypeParams, paramTags, getRankMap(formalParameters), writer, alreadyDocumented) ); } if (alreadyDocumented.size() != formalParameters.length) { //Some parameters are missing corresponding @param tags. //Try to inherit them. result.addContent(getInheritedTagletOutput (isNonTypeParams, holder, writer, formalParameters, alreadyDocumented)); } return result; } /** * Loop through each indivitual parameter. It it does not have a * corresponding param tag, try to inherit it. */ private Content getInheritedTagletOutput(boolean isNonTypeParams, Doc holder, TagletWriter writer, Object[] formalParameters, Set<String> alreadyDocumented) { Content result = writer.getOutputInstance(); if ((! alreadyDocumented.contains(null)) && holder instanceof MethodDoc) { for (int i = 0; i < formalParameters.length; i++) { if (alreadyDocumented.contains(String.valueOf(i))) { continue; } //This parameter does not have any @param documentation. //Try to inherit it. DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), new DocFinder.Input((MethodDoc) holder, this, String.valueOf(i), ! isNonTypeParams)); if (inheritedDoc.inlineTags != null && inheritedDoc.inlineTags.length > 0) { result.addContent( processParamTag(isNonTypeParams, writer, (ParamTag) inheritedDoc.holderTag, isNonTypeParams ? ((Parameter) formalParameters[i]).name(): ((TypeVariable) formalParameters[i]).typeName(), alreadyDocumented.size() == 0)); } alreadyDocumented.add(String.valueOf(i)); } } return result; } /** * Given an array of <code>Tag</code>s representing this custom * tag, return its string representation. Print a warning for param * tags that do not map to parameters. Print a warning for param * tags that are duplicated. * * @param paramTags the array of <code>ParamTag</code>s to convert. * @param writer the TagletWriter that will write this tag. * @param alreadyDocumented the set of exceptions that have already * been documented. * @param rankMap a {@link java.util.Map} which holds ordering * information about the parameters. * @param rankMap a {@link java.util.Map} which holds a mapping * of a rank of a parameter to its name. This is * used to ensure that the right name is used * when parameter documentation is inherited. * @return the Content representation of this <code>Tag</code>. */ private Content processParamTags(boolean isNonTypeParams, ParamTag[] paramTags, Map<String, String> rankMap, TagletWriter writer, Set<String> alreadyDocumented) { Content result = writer.getOutputInstance(); if (paramTags.length > 0) { for (ParamTag pt : paramTags) { String paramName = isNonTypeParams ? pt.parameterName() : "<" + pt.parameterName() + ">"; if (!rankMap.containsKey(pt.parameterName())) { writer.getMsgRetriever().warning(pt.position(), isNonTypeParams ? "doclet.Parameters_warn" : "doclet.Type_Parameters_warn", paramName); } String rank = rankMap.get(pt.parameterName()); if (rank != null && alreadyDocumented.contains(rank)) { writer.getMsgRetriever().warning(pt.position(), isNonTypeParams ? "doclet.Parameters_dup_warn" : "doclet.Type_Parameters_dup_warn", paramName); } result.addContent(processParamTag(isNonTypeParams, writer, pt, pt.parameterName(), alreadyDocumented.size() == 0)); alreadyDocumented.add(rank); } } return result; } /** * Convert the individual ParamTag into Content. * * @param isNonTypeParams true if this is just a regular param tag. False * if this is a type param tag. * @param writer the taglet writer for output writing. * @param paramTag the tag whose inline tags will be printed. * @param name the name of the parameter. We can't rely on * the name in the param tag because we might be * inheriting documentation. * @param isFirstParam true if this is the first param tag being printed. * */ private Content processParamTag(boolean isNonTypeParams, TagletWriter writer, ParamTag paramTag, String name, boolean isFirstParam) { Content result = writer.getOutputInstance(); String header = writer.configuration().getText( isNonTypeParams ? "doclet.Parameters" : "doclet.TypeParameters"); if (isFirstParam) { result.addContent(writer.getParamHeader(header)); } result.addContent(writer.paramTagOutput(paramTag, name)); return result; } }