/**
  * 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(
     Element e,
     boolean isParams,
     List<? extends DocTree> paramTags,
     Map<String, String> rankMap,
     TagletWriter writer,
     Set<String> alreadyDocumented) {
   Messages messages = writer.configuration().getMessages();
   Content result = writer.getOutputInstance();
   if (!paramTags.isEmpty()) {
     CommentHelper ch = writer.configuration().utils.getCommentHelper(e);
     for (DocTree dt : paramTags) {
       String paramName = isParams ? ch.getParameterName(dt) : "<" + ch.getParameterName(dt) + ">";
       if (!rankMap.containsKey(ch.getParameterName(dt))) {
         messages.warning(
             ch.getDocTreePath(dt),
             isParams ? "doclet.Parameters_warn" : "doclet.Type_Parameters_warn",
             paramName);
       }
       String rank = rankMap.get(ch.getParameterName(dt));
       if (rank != null && alreadyDocumented.contains(rank)) {
         messages.warning(
             ch.getDocTreePath(dt),
             isParams ? "doclet.Parameters_dup_warn" : "doclet.Type_Parameters_dup_warn",
             paramName);
       }
       result.addContent(
           processParamTag(
               e, isParams, writer, dt, ch.getParameterName(dt), alreadyDocumented.isEmpty()));
       alreadyDocumented.add(rank);
     }
   }
   return result;
 }
 /** {@inheritDoc} */
 public void inherit(DocFinder.Input input, DocFinder.Output output) {
   Utils utils = input.utils;
   if (input.tagId == null) {
     input.isTypeVariableParamTag = ((ParamTree) input.docTreeInfo.docTree).isTypeParameter();
     ExecutableElement ee = (ExecutableElement) input.docTreeInfo.element;
     CommentHelper ch = utils.getCommentHelper(ee);
     List<? extends Element> parameters =
         input.isTypeVariableParamTag ? ee.getTypeParameters() : ee.getParameters();
     String target = ch.getParameterName(input.docTreeInfo.docTree);
     for (int i = 0; i < parameters.size(); i++) {
       Element e = parameters.get(i);
       String pname =
           input.isTypeVariableParamTag
               ? utils.getTypeName(e.asType(), false)
               : utils.getSimpleName(e);
       if (pname.equals(target)) {
         input.tagId = String.valueOf(i);
         break;
       }
     }
   }
   ExecutableElement md = (ExecutableElement) input.element;
   CommentHelper ch = utils.getCommentHelper(md);
   List<? extends DocTree> tags =
       input.isTypeVariableParamTag ? utils.getTypeParamTrees(md) : utils.getParamTrees(md);
   List<? extends Element> parameters =
       input.isTypeVariableParamTag ? md.getTypeParameters() : md.getParameters();
   Map<String, String> rankMap = getRankMap(utils, parameters);
   for (DocTree tag : tags) {
     String paramName = ch.getParameterName(tag);
     if (rankMap.containsKey(paramName) && rankMap.get(paramName).equals((input.tagId))) {
       output.holder = input.element;
       output.holderTag = tag;
       output.inlineTags = ch.getBody(utils.configuration, tag);
       return;
     }
   }
 }