All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.pmd.lang.java.ast.ASTVariableId Maven / Gradle / Ivy

There is a newer version: 7.7.0
Show newest version
/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;

// @formatter:off
/**
 * Represents an identifier in the context of variable or parameter declarations (not their use in
 * expressions). Such a node declares a name in the scope it's defined in, and can occur in the following
 * contexts:
 *
 * 
    *
  • Field and enum constant declarations; *
  • Local variable declarations; *
  • Method, constructor and lambda parameter declarations; *
  • Exception parameter declarations occurring in catch clauses; *
  • Resource declarations occurring in try-with-resources statements. *
* *

Since this node conventionally represents the declared variable in PMD, * it owns a {@link JVariableSymbol} and can provide access to * {@linkplain #getLocalUsages() variable usages}. * *

 *
 * VariableId ::= <IDENTIFIER> {@link ASTArrayDimensions ArrayDimensions}?
 *
 * 
* *

Note: This node has been called ASTVariableDeclaratorId in PMD 6. */ // @formatter:on public final class ASTVariableId extends AbstractTypedSymbolDeclarator implements ModifierOwner { private String name; private List usages = Collections.emptyList(); ASTVariableId(int id) { super(id); } @Override protected R acceptVisitor(JavaVisitor visitor, P data) { return visitor.visit(this, data); } /** * Returns an unmodifiable list of the usages of this variable that * are made in this file. Note that for a record component, this returns * usages both for the formal parameter symbol and its field counterpart. * *

Note that a variable initializer is not part of the usages * (though this should be evident from the return type). */ public List getLocalUsages() { return usages; } void addUsage(ASTNamedReferenceExpr usage) { if (usages.isEmpty()) { usages = new ArrayList<>(4); //make modifiable } usages.add(usage); } /** * Returns the extra array dimensions associated with this variable. * For example in the declaration {@code int a[]}, {@link #getTypeNode()} * returns {@code int}, and this method returns the dimensions that follow * the variable ID. Returns null if there are no such dimensions. */ @Nullable public ASTArrayDimensions getExtraDimensions() { return children(ASTArrayDimensions.class).first(); } @NonNull @Override public ASTModifierList getModifiers() { // delegates modifiers return getModifierOwnerParent().getModifiers(); } /** * Return true if the declared variable is static. * There may not be an explicit final modifier, e.g. for enum constants. */ public boolean isFinal() { return hasModifiers(JModifier.FINAL); } /** * Return true if the declared variable is static. * There may not be an explicit static modifier, e.g. for enum constants. * * @since 7.1.0 */ public boolean isStatic() { return hasModifiers(JModifier.STATIC); } @Override public Visibility getVisibility() { return isPatternBinding() ? Visibility.V_LOCAL : getModifierOwnerParent().getVisibility(); } private ModifierOwner getModifierOwnerParent() { JavaNode parent = getParent(); if (parent instanceof ASTVariableDeclarator) { return (ModifierOwner) parent.getParent(); } return (ModifierOwner) parent; } /** * Return true if this variable has no name. The name is then equal to {@code "_"}. * A variable declaration with this name does not actually declare a variable in * the current scope, since Java 22. In Java 9 to 21, the identifier {@code _} is * restricted and cannot be used to name a variable. Before Java 9, it is a regular * identifier. */ public boolean isUnnamed() { return "_".equals(name) && getLanguageVersion().compareToVersion("21-preview") >= 0; } /** Returns the name of the variable. */ public String getName() { return name; } void setName(String name) { this.name = name; } /** * Returns true if the declared variable has an array type. */ public boolean hasArrayType() { return getExtraDimensions() != null || getTypeNode() instanceof ASTArrayType; } /** * Returns true if this nodes declares an exception parameter in * a {@code catch} statement. */ public boolean isExceptionBlockParameter() { return getParent() instanceof ASTCatchParameter; } /** * Returns true if this node declares a formal parameter for a method * declaration or a lambda expression. */ public boolean isFormalParameter() { return getParent() instanceof ASTFormalParameter || isLambdaParameter(); } /** * Returns true if this node declares a record component. The symbol * born by this node is the symbol of the corresponding field (not the * formal parameter of the record constructor). */ public boolean isRecordComponent() { return getParent() instanceof ASTRecordComponent; } /** * Returns true if this node declares a local variable from within * a regular {@link ASTLocalVariableDeclaration}. */ public boolean isLocalVariable() { return ancestors().get(1) instanceof ASTLocalVariableDeclaration && !isResourceDeclaration() && !isForeachVariable(); } /** * Returns true if this node is a variable declared in a * {@linkplain ASTForeachStatement foreach loop}. */ public boolean isForeachVariable() { // Foreach/LocalVarDecl/VarDeclarator/VarDeclId return ancestors().get(2) instanceof ASTForeachStatement; } /** * Returns true if this node is a variable declared in the init clause * of a {@linkplain ASTForStatement for loop}. */ public boolean isForLoopVariable() { // For/ForInit/LocalVarDecl/VarDeclarator/VarDeclId return ancestors().get(2) instanceof ASTForInit; } /** * Returns true if this node declares a formal parameter for * a lambda expression. In that case, the type of this parameter * is not necessarily inferred, see {@link #isTypeInferred()}. */ public boolean isLambdaParameter() { return getParent() instanceof ASTLambdaParameter; } /** * Returns true if this node declares a field from a regular * {@link ASTFieldDeclaration}. This returns false for enum * constants (use {@link JVariableSymbol#isField() getSymbol().isField()} * if you want that). */ public boolean isField() { return ancestors().get(1) instanceof ASTFieldDeclaration; } /** * Returns true if this node declares an enum constant. */ public boolean isEnumConstant() { return getParent() instanceof ASTEnumConstant; } /** * Returns true if this declarator id declares a resource in a try-with-resources statement. */ public boolean isResourceDeclaration() { // Resource/LocalVariableDeclaration/VariableDeclarator return getParent().getParent().getParent() instanceof ASTResource; } /** * 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;}. * *

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 getTypeNode() == null; } /** * Returns true if this is a binding variable in a * {@linkplain ASTPattern pattern}. */ public boolean isPatternBinding() { return getParent() instanceof ASTPattern; } /** * Returns the initializer of the variable, or null if it doesn't exist. */ @Nullable public ASTExpression getInitializer() { if (getParent() instanceof ASTVariableDeclarator) { return ((ASTVariableDeclarator) getParent()).getInitializer(); } return null; } /** * 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 @Nullable public Node getTypeNameNode() { return getTypeNode(); } /** * 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). * *

The type of the returned node is not necessarily the type of this * node. See {@link #getTypeMirror()} for an explanation. * * @return the type node, or {@code null} if there is no explicit type, * e.g. if {@link #isTypeInferred()} returns true. */ public @Nullable ASTType getTypeNode() { ModifierOwner parent = getModifierOwnerParent(); return parent.firstChild(ASTType.class); } // @formatter:off /** * Returns the type of the declared variable. The type of a declarator ID is *

    *
  • 1. not necessarily the same as the type written out at the * start of the declaration, e.g. {@code int a[];} *
  • 2. not necessarily the same as the types of other variables * declared in the same statement, e.g. {@code int a[], b;}. *
* *

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. * *

The returned type also takes into account whether this variable * is a varargs formal parameter. * *

The type of the declarator ID is thus always the real type of * the variable. */ // @formatter:on @Override @SuppressWarnings("PMD.UselessOverridingMethod") public @NonNull JTypeMirror getTypeMirror() { return super.getTypeMirror(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy