/**
   * Determines whether or not the given AST is in a valid hash code method. A valid hash code
   * method is considered to be a method of the signature {@code public int hashCode()}.
   *
   * @param ast the AST from which to search for an enclosing hash code method definition
   * @return {@code true} if {@code ast} is in the scope of a valid hash code method
   */
  private boolean isInHashCodeMethod(DetailAST ast) {
    // if not in a code block, can't be in hashCode()
    if (!ScopeUtils.inCodeBlock(ast)) {
      return false;
    }

    // find the method definition AST
    DetailAST methodDefAST = ast.getParent();
    while (null != methodDefAST && TokenTypes.METHOD_DEF != methodDefAST.getType()) {
      methodDefAST = methodDefAST.getParent();
    }

    if (null == methodDefAST) {
      return false;
    }

    // Check for 'hashCode' name.
    final DetailAST identAST = methodDefAST.findFirstToken(TokenTypes.IDENT);
    if (!"hashCode".equals(identAST.getText())) {
      return false;
    }

    // Check for no arguments.
    final DetailAST paramAST = methodDefAST.findFirstToken(TokenTypes.PARAMETERS);
    // we are in a 'public int hashCode()' method! The compiler will ensure
    // the method returns an 'int' and is public.
    return 0 == paramAST.getChildCount();
  }
  /**
   * process modifiers
   *
   * @param ast ast of Modifiers
   */
  private void processModifiers(DetailAST ast) {

    final ScopeState state = scopeStates.peek();
    if (ast.findFirstToken(TokenTypes.LITERAL_STATIC) != null) {
      if (state.currentScopeState > STATE_STATIC_VARIABLE_DEF) {
        if (!ignoreModifiers || state.currentScopeState > STATE_INSTANCE_VARIABLE_DEF) {
          log(ast, MSG_STATIC);
        }
      } else {
        state.currentScopeState = STATE_STATIC_VARIABLE_DEF;
      }
    } else {
      if (state.currentScopeState > STATE_INSTANCE_VARIABLE_DEF) {
        log(ast, MSG_INSTANCE);
      } else if (state.currentScopeState == STATE_STATIC_VARIABLE_DEF) {
        state.declarationAccess = Scope.PUBLIC;
        state.currentScopeState = STATE_INSTANCE_VARIABLE_DEF;
      }
    }

    final Scope access = ScopeUtils.getScopeFromMods(ast);
    if (state.declarationAccess.compareTo(access) > 0) {
      if (!ignoreModifiers) {
        log(ast, MSG_ACCESS);
      }
    } else {
      state.declarationAccess = access;
    }
  }
  /**
   * Finds the constant definition that contains aAST.
   *
   * @param ast the AST
   * @return the constant def or null if ast is not contained in a constant definition
   */
  private DetailAST findContainingConstantDef(DetailAST ast) {
    DetailAST varDefAST = ast;
    while (varDefAST != null
        && varDefAST.getType() != TokenTypes.VARIABLE_DEF
        && varDefAST.getType() != TokenTypes.ENUM_CONSTANT_DEF) {
      varDefAST = varDefAST.getParent();
    }

    // no containing variable definition?
    if (varDefAST == null) {
      return null;
    }

    // implicit constant?
    if (ScopeUtils.inInterfaceOrAnnotationBlock(varDefAST)
        || varDefAST.getType() == TokenTypes.ENUM_CONSTANT_DEF) {
      return varDefAST;
    }

    // explicit constant
    final DetailAST modifiersAST = varDefAST.findFirstToken(TokenTypes.MODIFIERS);
    if (modifiersAST.branchContains(TokenTypes.FINAL)) {
      return varDefAST;
    }

    return null;
  }
    /** {@inheritDoc} */
    @Override
    public boolean isValidOn(final DetailAST ast) {
      final int type = ast.getType();

      return type == TokenTypes.METHOD_DEF
          && !ast.branchContains(TokenTypes.LITERAL_STATIC)
          && ScopeUtils.getScopeFromMods(ast.findFirstToken(TokenTypes.MODIFIERS)) != Scope.PRIVATE;
    }
  @Override
  public void visitToken(DetailAST ast) {
    // do not check local variables and
    // fields declared in interface/annotations
    if (ScopeUtils.isLocalVariableDef(ast) || ScopeUtils.inInterfaceOrAnnotationBlock(ast)) {
      return;
    }

    final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
    if (assign == null) {
      // no assign - no check
      return;
    }

    final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
    if (modifiers != null && modifiers.branchContains(TokenTypes.FINAL)) {
      // do not check final variables
      return;
    }

    final DetailAST type = ast.findFirstToken(TokenTypes.TYPE);
    final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
    final DetailAST exprStart = assign.getFirstChild().getFirstChild();
    if (isObjectType(type) && exprStart.getType() == TokenTypes.LITERAL_NULL) {
      log(ident, MSG_KEY, ident.getText(), "null");
    }

    final int primitiveType = type.getFirstChild().getType();
    if (primitiveType == TokenTypes.LITERAL_BOOLEAN
        && exprStart.getType() == TokenTypes.LITERAL_FALSE) {
      log(ident, MSG_KEY, ident.getText(), "false");
    }
    if (isNumericType(primitiveType) && isZero(exprStart)) {
      log(ident, MSG_KEY, ident.getText(), "0");
    }
    if (primitiveType == TokenTypes.LITERAL_CHAR
        && (isZero(exprStart)
            || exprStart.getType() == TokenTypes.CHAR_LITERAL
                && "'\\0'".equals(exprStart.getText()))) {
      log(ident, MSG_KEY, ident.getText(), "\\0");
    }
  }
 /** {@inheritDoc} */
 @Override
 public boolean isValidOn(final DetailAST ast) {
   final int type = ast.getType();
   return type == TokenTypes.PACKAGE_DEF
       || type == TokenTypes.CLASS_DEF
       || type == TokenTypes.INTERFACE_DEF
       || type == TokenTypes.ENUM_DEF
       || type == TokenTypes.ANNOTATION_DEF
       || type == TokenTypes.METHOD_DEF
       || type == TokenTypes.CTOR_DEF
       || type == TokenTypes.VARIABLE_DEF && !ScopeUtils.isLocalVariableDef(ast);
 }
  @Override
  public void visitToken(DetailAST ast) {
    switch (ast.getType()) {
      case TokenTypes.OBJBLOCK:
      case TokenTypes.SLIST:
      case TokenTypes.LITERAL_FOR:
      case TokenTypes.METHOD_DEF:
      case TokenTypes.CTOR_DEF:
      case TokenTypes.STATIC_INIT:
      case TokenTypes.INSTANCE_INIT:
        scopeStack.push(new HashMap<String, DetailAST>());
        break;

      case TokenTypes.PARAMETER_DEF:
        if (!inLambda(ast)
            && !ast.branchContains(TokenTypes.FINAL)
            && !inAbstractOrNativeMethod(ast)
            && !ScopeUtils.inInterfaceBlock(ast)) {
          insertVariable(ast);
        }
        break;
      case TokenTypes.VARIABLE_DEF:
        if (ast.getParent().getType() != TokenTypes.OBJBLOCK
            && isVariableInForInit(ast)
            && shouldCheckEnhancedForLoopVariable(ast)
            && !ast.branchContains(TokenTypes.FINAL)) {
          insertVariable(ast);
        }
        break;

      case TokenTypes.IDENT:
        final int parentType = ast.getParent().getType();
        if (isAssignOperator(parentType) && ast.getParent().getFirstChild() == ast) {
          removeVariable(ast);
        }
        break;

      default:
    }
  }
    /** {@inheritDoc} */
    @Override
    public boolean isValidOn(final DetailAST ast) {
      final int type = ast.getType();

      return type == TokenTypes.VARIABLE_DEF && !ScopeUtils.isLocalVariableDef(ast);
    }