/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */
/* Generated By:JJTree: Do not edit this line. ASTVariableDeclaratorId.java */

package net.sourceforge.pmd.lang.java.ast;

import java.util.List;

import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;

public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dimensionable {

    private int arrayDepth;
    private VariableNameDeclaration nameDeclaration;
    private boolean explicitReceiverParameter = false;

    public ASTVariableDeclaratorId(int id) {
        super(id);
    }

    public ASTVariableDeclaratorId(JavaParser p, int id) {
        super(p, id);
    }

    /**
     * Accept the visitor. *
     */
    @Override
    public Object jjtAccept(JavaParserVisitor visitor, Object data) {
        return visitor.visit(this, data);
    }

    public VariableNameDeclaration getNameDeclaration() {
        return nameDeclaration;
    }

    public void setNameDeclaration(VariableNameDeclaration decl) {
        nameDeclaration = decl;
    }

    public List<NameOccurrence> getUsages() {
        return getScope().getDeclarations(VariableNameDeclaration.class).get(nameDeclaration);
    }

    public void bumpArrayDepth() {
        arrayDepth++;
    }

    @Override
    public int getArrayDepth() {
        return arrayDepth;
    }

    @Override
    public boolean isArray() {
        return arrayDepth > 0;
    }

    public boolean isExceptionBlockParameter() {
        return jjtGetParent().jjtGetParent() instanceof ASTTryStatement;
    }

    public void setExplicitReceiverParameter() {
        explicitReceiverParameter = true;
    }

    public boolean isExplicitReceiverParameter() {
        return explicitReceiverParameter;
    }


    /**
     * Returns true if the declared variable's type is inferred by
     * the compiler. In Java 8, this can happen if it's in a formal
     * parameter of a lambda with an inferred type (e.g. {@code (a, b) -> a + b}).
     * Since Java 10, the type of local variables can be inferred
     * too, e.g. {@code var i = 2;}.
     *
     * <p>This method returns true for declarator IDs in those contexts,
     * in which case {@link #getTypeNode()} returns {@code null},
     * since the type node is absent.
     */
    public boolean isTypeInferred() {
        return jjtGetParent() instanceof ASTLambdaExpression;
    }


    /**
     * Returns the first child of the node returned by {@link #getTypeNode()}.
     * The image of that node can usually be interpreted as the image of the
     * type.
     */
    // TODO unreliable, not typesafe and not useful, should be deprecated
    public Node getTypeNameNode() {
        ASTType type = getTypeNode();
        return type == null ? null : getTypeNode().jjtGetChild(0);
    }


    /**
     * Determines the type node of this variable id, that is, the type node
     * belonging to the variable declaration of this node (either a
     * FormalParameter, LocalVariableDeclaration or FieldDeclaration).
     *
     * <p>The type of the returned node is not necessarily the type of this
     * node. See {@link #getType()} for an explanation.
     *
     * @return the type node, or {@code null} if there is no explicit type,
     * e.g. if {@link #isTypeInferred()} returns true.
     */
    public ASTType getTypeNode() {
        if (jjtGetParent() instanceof ASTFormalParameter) {
            return ((ASTFormalParameter) jjtGetParent()).getTypeNode();
        } else if (isTypeInferred()) {
            // lambda expression with lax types. The type is inferred...
            return null;
        } else {
            Node n = jjtGetParent().jjtGetParent();
            if (n instanceof ASTLocalVariableDeclaration || n instanceof ASTFieldDeclaration) {
                return n.getFirstChildOfType(ASTType.class);
            }
        }
        return null;
    }

    // @formatter:off
    /**
     * Returns the type of the declared variable. The type of a declarator ID is
     * <ul>
     *   <li>1. not necessarily the same as the type written out at the
     *          start of the declaration, e.g. {@code int a[];}
     *   <li>2. not necessarily the same as the types of other variables
     *          declared in the same statement, e.g. {@code int a[], b;}.
     * </ul>
     *
     * <p>These are consequences of Java's allowing programmers to
     * declare additional pairs of brackets on declarator ids. The type
     * of the node returned by {@link #getTypeNode()} doesn't take into
     * account those additional array dimensions, whereas this node's
     * type takes into account the total number of dimensions, i.e.
     * those declared on this node plus those declared on the type node.
     *
     * <p>The returned type also takes into account whether this variable
     * is a varargs formal parameter.
     *
     * <p>The type of the declarator ID is thus always the real type of
     * the variable.
     */
    // @formatter:on
    @Override
    @SuppressWarnings("PMD.UselessOverridingMethod")
    public Class<?> getType() {
        return super.getType();
    }
}
