/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.core.dom; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import net.sourceforge.phpdt.internal.core.dom.NaiveASTFlattener; /** * Abstract superclass of all Abstract Syntax Tree (AST) node types. *
* An AST node represents a Java source code construct, such * as a name, type, expression, statement, or declaration. *
** Each AST node belongs to a unique AST instance, called the owning AST. * The children of an AST node always have the same owner as their parent node. * If a node from one AST is to be added to a different AST, the subtree must * be cloned first to ensure that the added nodes have the correct owning AST. *
*
* When an AST node is part of an AST, it has a unique parent node.
* Clients can navigate upwards, from child to parent, as well as downwards,
* from parent to child. Newly created nodes are unparented. When an
* unparented node is set as a child of a node (using a
* setCHILD
method), its parent link is set automatically
* and the parent link of the former child is set to null
.
* For nodes with properties that include a list of children (for example,
* Block
whose statements
property is a list
* of statements), adding or removing an element to/for the list property
* automatically updates the parent links. These lists support the
* List.set
method; however, the constraint that the same
* node cannot appear more than once means that this method cannot be used
* to swap elements without first removing the node.
*
* ASTs must not contain cycles. All operations that could create a cycle * detect this possibility and fail. *
** ASTs do not contain "holes" (missing subtrees). If a node is required to * have a certain property, a syntactically plausible initial value is * always supplied. *
** The hierarchy of AST node types has some convenient groupings marked * by abstract superclasses: *
Expression
Name
(a sub-kind of expression)Statement
Type
BodyDeclaration
* Abstract syntax trees may be hand constructed by clients, using the
* newTYPE
factory methods (see AST
) to
* create new nodes, and the various setCHILD
methods
* to connect them together.
*
* The class {@link ASTParser} parses a string * containing a Java source code and returns an abstract syntax tree * for it. The resulting nodes carry source ranges relating the node back to * the original source characters. The source range covers the construct * as a whole. *
** Each AST node carries bit flags, which may convey additional information about * the node. For instance, the parser uses a flag to indicate a syntax error. * Newly created nodes have no flags set. *
*
* Each AST node is capable of carrying an open-ended collection of
* client-defined properties. Newly created nodes have none.
* getProperty
and setProperty
are used to access
* these properties.
*
* AST nodes are thread-safe for readers provided there are no active writers.
* If one thread is modifying an AST, including creating new nodes or cloning
* existing ones, it is not safe for another thread to read, visit,
* write, create, or clone any of the nodes on the same AST.
* When synchronization is required, consider using the common AST
* object that owns the node; that is, use
* synchronize (node.getAST()) {...}
.
*
* ASTs also support the visitor pattern; see the class ASTVisitor
* for details.
*
* Compilation units created by ASTParser
from a
* source document can be serialized after arbitrary modifications
* with minimal loss of original formatting. See
* {@link CompilationUnit#recordModifications()} for details.
* See also {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite} for
* an alternative way to describe and serialize changes to a
* read-only AST.
*
AnonymousClassDeclaration
.
* @see AnonymousClassDeclaration
*/
public static final int ANONYMOUS_CLASS_DECLARATION = 1;
/**
* Node type constant indicating a node of type
* ArrayAccess
.
* @see ArrayAccess
*/
public static final int ARRAY_ACCESS = 2;
/**
* Node type constant indicating a node of type
* ArrayCreation
.
* @see ArrayCreation
*/
public static final int ARRAY_CREATION = 3;
/**
* Node type constant indicating a node of type
* ArrayInitializer
.
* @see ArrayInitializer
*/
public static final int ARRAY_INITIALIZER = 4;
/**
* Node type constant indicating a node of type
* ArrayType
.
* @see ArrayType
*/
public static final int ARRAY_TYPE = 5;
/**
* Node type constant indicating a node of type
* AssertStatement
.
* @see AssertStatement
*/
public static final int ASSERT_STATEMENT = 6;
/**
* Node type constant indicating a node of type
* Assignment
.
* @see Assignment
*/
public static final int ASSIGNMENT = 7;
/**
* Node type constant indicating a node of type
* Block
.
* @see Block
*/
public static final int BLOCK = 8;
/**
* Node type constant indicating a node of type
* BooleanLiteral
.
* @see BooleanLiteral
*/
public static final int BOOLEAN_LITERAL = 9;
/**
* Node type constant indicating a node of type
* BreakStatement
.
* @see BreakStatement
*/
public static final int BREAK_STATEMENT = 10;
/**
* Node type constant indicating a node of type
* CastExpression
.
* @see CastExpression
*/
public static final int CAST_EXPRESSION = 11;
/**
* Node type constant indicating a node of type
* CatchClause
.
* @see CatchClause
*/
public static final int CATCH_CLAUSE = 12;
/**
* Node type constant indicating a node of type
* CharacterLiteral
.
* @see CharacterLiteral
*/
public static final int CHARACTER_LITERAL = 13;
/**
* Node type constant indicating a node of type
* ClassInstanceCreation
.
* @see ClassInstanceCreation
*/
public static final int CLASS_INSTANCE_CREATION = 14;
/**
* Node type constant indicating a node of type
* CompilationUnit
.
* @see CompilationUnit
*/
public static final int COMPILATION_UNIT = 15;
/**
* Node type constant indicating a node of type
* ConditionalExpression
.
* @see ConditionalExpression
*/
public static final int CONDITIONAL_EXPRESSION = 16;
/**
* Node type constant indicating a node of type
* ConstructorInvocation
.
* @see ConstructorInvocation
*/
public static final int CONSTRUCTOR_INVOCATION = 17;
/**
* Node type constant indicating a node of type
* ContinueStatement
.
* @see ContinueStatement
*/
public static final int CONTINUE_STATEMENT = 18;
/**
* Node type constant indicating a node of type
* DoStatement
.
* @see DoStatement
*/
public static final int DO_STATEMENT = 19;
/**
* Node type constant indicating a node of type
* EmptyStatement
.
* @see EmptyStatement
*/
public static final int EMPTY_STATEMENT = 20;
/**
* Node type constant indicating a node of type
* ExpressionStatement
.
* @see ExpressionStatement
*/
public static final int EXPRESSION_STATEMENT = 21;
/**
* Node type constant indicating a node of type
* FieldAccess
.
* @see FieldAccess
*/
public static final int FIELD_ACCESS = 22;
/**
* Node type constant indicating a node of type
* FieldDeclaration
.
* @see FieldDeclaration
*/
public static final int FIELD_DECLARATION = 23;
/**
* Node type constant indicating a node of type
* ForStatement
.
* @see ForStatement
*/
public static final int FOR_STATEMENT = 24;
/**
* Node type constant indicating a node of type
* IfStatement
.
* @see IfStatement
*/
public static final int IF_STATEMENT = 25;
/**
* Node type constant indicating a node of type
* ImportDeclaration
.
* @see ImportDeclaration
*/
public static final int IMPORT_DECLARATION = 26;
/**
* Node type constant indicating a node of type
* InfixExpression
.
* @see InfixExpression
*/
public static final int INFIX_EXPRESSION = 27;
/**
* Node type constant indicating a node of type
* Initializer
.
* @see Initializer
*/
public static final int INITIALIZER = 28;
/**
* Node type constant indicating a node of type
* Javadoc
.
* @see Javadoc
*/
public static final int JAVADOC = 29;
/**
* Node type constant indicating a node of type
* LabeledStatement
.
* @see LabeledStatement
*/
public static final int LABELED_STATEMENT = 30;
/**
* Node type constant indicating a node of type
* MethodDeclaration
.
* @see MethodDeclaration
*/
public static final int METHOD_DECLARATION = 31;
/**
* Node type constant indicating a node of type
* MethodInvocation
.
* @see MethodInvocation
*/
public static final int METHOD_INVOCATION = 32;
/**
* Node type constant indicating a node of type
* NullLiteral
.
* @see NullLiteral
*/
public static final int NULL_LITERAL = 33;
/**
* Node type constant indicating a node of type
* NumberLiteral
.
* @see NumberLiteral
*/
public static final int NUMBER_LITERAL = 34;
/**
* Node type constant indicating a node of type
* PackageDeclaration
.
* @see PackageDeclaration
*/
public static final int PACKAGE_DECLARATION = 35;
/**
* Node type constant indicating a node of type
* ParenthesizedExpression
.
* @see ParenthesizedExpression
*/
public static final int PARENTHESIZED_EXPRESSION = 36;
/**
* Node type constant indicating a node of type
* PostfixExpression
.
* @see PostfixExpression
*/
public static final int POSTFIX_EXPRESSION = 37;
/**
* Node type constant indicating a node of type
* PrefixExpression
.
* @see PrefixExpression
*/
public static final int PREFIX_EXPRESSION = 38;
/**
* Node type constant indicating a node of type
* PrimitiveType
.
* @see PrimitiveType
*/
public static final int PRIMITIVE_TYPE = 39;
/**
* Node type constant indicating a node of type
* QualifiedName
.
* @see QualifiedName
*/
public static final int QUALIFIED_NAME = 40;
/**
* Node type constant indicating a node of type
* ReturnStatement
.
* @see ReturnStatement
*/
public static final int RETURN_STATEMENT = 41;
/**
* Node type constant indicating a node of type
* SimpleName
.
* @see SimpleName
*/
public static final int SIMPLE_NAME = 42;
/**
* Node type constant indicating a node of type
* SimpleType
.
* @see SimpleType
*/
public static final int SIMPLE_TYPE = 43;
/**
* Node type constant indicating a node of type
* SingleVariableDeclaration
.
* @see SingleVariableDeclaration
*/
public static final int SINGLE_VARIABLE_DECLARATION = 44;
/**
* Node type constant indicating a node of type
* StringLiteral
.
* @see StringLiteral
*/
public static final int STRING_LITERAL = 45;
/**
* Node type constant indicating a node of type
* SuperConstructorInvocation
.
* @see SuperConstructorInvocation
*/
public static final int SUPER_CONSTRUCTOR_INVOCATION = 46;
/**
* Node type constant indicating a node of type
* SuperFieldAccess
.
* @see SuperFieldAccess
*/
public static final int SUPER_FIELD_ACCESS = 47;
/**
* Node type constant indicating a node of type
* SuperMethodInvocation
.
* @see SuperMethodInvocation
*/
public static final int SUPER_METHOD_INVOCATION = 48;
/**
* Node type constant indicating a node of type
* SwitchCase
.
* @see SwitchCase
*/
public static final int SWITCH_CASE = 49;
/**
* Node type constant indicating a node of type
* SwitchStatement
.
* @see SwitchStatement
*/
public static final int SWITCH_STATEMENT = 50;
/**
* Node type constant indicating a node of type
* SynchronizedStatement
.
* @see SynchronizedStatement
*/
public static final int SYNCHRONIZED_STATEMENT = 51;
/**
* Node type constant indicating a node of type
* ThisExpression
.
* @see ThisExpression
*/
public static final int THIS_EXPRESSION = 52;
/**
* Node type constant indicating a node of type
* ThrowStatement
.
* @see ThrowStatement
*/
public static final int THROW_STATEMENT = 53;
/**
* Node type constant indicating a node of type
* TryStatement
.
* @see TryStatement
*/
public static final int TRY_STATEMENT = 54;
/**
* Node type constant indicating a node of type
* TypeDeclaration
.
* @see TypeDeclaration
*/
public static final int TYPE_DECLARATION = 55;
/**
* Node type constant indicating a node of type
* TypeDeclarationStatement
.
* @see TypeDeclarationStatement
*/
public static final int TYPE_DECLARATION_STATEMENT = 56;
/**
* Node type constant indicating a node of type
* TypeLiteral
.
* @see TypeLiteral
*/
public static final int TYPE_LITERAL = 57;
/**
* Node type constant indicating a node of type
* VariableDeclarationExpression
.
* @see VariableDeclarationExpression
*/
public static final int VARIABLE_DECLARATION_EXPRESSION = 58;
/**
* Node type constant indicating a node of type
* VariableDeclarationFragment
.
* @see VariableDeclarationFragment
*/
public static final int VARIABLE_DECLARATION_FRAGMENT = 59;
/**
* Node type constant indicating a node of type
* VariableDeclarationStatement
.
* @see VariableDeclarationStatement
*/
public static final int VARIABLE_DECLARATION_STATEMENT = 60;
/**
* Node type constant indicating a node of type
* WhileStatement
.
* @see WhileStatement
*/
public static final int WHILE_STATEMENT = 61;
/**
* Node type constant indicating a node of type
* InstanceofExpression
.
* @see InstanceofExpression
*/
public static final int INSTANCEOF_EXPRESSION = 62;
/**
* Node type constant indicating a node of type
* LineComment
.
* @see LineComment
* @since 3.0
*/
public static final int LINE_COMMENT = 63;
/**
* Node type constant indicating a node of type
* BlockComment
.
* @see BlockComment
* @since 3.0
*/
public static final int BLOCK_COMMENT = 64;
/**
* Node type constant indicating a node of type
* TagElement
.
* @see TagElement
* @since 3.0
*/
public static final int TAG_ELEMENT = 65;
/**
* Node type constant indicating a node of type
* TextElement
.
* @see TextElement
* @since 3.0
*/
public static final int TEXT_ELEMENT = 66;
/**
* Node type constant indicating a node of type
* MemberRef
.
* @see MemberRef
* @since 3.0
*/
public static final int MEMBER_REF = 67;
/**
* Node type constant indicating a node of type
* MethodRef
.
* @see MethodRef
* @since 3.0
*/
public static final int METHOD_REF = 68;
/**
* Node type constant indicating a node of type
* MethodRefParameter
.
* @see MethodRefParameter
* @since 3.0
*/
public static final int METHOD_REF_PARAMETER = 69;
/**
* Node type constant indicating a node of type
* EnhancedForStatement
.
* @see EnhancedForStatement
* @since 3.1
*/
public static final int ENHANCED_FOR_STATEMENT = 70;
/**
* Node type constant indicating a node of type
* EnumDeclaration
.
* @see EnumDeclaration
* @since 3.1
*/
public static final int ENUM_DECLARATION = 71;
/**
* Node type constant indicating a node of type
* EnumConstantDeclaration
.
* @see EnumConstantDeclaration
* @since 3.1
*/
public static final int ENUM_CONSTANT_DECLARATION = 72;
/**
* Node type constant indicating a node of type
* TypeParameter
.
* @see TypeParameter
* @since 3.1
*/
public static final int TYPE_PARAMETER = 73;
/**
* Node type constant indicating a node of type
* ParameterizedType
.
* @see ParameterizedType
* @since 3.1
*/
public static final int PARAMETERIZED_TYPE = 74;
/**
* Node type constant indicating a node of type
* QualifiedType
.
* @see QualifiedType
* @since 3.1
*/
public static final int QUALIFIED_TYPE = 75;
/**
* Node type constant indicating a node of type
* WildcardType
.
* @see WildcardType
* @since 3.1
*/
public static final int WILDCARD_TYPE = 76;
/**
* Node type constant indicating a node of type
* NormalAnnotation
.
* @see NormalAnnotation
* @since 3.1
*/
public static final int NORMAL_ANNOTATION = 77;
/**
* Node type constant indicating a node of type
* MarkerAnnotation
.
* @see MarkerAnnotation
* @since 3.1
*/
public static final int MARKER_ANNOTATION = 78;
/**
* Node type constant indicating a node of type
* SingleMemberAnnotation
.
* @see SingleMemberAnnotation
* @since 3.1
*/
public static final int SINGLE_MEMBER_ANNOTATION = 79;
/**
* Node type constant indicating a node of type
* MemberValuePair
.
* @see MemberValuePair
* @since 3.1
*/
public static final int MEMBER_VALUE_PAIR = 80;
/**
* Node type constant indicating a node of type
* AnnotationTypeDeclaration
.
* @see AnnotationTypeDeclaration
* @since 3.1
*/
public static final int ANNOTATION_TYPE_DECLARATION = 81;
/**
* Node type constant indicating a node of type
* AnnotationTypeMemberDeclaration
.
* @see AnnotationTypeMemberDeclaration
* @since 3.1
*/
public static final int ANNOTATION_TYPE_MEMBER_DECLARATION = 82;
/**
* Node type constant indicating a node of type
* Modifier
.
* @see Modifier
* @since 3.1
*/
public static final int MODIFIER = 83;
/**
* Returns the node class for the corresponding node type.
*
* @param nodeType AST node type
* @return the corresponding ASTNode
subclass
* @exception IllegalArgumentException if nodeType
is
* not a legal AST node type
* @see #getNodeType()
* @since 3.0
*/
public static Class nodeClassForType(int nodeType) {
switch (nodeType) {
case ANNOTATION_TYPE_DECLARATION :
return AnnotationTypeDeclaration.class;
case ANNOTATION_TYPE_MEMBER_DECLARATION :
return AnnotationTypeMemberDeclaration.class;
case ANONYMOUS_CLASS_DECLARATION :
return AnonymousClassDeclaration.class;
case ARRAY_ACCESS :
return ArrayAccess.class;
case ARRAY_CREATION :
return ArrayCreation.class;
case ARRAY_INITIALIZER :
return ArrayInitializer.class;
case ARRAY_TYPE :
return ArrayType.class;
case ASSERT_STATEMENT :
return AssertStatement.class;
case ASSIGNMENT :
return Assignment.class;
case BLOCK :
return Block.class;
case BLOCK_COMMENT :
return BlockComment.class;
case BOOLEAN_LITERAL :
return BooleanLiteral.class;
case BREAK_STATEMENT :
return BreakStatement.class;
case CAST_EXPRESSION :
return CastExpression.class;
case CATCH_CLAUSE :
return CatchClause.class;
case CHARACTER_LITERAL :
return CharacterLiteral.class;
case CLASS_INSTANCE_CREATION :
return ClassInstanceCreation.class;
case COMPILATION_UNIT :
return CompilationUnit.class;
case CONDITIONAL_EXPRESSION :
return ConditionalExpression.class;
case CONSTRUCTOR_INVOCATION :
return ConstructorInvocation.class;
case CONTINUE_STATEMENT :
return ContinueStatement.class;
case DO_STATEMENT :
return DoStatement.class;
case EMPTY_STATEMENT :
return EmptyStatement.class;
case ENHANCED_FOR_STATEMENT :
return EnhancedForStatement.class;
case ENUM_CONSTANT_DECLARATION :
return EnumConstantDeclaration.class;
case ENUM_DECLARATION :
return EnumDeclaration.class;
case EXPRESSION_STATEMENT :
return ExpressionStatement.class;
case FIELD_ACCESS :
return FieldAccess.class;
case FIELD_DECLARATION :
return FieldDeclaration.class;
case FOR_STATEMENT :
return ForStatement.class;
case IF_STATEMENT :
return IfStatement.class;
case IMPORT_DECLARATION :
return ImportDeclaration.class;
case INFIX_EXPRESSION :
return InfixExpression.class;
case INITIALIZER :
return Initializer.class;
case INSTANCEOF_EXPRESSION :
return InstanceofExpression.class;
case JAVADOC :
return Javadoc.class;
case LABELED_STATEMENT :
return LabeledStatement.class;
case LINE_COMMENT :
return LineComment.class;
case MARKER_ANNOTATION :
return MarkerAnnotation.class;
case MEMBER_REF :
return MemberRef.class;
case MEMBER_VALUE_PAIR :
return MemberValuePair.class;
case METHOD_DECLARATION :
return MethodDeclaration.class;
case METHOD_INVOCATION :
return MethodInvocation.class;
case METHOD_REF :
return MethodRef.class;
case METHOD_REF_PARAMETER :
return MethodRefParameter.class;
case MODIFIER :
return Modifier.class;
case NORMAL_ANNOTATION :
return NormalAnnotation.class;
case NULL_LITERAL :
return NullLiteral.class;
case NUMBER_LITERAL :
return NumberLiteral.class;
case PACKAGE_DECLARATION :
return PackageDeclaration.class;
case PARAMETERIZED_TYPE :
return ParameterizedType.class;
case PARENTHESIZED_EXPRESSION :
return ParenthesizedExpression.class;
case POSTFIX_EXPRESSION :
return PostfixExpression.class;
case PREFIX_EXPRESSION :
return PrefixExpression.class;
case PRIMITIVE_TYPE :
return PrimitiveType.class;
case QUALIFIED_NAME :
return QualifiedName.class;
case QUALIFIED_TYPE :
return QualifiedType.class;
case RETURN_STATEMENT :
return ReturnStatement.class;
case SIMPLE_NAME :
return SimpleName.class;
case SIMPLE_TYPE :
return SimpleType.class;
case SINGLE_MEMBER_ANNOTATION :
return SingleMemberAnnotation.class;
case SINGLE_VARIABLE_DECLARATION :
return SingleVariableDeclaration.class;
case STRING_LITERAL :
return StringLiteral.class;
case SUPER_CONSTRUCTOR_INVOCATION :
return SuperConstructorInvocation.class;
case SUPER_FIELD_ACCESS :
return SuperFieldAccess.class;
case SUPER_METHOD_INVOCATION :
return SuperMethodInvocation.class;
case SWITCH_CASE:
return SwitchCase.class;
case SWITCH_STATEMENT :
return SwitchStatement.class;
case SYNCHRONIZED_STATEMENT :
return SynchronizedStatement.class;
case TAG_ELEMENT :
return TagElement.class;
case TEXT_ELEMENT :
return TextElement.class;
case THIS_EXPRESSION :
return ThisExpression.class;
case THROW_STATEMENT :
return ThrowStatement.class;
case TRY_STATEMENT :
return TryStatement.class;
case TYPE_DECLARATION :
return TypeDeclaration.class;
case TYPE_DECLARATION_STATEMENT :
return TypeDeclarationStatement.class;
case TYPE_LITERAL :
return TypeLiteral.class;
case TYPE_PARAMETER :
return TypeParameter.class;
case VARIABLE_DECLARATION_EXPRESSION :
return VariableDeclarationExpression.class;
case VARIABLE_DECLARATION_FRAGMENT :
return VariableDeclarationFragment.class;
case VARIABLE_DECLARATION_STATEMENT :
return VariableDeclarationStatement.class;
case WHILE_STATEMENT :
return WhileStatement.class;
case WILDCARD_TYPE :
return WildcardType.class;
}
throw new IllegalArgumentException();
}
/**
* Owning AST.
* * N.B. This ia a private field, but declared as package-visible * for more efficient access from inner classes. *
*/ final AST ast; /** * Parent AST node, ornull
if this node is a root.
* Initially null
.
*/
private ASTNode parent = null;
/**
* An unmodifiable empty map (used to implement properties()
).
*/
private static final Map UNMODIFIABLE_EMPTY_MAP
= Collections.unmodifiableMap(new HashMap(1));
/**
* Primary field used in representing node properties efficiently.
* If null
, this node has no properties.
* If a String
, this is the name of this node's sole property,
* and property2
contains its value.
* If a HashMap
, this is the table of property name-value
* mappings; property2
, if non-null is its unmodifiable
* equivalent.
* Initially null
.
*
* @see #property2
*/
private Object property1 = null;
/**
* Auxillary field used in representing node properties efficiently.
*
* @see #property1
*/
private Object property2 = null;
/**
* A character index into the original source string,
* or -1
if no source position information is available
* for this node; -1
by default.
*/
private int startPosition = -1;
/**
* A character length, or 0
if no source position
* information is recorded for this node; 0
by default.
*/
private int length = 0;
/**
* Flag constant (bit mask, value 1) indicating that there is something
* not quite right with this AST node.
*
* The standard parser (ASTParser
) sets this
* flag on a node to indicate a syntax error detected in the vicinity.
*
* The standard parser (ASTParser
) sets this
* flag on the nodes it creates.
*
* The standard parser (ASTParser
) does not set
* this flag on the nodes it creates. However, clients may set
* this flag on a node to prevent further modification of the
* its structural properties.
*
* The standard parser (ASTParser
) sets this
* flag on a node to indicate a recovered node.
*
* N.B. This is a private field, but declared as package-visible * for more efficient access from inner classes. *
* * @see #MALFORMED */ int typeAndFlags = 0; /** * Property of parent in which this node is a child, ornull
* if this node is a root. Initially null
.
*
* @see #getLocationInParent
* @since 3.0
*/
private StructuralPropertyDescriptor location = null;
/** Internal convenience constant indicating that there is definite risk of cycles.
* @since 3.0
*/
static final boolean CYCLE_RISK = true;
/** Internal convenience constant indicating that there is no risk of cycles.
* @since 3.0
*/
static final boolean NO_CYCLE_RISK = false;
/** Internal convenience constant indicating that a structural property is mandatory.
* @since 3.0
*/
static final boolean MANDATORY = true;
/** Internal convenience constant indicating that a structural property is optional.
* @since 3.0
*/
static final boolean OPTIONAL = false;
/**
* A specialized implementation of a list of ASTNodes. The
* implementation is based on an ArrayList.
*/
class NodeList extends AbstractList {
/**
* The underlying list in which the nodes of this list are
* stored (element type: ASTNode
).
* * Be stingy on storage - assume that list will be empty. *
*
* This field declared default visibility (rather than private)
* so that accesses from NodeList.Cursor
do not require
* a synthetic accessor method.
*
Iterator
.
*/
public boolean hasNext() {
return this.position < NodeList.this.store.size();
}
/* (non-Javadoc)
* Method declared on Iterator
.
*/
public Object next() {
Object result = NodeList.this.store.get(this.position);
this.position++;
return result;
}
/* (non-Javadoc)
* Method declared on Iterator
.
*/
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Adjusts this cursor to accomodate an add/remove at the given
* index.
*
* @param index the position at which the element was added
* or removed
* @param delta +1 for add, and -1 for remove
*/
void update(int index, int delta) {
if (this.position > index) {
// the cursor has passed the added or removed element
this.position += delta;
}
}
}
/**
* A list of currently active cursors (element type:
* Cursor
), or null
if there are no
* active cursors.
* * It is important for storage considerations to maintain the * null-means-empty invariant; otherwise, every NodeList instance * will waste a lot of space. A cursor is needed only for the duration * of a visit to the child nodes. Under normal circumstances, only a * single cursor is needed; multiple cursors are only required if there * are multiple visits going on at the same time. *
*/ private List cursors = null; /** * Creates a new empty list of nodes owned by this node. * This node will be the common parent of all nodes added to * this list. * * @param property the property descriptor * @since 3.0 */ NodeList(ChildListPropertyDescriptor property) { super(); this.propertyDescriptor = property; } /* (non-javadoc) * @see java.util.AbstractCollection#size() */ public int size() { return this.store.size(); } /* (non-javadoc) * @see AbstractList#get(int) */ public Object get(int index) { return this.store.get(index); } /* (non-javadoc) * @see List#set(int, java.lang.Object) */ public Object set(int index, Object element) { if (element == null) { throw new IllegalArgumentException(); } if ((ASTNode.this.typeAndFlags & PROTECT) != 0) { // this node is protected => cannot gain or lose children throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ } // delink old child from parent, and link new child to parent ASTNode newChild = (ASTNode) element; ASTNode oldChild = (ASTNode) this.store.get(index); if (oldChild == newChild) { return oldChild; } if ((oldChild.typeAndFlags & PROTECT) != 0) { // old child is protected => cannot be unparented throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ } ASTNode.checkNewChild(ASTNode.this, newChild, this.propertyDescriptor.cycleRisk, this.propertyDescriptor.elementType); ASTNode.this.ast.preReplaceChildEvent(ASTNode.this, oldChild, newChild, this.propertyDescriptor); Object result = this.store.set(index, newChild); // n.b. setParent will call ast.modifying() oldChild.setParent(null, null); newChild.setParent(ASTNode.this, this.propertyDescriptor); ASTNode.this.ast.postReplaceChildEvent(ASTNode.this, oldChild, newChild, this.propertyDescriptor); return result; } /* (non-javadoc) * @see List#add(int, java.lang.Object) */ public void add(int index, Object element) { if (element == null) { throw new IllegalArgumentException(); } if ((ASTNode.this.typeAndFlags & PROTECT) != 0) { // this node is protected => cannot gain or lose children throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ } // link new child to parent ASTNode newChild = (ASTNode) element; ASTNode.checkNewChild(ASTNode.this, newChild, this.propertyDescriptor.cycleRisk, this.propertyDescriptor.elementType); ASTNode.this.ast.preAddChildEvent(ASTNode.this, newChild, this.propertyDescriptor); this.store.add(index, element); updateCursors(index, +1); // n.b. setParent will call ast.modifying() newChild.setParent(ASTNode.this, this.propertyDescriptor); ASTNode.this.ast.postAddChildEvent(ASTNode.this, newChild, this.propertyDescriptor); } /* (non-javadoc) * @see List#remove(int) */ public Object remove(int index) { if ((ASTNode.this.typeAndFlags & PROTECT) != 0) { // this node is protected => cannot gain or lose children throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ } // delink old child from parent ASTNode oldChild = (ASTNode) this.store.get(index); if ((oldChild.typeAndFlags & PROTECT) != 0) { // old child is protected => cannot be unparented throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ } ASTNode.this.ast.preRemoveChildEvent(ASTNode.this, oldChild, this.propertyDescriptor); // n.b. setParent will call ast.modifying() oldChild.setParent(null, null); Object result = this.store.remove(index); updateCursors(index, -1); ASTNode.this.ast.postRemoveChildEvent(ASTNode.this, oldChild, this.propertyDescriptor); return result; } /** * Allocate a cursor to use for a visit. The client must call *releaseCursor
when done.
* * This method is internally synchronized on this NodeList. * It is thread-safe to create a cursor. *
* * @return a new cursor positioned before the first element * of the list */ Cursor newCursor() { synchronized (this) { // serialize cursor management on this NodeList if (this.cursors == null) { // convert null to empty list this.cursors = new ArrayList(1); } Cursor result = new Cursor(); this.cursors.add(result); return result; } } /** * Releases the given cursor at the end of a visit. ** This method is internally synchronized on this NodeList. * It is thread-safe to release a cursor. *
* * @param cursor the cursor */ void releaseCursor(Cursor cursor) { synchronized (this) { // serialize cursor management on this NodeList this.cursors.remove(cursor); if (this.cursors.isEmpty()) { // important: convert empty list back to null // otherwise the node will hang on to needless junk this.cursors = null; } } } /** * Adjusts all cursors to accomodate an add/remove at the given * index. ** This method is only used when the list is being modified. * The AST is not thread-safe if any of the clients are modifying it. *
* * @param index the position at which the element was added * or removed * @param delta +1 for add, and -1 for remove */ private void updateCursors(int index, int delta) { if (this.cursors == null) { // there are no cursors to worry about return; } for (Iterator it = this.cursors.iterator(); it.hasNext(); ) { Cursor c = (Cursor) it.next(); c.update(index, delta); } } /** * Returns an estimate of the memory footprint of this node list * instance in bytes. ** N.B. This constructor is package-private; all subclasses my be * declared in the same package; clients are unable to declare * additional subclasses. *
* * @param ast the AST that is to own this node */ ASTNode(AST ast) { if (ast == null) { throw new IllegalArgumentException(); } this.ast = ast; setNodeType(getNodeType0()); setFlags(ast.getDefaultNodeFlag()); // setFlags calls modifying(); } /** * Returns this node's AST. ** Note that the relationship between an AST node and its owing AST does * not change over the lifetime of a node. *
* * @return the AST that owns this node */ public final AST getAST() { return this.ast; } /** * Returns this node's parent node, ornull
if this is the
* root node.
* * Note that the relationship between an AST node and its parent node * may change over the lifetime of a node. *
* * @return the parent of this node, ornull
if none
*/
public final ASTNode getParent() {
return this.parent;
}
/**
* Returns the location of this node within its parent,
* or null
if this is a root node.
* *
* ASTNode node = ...; * ASTNode parent = node.getParent(); * StructuralPropertyDescriptor location = node.getLocationInParent(); * assert (parent != null) == (location != null); * if ((location != null) && location.isChildProperty()) * assert parent.getStructuralProperty(location) == node; * if ((location != null) && location.isChildListProperty()) * assert ((List) parent.getStructuralProperty(location)).contains(node); ** *
* Note that the relationship between an AST node and its parent node * may change over the lifetime of a node. *
* * @return the location of this node in its parent, * ornull
if this node has no parent
* @since 3.0
*/
public final StructuralPropertyDescriptor getLocationInParent() {
return this.location;
}
/**
* Returns the root node at or above this node; returns this node if
* it is a root.
*
* @return the root node at or above this node
*/
public final ASTNode getRoot() {
ASTNode candidate = this;
while (true) {
ASTNode p = candidate.getParent();
if (p == null) {
// candidate has no parent - that's the guy
return candidate;
}
candidate = p;
}
}
/**
* Returns the value of the given structural property for this node. The value
* returned depends on the kind of property:
* null
if none; primitive values are "boxed"ASTNode
),
* or null
if nonenull
if none
* @exception RuntimeException if this node does not have the given property
* @since 3.0
*/
public final Object getStructuralProperty(StructuralPropertyDescriptor property) {
if (property instanceof SimplePropertyDescriptor) {
SimplePropertyDescriptor p = (SimplePropertyDescriptor) property;
if (p.getValueType() == int.class) {
int result = internalGetSetIntProperty(p, true, 0);
return new Integer(result);
} else if (p.getValueType() == boolean.class) {
boolean result = internalGetSetBooleanProperty(p, true, false);
return Boolean.valueOf(result);
} else {
return internalGetSetObjectProperty(p, true, null);
}
}
if (property instanceof ChildPropertyDescriptor) {
return internalGetSetChildProperty((ChildPropertyDescriptor) property, true, null);
}
if (property instanceof ChildListPropertyDescriptor) {
return internalGetChildListProperty((ChildListPropertyDescriptor) property);
}
throw new IllegalArgumentException();
}
/**
* Sets the value of the given structural property for this node. The value
* passed depends on the kind of property:
* null
if none; primitive values are "boxed"ASTNode
),
* or null
if nonetrue
for a get operation, and
* false
for a set operation
* @param value the new property value; ignored for get operations
* @return the value; always returns
* 0
for set operations
* @exception RuntimeException if this node does not have the
* given property, or if the given value cannot be set as specified
* @since 3.0
*/
int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) {
throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$
}
/**
* Sets the value of the given boolean-valued property for this node.
* The default implementation of this method throws an exception explaining
* that this node does not have such a property. This method should be
* extended in subclasses that have at leasy one simple property whose value
* type is boolean.
*
* @param property the property
* @param get true
for a get operation, and
* false
for a set operation
* @param value the new property value; ignored for get operations
* @return the value; always returns
* false
for set operations
* @exception RuntimeException if this node does not have the
* given property, or if the given value cannot be set as specified
* @since 3.0
*/
boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) {
throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$
}
/**
* Sets the value of the given property for this node.
* The default implementation of this method throws an exception explaining
* that this node does not have such a property. This method should be
* extended in subclasses that have at leasy one simple property whose value
* type is a reference type.
*
* @param property the property
* @param get true
for a get operation, and
* false
for a set operation
* @param value the new property value, or null
if none;
* ignored for get operations
* @return the value, or null
if none; always returns
* null
for set operations
* @exception RuntimeException if this node does not have the
* given property, or if the given value cannot be set as specified
* @since 3.0
*/
Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) {
throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$
}
/**
* Sets the child value of the given property for this node.
* The default implementation of this method throws an exception explaining
* that this node does not have such a property. This method should be
* extended in subclasses that have at leasy one child property.
*
* @param property the property
* @param get true
for a get operation, and
* false
for a set operation
* @param child the new child value, or null
if none;
* always null
for get operations
* @return the child, or null
if none; always returns
* null
for set operations
* @exception RuntimeException if this node does not have the
* given property, or if the given child cannot be set as specified
* @since 3.0
*/
ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$
}
/**
* Returns the list value of the given property for this node.
* The default implementation of this method throws an exception explaining
* that this noed does not have such a property. This method should be
* extended in subclasses that have at leasy one child list property.
*
* @param property the property
* @return the list (element type: {@link ASTNode})
* @exception RuntimeException if the given node does not have the
* given property
* @since 3.0
*/
List internalGetChildListProperty(ChildListPropertyDescriptor property) {
throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$
}
/**
* Returns a list of structural property descriptors for nodes of the
* same type as this node. Clients must not modify the result.
*
* Note that property descriptors are a meta-level mechanism
* for manipulating ASTNodes in a generic way. They are
* unrelated to get/setProperty
.
*
* N.B. This method is package-private, so that the implementations * of this method in each of the concrete AST node types do not * clutter up the API doc. *
* * @param apiLevel the API level; one of theAST.JLS*
constants
* @return a list of property descriptors (element type:
* {@link StructuralPropertyDescriptor})
* @since 3.0
*/
abstract List internalStructuralPropertiesForType(int apiLevel);
/**
* Internal helper method that starts the building a list of
* property descriptors for the given node type.
*
* @param nodeClass the class for a concrete node type
* @param propertyList empty list
*/
static void createPropertyList(Class nodeClass, List propertyList) {
// stuff nodeClass at head of list for future ref
propertyList.add(nodeClass);
}
/**
* Internal helper method that adding a property descriptor.
*
* @param property the structural property descriptor
* @param propertyList list beginning with the AST node class
* followed by accumulated structural property descriptors
*/
static void addProperty(StructuralPropertyDescriptor property, List propertyList) {
Class nodeClass = (Class) propertyList.get(0);
if (property.getNodeClass() != nodeClass) {
// easily made cut-and-paste mistake
throw new RuntimeException("Structural property descriptor has wrong node class!"); //$NON-NLS-1$
}
propertyList.add(property);
}
/**
* Internal helper method that completes the building of
* a node type's structural property descriptor list.
*
* @param propertyList list beginning with the AST node class
* followed by accumulated structural property descriptors
* @return unmodifiable list of structural property descriptors
* (element type: StructuralPropertyDescriptor
)
*/
static List reapPropertyList(List propertyList) {
propertyList.remove(0); // remove nodeClass
// compact
ArrayList a = new ArrayList(propertyList.size());
a.addAll(propertyList);
return Collections.unmodifiableList(a);
}
/**
* Checks that this AST operation is not used when
* building JLS2 level ASTs.
* @exception UnsupportedOperationException
* @since 3.0
*/
final void unsupportedIn2() {
if (this.ast.apiLevel == AST.JLS2_INTERNAL) {
throw new UnsupportedOperationException("Operation not supported in JLS2 AST"); //$NON-NLS-1$
}
}
/**
* Checks that this AST operation is only used when
* building JLS2 level ASTs.
* @exception UnsupportedOperationException
* @since 3.0
*/
final void supportedOnlyIn2() {
if (this.ast.apiLevel != AST.JLS2_INTERNAL) {
throw new UnsupportedOperationException("Operation only supported in JLS2 AST"); //$NON-NLS-1$
}
}
/**
* Sets or clears this node's parent node and location.
*
* Note that this method is package-private. The pointer from a node
* to its parent is set implicitly as a side effect of inserting or
* removing the node as a child of another node. This method calls
* ast.modifying()
.
*
null
if none
* @param property the location of this node in its parent,
* or null
if parent
is null
* @see #getLocationInParent
* @see #getParent
* @since 3.0
*/
final void setParent(ASTNode parent, StructuralPropertyDescriptor property) {
this.ast.modifying();
this.parent = parent;
this.location = property;
}
/**
* Removes this node from its parent. Has no effect if this node
* is unparented. If this node appears as an element of a child list
* property of its parent, then this node is removed from the
* list using List.remove
.
* If this node appears as the value of a child property of its
* parent, then this node is detached from its parent
* by passing null
to the appropriate setter method;
* this operation fails if this node is in a mandatory property.
*
* @since 3.0
*/
public final void delete() {
StructuralPropertyDescriptor p = getLocationInParent();
if (p == null) {
// node is unparented
return;
}
if (p.isChildProperty()) {
getParent().setStructuralProperty(this.location, null);
return;
}
if (p.isChildListProperty()) {
List l = (List) getParent().getStructuralProperty(this.location);
l.remove(this);
}
}
/**
* Checks whether the given new child node is a node
* in a different AST from its parent-to-be, whether it is
* already has a parent, whether adding it to its
* parent-to-be would create a cycle, and whether the child is of
* the right type. The parent-to-be is the enclosing instance.
*
* @param node the parent-to-be node
* @param newChild the new child of the parent
* @param cycleCheck true
if cycles are possible and need
* to be checked, false
if cycles are impossible and do
* not need to be checked
* @param nodeType a type constraint on child nodes, or null
* if no special check is required
* @exception IllegalArgumentException if:
* * ASTNode oldChild = this.foo; * preReplaceChild(oldChild, newFoo, FOO_PROPERTY); * this.foo = newFoo; * postReplaceChild(oldChild, newFoo, FOO_PROPERTY); ** The first part (preReplaceChild) does all the precondition checks, * reports pre-delete events, and changes parent links. * The old child is delinked from its parent (making it a root node), * and the new child node is linked to its parent. The new child node * must be a root node in the same AST as its new parent, and must not * be an ancestor of this node. All three nodes must be * modifiable (not PROTECTED). The replace operation must fail * atomically; so it is crucial that all precondition checks * be done before any linking and delinking happens. * The final part (postReplaceChild )reports post-add events. *
* This method calls ast.modifying()
for the nodes affected.
*
null
if
* there was no old child to replace
* @param newChild the new child of this node, or null
if
* there is no replacement child
* @param property the property descriptor of this node describing
* the relationship between node and child
* @exception RuntimeException if:
* * preValueChange(FOO_PROPERTY); * this.foo = newFoo; * postValueChange(FOO_PROPERTY); ** The first part (preValueChange) does the precondition check * to make sure the node is modifiable (not PROTECTED). * The change operation must fail atomically; so it is crucial * that the precondition checks are done before the field is * hammered. The final part (postValueChange)reports post-change * events. *
* This method calls ast.modifying()
for the node affected.
*
* if (this.foo == null) { * // lazy init must be thread-safe for readers * synchronized (this) { * if (this.foo == null) { * preLazyInit(); * this.foo = ...; // code to create new node * postLazyInit(this.foo, FOO_PROPERTY); * } * } * } ** @since 3.0 */ final void preLazyInit() { // IMPORTANT: this method is called by readers // ASTNode.this is locked at this point this.ast.disableEvents(); // will turn events back on in postLasyInit } /** * End lazy initialization of this node. * * @param newChild the new child of this node, or
null
if
* there is no replacement child
* @param property the property descriptor of this node describing
* the relationship between node and child
* @since 3.0
*/
final void postLazyInit(ASTNode newChild, ChildPropertyDescriptor property) {
// IMPORTANT: this method is called by readers
// ASTNode.this is locked at this point
// newChild is brand new (so no chance of concurrent access)
newChild.setParent(this, property);
// turn events back on (they were turned off in corresponding preLazyInit)
this.ast.reenableEvents();
}
/**
* Returns the named property of this node, or null
if none.
*
* @param propertyName the property name
* @return the property value, or null
if none
* @see #setProperty(String,Object)
*/
public final Object getProperty(String propertyName) {
if (propertyName == null) {
throw new IllegalArgumentException();
}
if (this.property1 == null) {
// node has no properties at all
return null;
}
if (this.property1 instanceof String) {
// node has only a single property
if (propertyName.equals(this.property1)) {
return this.property2;
} else {
return null;
}
}
// otherwise node has table of properties
Map m = (Map) this.property1;
return m.get(propertyName);
}
/**
* Sets the named property of this node to the given value,
* or to null
to clear it.
* * Clients should employ property names that are sufficiently unique * to avoid inadvertent conflicts with other clients that might also be * setting properties on the same node. *
** Note that modifying a property is not considered a modification to the * AST itself. This is to allow clients to decorate existing nodes with * their own properties without jeopardizing certain things (like the * validity of bindings), which rely on the underlying tree remaining static. *
* * @param propertyName the property name * @param data the new property value, ornull
if none
* @see #getProperty(String)
*/
public final void setProperty(String propertyName, Object data) {
if (propertyName == null) {
throw new IllegalArgumentException();
}
// N.B. DO NOT CALL ast.modifying();
if (this.property1 == null) {
// node has no properties at all
if (data == null) {
// we already know this
return;
}
// node gets its fist property
this.property1 = propertyName;
this.property2 = data;
return;
}
if (this.property1 instanceof String) {
// node has only a single property
if (propertyName.equals(this.property1)) {
// we're in luck
this.property2 = data;
if (data == null) {
// just deleted last property
this.property1 = null;
this.property2 = null;
}
return;
}
if (data == null) {
// we already know this
return;
}
// node already has one property - getting its second
// convert to more flexible representation
HashMap m = new HashMap(2);
m.put(this.property1, this.property2);
m.put(propertyName, data);
this.property1 = m;
this.property2 = null;
return;
}
// node has two or more properties
HashMap m = (HashMap) this.property1;
if (data == null) {
m.remove(propertyName);
// check for just one property left
if (m.size() == 1) {
// convert to more efficient representation
Map.Entry[] entries = (Map.Entry[]) m.entrySet().toArray(new Map.Entry[1]);
this.property1 = entries[0].getKey();
this.property2 = entries[0].getValue();
}
return;
} else {
m.put(propertyName, data);
// still has two or more properties
return;
}
}
/**
* Returns an unmodifiable table of the properties of this node with
* non-null
values.
*
* @return the table of property values keyed by property name
* (key type: String
; value type: Object
)
*/
public final Map properties() {
if (this.property1 == null) {
// node has no properties at all
return UNMODIFIABLE_EMPTY_MAP;
}
if (this.property1 instanceof String) {
// node has a single property
return Collections.singletonMap(this.property1, this.property2);
}
// node has two or more properties
if (this.property2 == null) {
this.property2 = Collections.unmodifiableMap((Map) this.property1);
}
// property2 is unmodifiable wrapper for map in property1
return (Map) this.property2;
}
/**
* Returns the flags associated with this node.
* * No flags are associated with newly created nodes. *
** The flags are the bitwise-or of individual flags. * The following flags are currently defined: *
* The flags are the bitwise-or of individual flags. * The following flags are currently defined: *
* Note that the flags are not considered a structural * property of the node, and can be changed even if the * node is marked as protected. *
* * @param flags the bitwise-or of individual flags * @see #getFlags() */ public final void setFlags(int flags) { this.ast.modifying(); int old = this.typeAndFlags & 0xFFFF0000; this.typeAndFlags = old | (flags & 0xFFFF); } /** * Returns an integer value identifying the type of this concrete AST node. * The values are small positive integers, suitable for use in switch statements. *
* For each concrete node type there is a unique node type constant (name
* and value). The unique node type constant for a concrete node type such as
* CastExpression
is ASTNode.CAST_EXPRESSION
.
*
* This internal method is implemented in each of the * concrete node subclasses. *
* * @return one of the node type constants */ abstract int getNodeType0(); /** * TheASTNode
implementation of this Object
* method uses object identity (==). Use subtreeMatch
to
* compare two subtrees for equality.
*
* @param obj {@inheritDoc}
* @return {@inheritDoc}
* @see #subtreeMatch(ASTMatcher matcher, Object other)
*/
public final boolean equals(Object obj) {
return this == obj; // equivalent to Object.equals
}
/*
* (non-Javadoc)
* This makes it consistent with the fact that a equals methods has been provided.
* @see java.lang.Object#hashCode()
*/
public final int hashCode() {
return super.hashCode();
}
/**
* Returns whether the subtree rooted at the given node matches the
* given other object as decided by the given matcher.
*
* @param matcher the matcher
* @param other the other object, or null
* @return true
if the subtree matches, or
* false
if they do not match
*/
public final boolean subtreeMatch(ASTMatcher matcher, Object other) {
return subtreeMatch0(matcher, other);
}
/**
* Returns whether the subtree rooted at the given node matches the
* given other object as decided by the given matcher.
* * This internal method is implemented in each of the * concrete node subclasses. *
* * @param matcher the matcher * @param other the other object, ornull
* @return true
if the subtree matches, or
* false
if they do not match
*/
abstract boolean subtreeMatch0(ASTMatcher matcher, Object other);
/**
* Returns a deep copy of the subtree of AST nodes rooted at the
* given node. The resulting nodes are owned by the given AST,
* which may be different from the ASTs of the given node.
* Even if the given node has a parent, the result node will be unparented.
*
* Source range information on the original nodes is automatically copied to the new
* nodes. Client properties (properties
) are not carried over.
*
* The node's AST
and the target AST
must support
* the same API level.
*
null
if none
* @return the copied node, or null
if node
* is null
*/
public static ASTNode copySubtree(AST target, ASTNode node) {
if (node == null) {
return null;
}
if (target == null) {
throw new IllegalArgumentException();
}
if (target.apiLevel() != node.getAST().apiLevel()) {
throw new UnsupportedOperationException();
}
ASTNode newNode = node.clone(target);
return newNode;
}
/**
* Returns a deep copy of the subtrees of AST nodes rooted at the
* given list of nodes. The resulting nodes are owned by the given AST,
* which may be different from the ASTs of the nodes in the list.
* Even if the nodes in the list have parents, the nodes in the result
* will be unparented.
*
* Source range information on the original nodes is automatically copied to the new
* nodes. Client properties (properties
) are not carried over.
*
ASTNode
)
* @return the list of copied subtrees
* (element type: ASTNode
)
*/
public static List copySubtrees(AST target, List nodes) {
List result = new ArrayList(nodes.size());
for (Iterator it = nodes.iterator(); it.hasNext(); ) {
ASTNode oldNode = (ASTNode) it.next();
ASTNode newNode = oldNode.clone(target);
result.add(newNode);
}
return result;
}
/**
* Returns a deep copy of the subtree of AST nodes rooted at this node.
* The resulting nodes are owned by the given AST, which may be different
* from the AST of this node. Even if this node has a parent, the
* result node will be unparented.
*
* This method reports pre- and post-clone events, and dispatches
* to clone0(AST)
which is reimplemented in node subclasses.
*
* This method must be implemented in subclasses. *
*
* This method does not report pre- and post-clone events.
* All callers should instead call clone(AST)
* to ensure that pre- and post-clone events are reported.
*
* N.B. This method is package-private, so that the implementations * of this method in each of the concrete AST node types do not * clutter up the API doc. *
* * @param target the AST that is to own the nodes in the result * @return the root node of the copies subtree */ abstract ASTNode clone0(AST target); /** * Accepts the given visitor on a visit of the current node. * * @param visitor the visitor object * @exception IllegalArgumentException if the visitor is null */ public final void accept(ASTVisitor visitor) { if (visitor == null) { throw new IllegalArgumentException(); } // begin with the generic pre-visit visitor.preVisit(this); // dynamic dispatch to internal method for type-specific visit/endVisit accept0(visitor); // end with the generic post-visit visitor.postVisit(this); } /** * Accepts the given visitor on a type-specific visit of the current node. * This method must be implemented in all concrete AST node types. ** General template for implementation on each concrete ASTNode class: *
*
* boolean visitChildren = visitor.visit(this);
* if (visitChildren) {
* // visit children in normal left to right reading order
* acceptChild(visitor, getProperty1());
* acceptChildren(visitor, rawListProperty);
* acceptChild(visitor, getProperty2());
* }
* visitor.endVisit(this);
*
*
* Note that the caller (accept
) take cares of invoking
* visitor.preVisit(this)
and visitor.postVisit(this)
.
*
*
* @param visitor the visitor object
*/
abstract void accept0(ASTVisitor visitor);
/**
* Accepts the given visitor on a visit of the current node.
*
* This method should be used by the concrete implementations of
* accept0
to traverse optional properties. Equivalent
* to child.accept(visitor)
if child
* is not null
.
*
null
* if none
*/
final void acceptChild(ASTVisitor visitor, ASTNode child) {
if (child == null) {
return;
}
child.accept(visitor);
}
/**
* Accepts the given visitor on a visit of the given live list of
* child nodes.
*
* This method must be used by the concrete implementations of
* accept
to traverse list-values properties; it
* encapsulates the proper handling of on-the-fly changes to the list.
*
null
* if none
*/
final void acceptChildren(ASTVisitor visitor, ASTNode.NodeList children) {
// use a cursor to keep track of where we are up to
// (the list may be changing under foot)
NodeList.Cursor cursor = children.newCursor();
try {
while (cursor.hasNext()) {
ASTNode child = (ASTNode) cursor.next();
child.accept(visitor);
}
} finally {
children.releaseCursor(cursor);
}
}
/**
* Returns the character index into the original source file indicating
* where the source fragment corresponding to this node begins.
* * The parser supplies useful well-defined source ranges to the nodes it creates. * See {@link ASTParser#setKind(int)} for details * on precisely where source ranges begin and end. *
* * @return the 0-based character index, or-1
* if no source position information is recorded for this node
* @see #getLength()
* @see ASTParser
*/
public final int getStartPosition() {
return this.startPosition;
}
/**
* Returns the length in characters of the original source file indicating
* where the source fragment corresponding to this node ends.
* * The parser supplies useful well-defined source ranges to the nodes it creates. * See {@link ASTParser#setKind(int)} methods for details * on precisely where source ranges begin and end. *
* * @return a (possibly 0) length, or0
* if no source position information is recorded for this node
* @see #getStartPosition()
* @see ASTParser
*/
public final int getLength() {
return this.length;
}
/**
* Sets the source range of the original source file where the source
* fragment corresponding to this node was found.
* * See {@link ASTParser#setKind(int)} for details * on precisely where source ranges are supposed to begin and end. *
* * @param startPosition a 0-based character index, * or-1
if no source position information is
* available for this node
* @param length a (possibly 0) length,
* or 0
if no source position information is recorded
* for this node
* @see #getStartPosition()
* @see #getLength()
* @see ASTParser
*/
public final void setSourceRange(int startPosition, int length) {
if (startPosition >= 0 && length < 0) {
throw new IllegalArgumentException();
}
if (startPosition < 0 && length != 0) {
throw new IllegalArgumentException();
}
// source positions are not considered a structural property
// but we protect them nevertheless
checkModifiable();
this.startPosition = startPosition;
this.length = length;
}
/**
* Returns a string representation of this node suitable for debugging
* purposes only.
*
* @return a debug string
*/
public final String toString() {
StringBuffer buffer = new StringBuffer();
int p = buffer.length();
try {
appendDebugString(buffer);
} catch (RuntimeException e) {
// since debugger sometimes call toString methods, problems can easily happen when
// toString is called on an instance that is being initialized
buffer.setLength(p);
buffer.append("!"); //$NON-NLS-1$
buffer.append(standardToString());
}
return buffer.toString();
}
/**
* Returns the string representation of this node produced by the standard
* Object.toString
method.
*
* @return a debug string
*/
final String standardToString() {
return super.toString();
}
/**
* Appends a debug representation of this node to the given string buffer.
*
* The ASTNode
implementation of this method prints out the entire
* subtree. Subclasses may override to provide a more succinct representation.
*
null
* @return the size of this string object in bytes, or
* 0 if the string is null
* @since 3.0
*/
static int stringSize(String string) {
int size = 0;
if (string != null) {
// Strings usually have 4 instance fields, one of which is a char[]
size += HEADERS + 4 * 4;
// char[] has 2 bytes per character
size += HEADERS + 2 * string.length();
}
return size;
}
/**
* Returns an estimate of the memory footprint in bytes of the entire
* subtree rooted at this node.
*
* @return the size of this subtree in bytes
*/
public final int subtreeBytes() {
return treeSize();
}
/**
* Returns an estimate of the memory footprint in bytes of the entire
* subtree rooted at this node.
* * N.B. This method is package-private, so that the implementations * of this method in each of the concrete AST node types do not * clutter up the API doc. *
* * @return the size of this subtree in bytes */ abstract int treeSize(); /** * Returns an estimate of the memory footprint of this node in bytes. * The estimate does not include the space occupied by child nodes. * * @return the size of this node in bytes */ abstract int memSize(); }