/**
  * Checks if the given parameter is final.
  *
  * @param param parameter to check.
  */
 private void checkParam(final DetailAST param) {
   if (!param.branchContains(TokenTypes.FINAL)
       && !isIgnoredParam(param)
       && !CheckUtils.isReceiverParameter(param)) {
     final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT);
     final DetailAST firstNode = CheckUtils.getFirstNode(param);
     log(firstNode.getLineNo(), firstNode.getColumnNo(), MSG_KEY, paramName.getText());
   }
 }
  @Override
  public void visitToken(DetailAST ast) {
    equalsMethods.clear();

    // examine method definitions for equals methods
    final DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK);
    if (objBlock != null) {
      DetailAST child = objBlock.getFirstChild();
      boolean hasEqualsObject = false;
      while (child != null) {
        if (child.getType() == TokenTypes.METHOD_DEF && CheckUtils.isEqualsMethod(child)) {
          if (isFirstParameterObject(child)) {
            hasEqualsObject = true;
          } else {
            equalsMethods.add(child);
          }
        }
        child = child.getNextSibling();
      }

      // report equals method definitions
      if (!hasEqualsObject) {
        for (DetailAST equalsAST : equalsMethods) {
          final DetailAST nameNode = equalsAST.findFirstToken(TokenTypes.IDENT);
          log(nameNode.getLineNo(), nameNode.getColumnNo(), MSG_KEY);
        }
      }
    }
  }
  /**
   * Checks the Javadoc for a method.
   *
   * @param ast the token for the method
   * @param comment the Javadoc comment
   */
  private void checkComment(DetailAST ast, TextBlock comment) {
    final List<JavadocTag> tags = getMethodTags(comment);

    if (hasShortCircuitTag(ast, tags)) {
      return;
    }

    final Iterator<JavadocTag> it = tags.iterator();
    if (ast.getType() != TokenTypes.ANNOTATION_FIELD_DEF) {
      // Check for inheritDoc
      boolean hasInheritDocTag = false;
      while (it.hasNext() && !hasInheritDocTag) {
        hasInheritDocTag = it.next().isInheritDocTag();
      }

      checkParamTags(tags, ast, !hasInheritDocTag);
      checkThrowsTags(tags, getThrows(ast), !hasInheritDocTag);
      if (CheckUtils.isVoidMethod(ast)) {
        checkReturnTag(tags, ast.getLineNo(), !hasInheritDocTag);
      }
    }

    // Dump out all unused tags
    for (JavadocTag javadocTag : tags) {
      if (!javadocTag.isSeeOrInheritDocTag()) {
        log(javadocTag.getLineNo(), MSG_UNUSED_TAG_GENERAL);
      }
    }
  }
  /**
   * 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() + ">");
      }
    }
  }
  /**
   * Creates new parameter set for given method.
   *
   * @param ast a method for process.
   */
  private void visitMethodParameters(DetailAST ast) {
    DetailAST parameterDefAST = ast.findFirstToken(TokenTypes.PARAMETER_DEF);

    while (parameterDefAST != null) {
      if (parameterDefAST.getType() == TokenTypes.PARAMETER_DEF
          && !CheckUtils.isReceiverParameter(parameterDefAST)) {
        final DetailAST param = parameterDefAST.findFirstToken(TokenTypes.IDENT);
        parameterNames.add(param.getText());
      }
      parameterDefAST = parameterDefAST.getNextSibling();
    }
  }
 /**
  * @param expr node to check.
  * @return true if given node contains numeric constant for zero.
  */
 private static boolean isZero(DetailAST expr) {
   final int type = expr.getType();
   switch (type) {
     case TokenTypes.NUM_FLOAT:
     case TokenTypes.NUM_DOUBLE:
     case TokenTypes.NUM_INT:
     case TokenTypes.NUM_LONG:
       final String text = expr.getText();
       return Double.compare(CheckUtils.parseDouble(text, type), 0.0) == 0;
     default:
       return false;
   }
 }
 /**
  * The JavadocMethodCheck is about to report a missing Javadoc. This hook can be used by derived
  * classes to allow a missing javadoc in some situations. The default implementation checks {@code
  * allowMissingJavadoc} and {@code allowMissingPropertyJavadoc} properties, do not forget to call
  * {@code super.isMissingJavadocAllowed(ast)} in case you want to keep this logic.
  *
  * @param ast the tree node for the method or constructor.
  * @return True if this method or constructor doesn't need Javadoc.
  */
 protected boolean isMissingJavadocAllowed(final DetailAST ast) {
   return allowMissingJavadoc
       || allowMissingPropertyJavadoc
           && (CheckUtils.isSetterMethod(ast) || CheckUtils.isGetterMethod(ast))
       || matchesSkipRegex(ast);
 }
 @Override
 public void leaveToken(DetailAST literalIf) {
   if (!CheckUtils.isElseIf(literalIf)) {
     nestOut();
   }
 }
 @Override
 public void visitToken(DetailAST literalIf) {
   if (!CheckUtils.isElseIf(literalIf)) {
     nestIn(literalIf, MSG_KEY);
   }
 }