/**
   * Checks a set of tags for matching throws.
   *
   * @param tags the tags to check
   * @param throwsList the throws to check
   * @param reportExpectedTags whether we should report if do not find expected tag
   */
  private void checkThrowsTags(
      List<JavadocTag> tags, List<ExceptionInfo> throwsList, boolean reportExpectedTags) {
    // Loop over the tags, checking to see they exist in the throws.
    // The foundThrows used for performance only
    final Set<String> foundThrows = Sets.newHashSet();
    final ListIterator<JavadocTag> tagIt = tags.listIterator();
    while (tagIt.hasNext()) {
      final JavadocTag tag = tagIt.next();

      if (!tag.isThrowsTag()) {
        continue;
      }
      tagIt.remove();

      // Loop looking for matching throw
      final String documentedEx = tag.getFirstArg();
      final Token token = new Token(tag.getFirstArg(), tag.getLineNo(), tag.getColumnNo());
      final AbstractClassInfo documentedCI = createClassInfo(token, getCurrentClassName());
      final boolean found =
          foundThrows.contains(documentedEx) || isInThrows(throwsList, documentedCI, foundThrows);

      // Handle extra JavadocTag.
      if (!found) {
        boolean reqd = true;
        if (allowUndeclaredRTE) {
          reqd = !isUnchecked(documentedCI.getClazz());
        }

        if (reqd && validateThrows) {
          log(
              tag.getLineNo(),
              tag.getColumnNo(),
              MSG_UNUSED_TAG,
              JavadocTagInfo.THROWS.getText(),
              tag.getFirstArg());
        }
      }
    }
    // Now dump out all throws without tags :- unless
    // the user has chosen to suppress these problems
    if (!allowMissingThrowsTags && reportExpectedTags) {
      for (ExceptionInfo ei : throwsList) {
        if (!ei.isFound()) {
          final Token fi = ei.getName();
          log(
              fi.getLineNo(),
              fi.getColumnNo(),
              MSG_EXCPECTED_TAG,
              JavadocTagInfo.THROWS.getText(),
              fi.getText());
        }
      }
    }
  }
  /**
   * Checks a set of tags for matching parameters.
   *
   * @param tags the tags to check
   * @param parent the node which takes the parameters
   * @param reportExpectedTags whether we should report if do not find expected tag
   */
  private void checkParamTags(
      final List<JavadocTag> tags, final DetailAST parent, boolean reportExpectedTags) {
    final List<DetailAST> params = getParameters(parent);
    final List<DetailAST> typeParams = CheckUtils.getTypeParameters(parent);

    // Loop over the tags, checking to see they exist in the params.
    final ListIterator<JavadocTag> tagIt = tags.listIterator();
    while (tagIt.hasNext()) {
      final JavadocTag tag = tagIt.next();

      if (!tag.isParamTag()) {
        continue;
      }

      tagIt.remove();

      final String arg1 = tag.getFirstArg();
      boolean found = removeMatchingParam(params, arg1);

      if (CommonUtils.startsWithChar(arg1, '<') && CommonUtils.endsWithChar(arg1, '>')) {
        // Loop looking for matching type param
        final Iterator<DetailAST> typeParamsIt = typeParams.iterator();
        while (typeParamsIt.hasNext()) {
          final DetailAST typeParam = typeParamsIt.next();
          if (typeParam
              .findFirstToken(TokenTypes.IDENT)
              .getText()
              .equals(arg1.substring(1, arg1.length() - 1))) {
            found = true;
            typeParamsIt.remove();
            break;
          }
        }
      }

      // Handle extra JavadocTag
      if (!found) {
        log(tag.getLineNo(), tag.getColumnNo(), MSG_UNUSED_TAG, "@param", arg1);
      }
    }

    // Now dump out all type parameters/parameters without tags :- unless
    // the user has chosen to suppress these problems
    if (!allowMissingParamTags && reportExpectedTags) {
      for (DetailAST param : params) {
        log(param, MSG_EXCPECTED_TAG, JavadocTagInfo.PARAM.getText(), param.getText());
      }

      for (DetailAST typeParam : typeParams) {
        log(
            typeParam,
            MSG_EXCPECTED_TAG,
            JavadocTagInfo.PARAM.getText(),
            "<" + typeParam.findFirstToken(TokenTypes.IDENT).getText() + ">");
      }
    }
  }