Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 27511 Details for
Bug 110594
[refactoring] CCE in Infer type argument refactoring
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
updated ASTNode.java
ASTNode.java (text/plain), 85.34 KB, created by
Martin Aeschlimann
on 2005-09-26 10:23:23 EDT
(
hide
)
Description:
updated ASTNode.java
Filename:
MIME Type:
Creator:
Martin Aeschlimann
Created:
2005-09-26 10:23:23 EDT
Size:
85.34 KB
patch
obsolete
>/******************************************************************************* > * Copyright (c) 2000, 2005 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 org.eclipse.jdt.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; > >/** > * Abstract superclass of all Abstract Syntax Tree (AST) node types. > * <p> > * An AST node represents a Java source code construct, such > * as a name, type, expression, statement, or declaration. > * </p> > * <p> > * 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. > * </p> > * <p> > * 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 > * <code>set<it>CHILD</it></code> method), its parent link is set automatically > * and the parent link of the former child is set to <code>null</code>. > * For nodes with properties that include a list of children (for example, > * <code>Block</code> whose <code>statements</code> 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 > * <code>List.set</code> 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. > * </p> > * <p> > * ASTs must not contain cycles. All operations that could create a cycle > * detect this possibility and fail. > * </p> > * <p> > * 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. > * </p> > * <p> > * The hierarchy of AST node types has some convenient groupings marked > * by abstract superclasses: > * <ul> > * <li>expressions - <code>Expression</code></li> > * <li>names - <code>Name</code> (a sub-kind of expression)</li> > * <li>statements - <code>Statement</code></li> > * <li>types - <code>Type</code></li> > * <li>type body declarations - <code>BodyDeclaration</code></li> > * </ul> > * </p> > * <p> > * Abstract syntax trees may be hand constructed by clients, using the > * <code>new<it>TYPE</it></code> factory methods (see <code>AST</code>) to > * create new nodes, and the various <code>set<it>CHILD</it></code> methods > * to connect them together. > * </p> > * <p> > * 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. > * </p> > * <p> > * 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. > * </p> > * <p> > * Each AST node is capable of carrying an open-ended collection of > * client-defined properties. Newly created nodes have none. > * <code>getProperty</code> and <code>setProperty</code> are used to access > * these properties. > * </p> > * <p> > * 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 <b>not</b> safe for another thread to read, visit, > * write, create, or clone <em>any</em> of the nodes on the same AST. > * When synchronization is required, consider using the common AST > * object that owns the node; that is, use > * <code>synchronize (node.getAST()) {...}</code>. > * </p> > * <p> > * ASTs also support the visitor pattern; see the class <code>ASTVisitor</code> > * for details. > * </p> > * <p> > * Compilation units created by <code>ASTParser</code> 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. > * </p> > * > * @see ASTParser > * @see ASTVisitor > * @since 2.0 > */ >public abstract class ASTNode { > /* > * INSTRUCTIONS FOR ADDING NEW CONCRETE AST NODE TYPES > * > * There are several things that need to be changed when a > * new concrete AST node type (call it "FooBar"): > * > * 1. Create the FooBar AST node type class. > * The most effective way to do this is to copy a similar > * existing concrete node class to get a template that > * includes all the framework methods that must be implemented. > * > * 2. Add node type constant ASTNode.FOO_BAR. > * Node constants are numbered consecutively. Add the > * constant after the existing ones. > * > * 3. Add entry to ASTNode.nodeClassForType(int). > * > * 4. Add AST.newFooBar() factory method. > * > * 5. Add ASTVisitor.visit(FooBar) and endVisit(FooBar) methods. > * > * 6. Add ASTMatcher.match(FooBar,Object) method. > * > * 7. Ensure that SimpleName.isDeclaration() covers FooBar > * nodes if required. > * > * 8. Add NaiveASTFlattener.visit(FooBar) method to illustrate > * how these nodes should be serialized. > * > * 9. Update the AST test suites. > * > * The next steps are to update AST.parse* to start generating > * the new type of nodes, and ASTRewrite to serialize them back out. > */ > > /** > * Node type constant indicating a node of type > * <code>AnonymousClassDeclaration</code>. > * @see AnonymousClassDeclaration > */ > public static final int ANONYMOUS_CLASS_DECLARATION = 1; > > /** > * Node type constant indicating a node of type > * <code>ArrayAccess</code>. > * @see ArrayAccess > */ > public static final int ARRAY_ACCESS = 2; > > /** > * Node type constant indicating a node of type > * <code>ArrayCreation</code>. > * @see ArrayCreation > */ > public static final int ARRAY_CREATION = 3; > > /** > * Node type constant indicating a node of type > * <code>ArrayInitializer</code>. > * @see ArrayInitializer > */ > public static final int ARRAY_INITIALIZER = 4; > > /** > * Node type constant indicating a node of type > * <code>ArrayType</code>. > * @see ArrayType > */ > public static final int ARRAY_TYPE = 5; > > /** > * Node type constant indicating a node of type > * <code>AssertStatement</code>. > * @see AssertStatement > */ > public static final int ASSERT_STATEMENT = 6; > > /** > * Node type constant indicating a node of type > * <code>Assignment</code>. > * @see Assignment > */ > public static final int ASSIGNMENT = 7; > > /** > * Node type constant indicating a node of type > * <code>Block</code>. > * @see Block > */ > public static final int BLOCK = 8; > > /** > * Node type constant indicating a node of type > * <code>BooleanLiteral</code>. > * @see BooleanLiteral > */ > public static final int BOOLEAN_LITERAL = 9; > > /** > * Node type constant indicating a node of type > * <code>BreakStatement</code>. > * @see BreakStatement > */ > public static final int BREAK_STATEMENT = 10; > > /** > * Node type constant indicating a node of type > * <code>CastExpression</code>. > * @see CastExpression > */ > public static final int CAST_EXPRESSION = 11; > > /** > * Node type constant indicating a node of type > * <code>CatchClause</code>. > * @see CatchClause > */ > public static final int CATCH_CLAUSE = 12; > > /** > * Node type constant indicating a node of type > * <code>CharacterLiteral</code>. > * @see CharacterLiteral > */ > public static final int CHARACTER_LITERAL = 13; > > /** > * Node type constant indicating a node of type > * <code>ClassInstanceCreation</code>. > * @see ClassInstanceCreation > */ > public static final int CLASS_INSTANCE_CREATION = 14; > > /** > * Node type constant indicating a node of type > * <code>CompilationUnit</code>. > * @see CompilationUnit > */ > public static final int COMPILATION_UNIT = 15; > > /** > * Node type constant indicating a node of type > * <code>ConditionalExpression</code>. > * @see ConditionalExpression > */ > public static final int CONDITIONAL_EXPRESSION = 16; > > /** > * Node type constant indicating a node of type > * <code>ConstructorInvocation</code>. > * @see ConstructorInvocation > */ > public static final int CONSTRUCTOR_INVOCATION = 17; > > /** > * Node type constant indicating a node of type > * <code>ContinueStatement</code>. > * @see ContinueStatement > */ > public static final int CONTINUE_STATEMENT = 18; > > /** > * Node type constant indicating a node of type > * <code>DoStatement</code>. > * @see DoStatement > */ > public static final int DO_STATEMENT = 19; > > /** > * Node type constant indicating a node of type > * <code>EmptyStatement</code>. > * @see EmptyStatement > */ > public static final int EMPTY_STATEMENT = 20; > > /** > * Node type constant indicating a node of type > * <code>ExpressionStatement</code>. > * @see ExpressionStatement > */ > public static final int EXPRESSION_STATEMENT = 21; > > /** > * Node type constant indicating a node of type > * <code>FieldAccess</code>. > * @see FieldAccess > */ > public static final int FIELD_ACCESS = 22; > > /** > * Node type constant indicating a node of type > * <code>FieldDeclaration</code>. > * @see FieldDeclaration > */ > public static final int FIELD_DECLARATION = 23; > > /** > * Node type constant indicating a node of type > * <code>ForStatement</code>. > * @see ForStatement > */ > public static final int FOR_STATEMENT = 24; > > /** > * Node type constant indicating a node of type > * <code>IfStatement</code>. > * @see IfStatement > */ > public static final int IF_STATEMENT = 25; > > /** > * Node type constant indicating a node of type > * <code>ImportDeclaration</code>. > * @see ImportDeclaration > */ > public static final int IMPORT_DECLARATION = 26; > > /** > * Node type constant indicating a node of type > * <code>InfixExpression</code>. > * @see InfixExpression > */ > public static final int INFIX_EXPRESSION = 27; > > /** > * Node type constant indicating a node of type > * <code>Initializer</code>. > * @see Initializer > */ > public static final int INITIALIZER = 28; > > /** > * Node type constant indicating a node of type > * <code>Javadoc</code>. > * @see Javadoc > */ > public static final int JAVADOC = 29; > > /** > * Node type constant indicating a node of type > * <code>LabeledStatement</code>. > * @see LabeledStatement > */ > public static final int LABELED_STATEMENT = 30; > > /** > * Node type constant indicating a node of type > * <code>MethodDeclaration</code>. > * @see MethodDeclaration > */ > public static final int METHOD_DECLARATION = 31; > > /** > * Node type constant indicating a node of type > * <code>MethodInvocation</code>. > * @see MethodInvocation > */ > public static final int METHOD_INVOCATION = 32; > > /** > * Node type constant indicating a node of type > * <code>NullLiteral</code>. > * @see NullLiteral > */ > public static final int NULL_LITERAL = 33; > > /** > * Node type constant indicating a node of type > * <code>NumberLiteral</code>. > * @see NumberLiteral > */ > public static final int NUMBER_LITERAL = 34; > > /** > * Node type constant indicating a node of type > * <code>PackageDeclaration</code>. > * @see PackageDeclaration > */ > public static final int PACKAGE_DECLARATION = 35; > > /** > * Node type constant indicating a node of type > * <code>ParenthesizedExpression</code>. > * @see ParenthesizedExpression > */ > public static final int PARENTHESIZED_EXPRESSION = 36; > > /** > * Node type constant indicating a node of type > * <code>PostfixExpression</code>. > * @see PostfixExpression > */ > public static final int POSTFIX_EXPRESSION = 37; > > /** > * Node type constant indicating a node of type > * <code>PrefixExpression</code>. > * @see PrefixExpression > */ > public static final int PREFIX_EXPRESSION = 38; > > /** > * Node type constant indicating a node of type > * <code>PrimitiveType</code>. > * @see PrimitiveType > */ > public static final int PRIMITIVE_TYPE = 39; > > /** > * Node type constant indicating a node of type > * <code>QualifiedName</code>. > * @see QualifiedName > */ > public static final int QUALIFIED_NAME = 40; > > /** > * Node type constant indicating a node of type > * <code>ReturnStatement</code>. > * @see ReturnStatement > */ > public static final int RETURN_STATEMENT = 41; > > /** > * Node type constant indicating a node of type > * <code>SimpleName</code>. > * @see SimpleName > */ > public static final int SIMPLE_NAME = 42; > > /** > * Node type constant indicating a node of type > * <code>SimpleType</code>. > * @see SimpleType > */ > public static final int SIMPLE_TYPE = 43; > > /** > * Node type constant indicating a node of type > * <code>SingleVariableDeclaration</code>. > * @see SingleVariableDeclaration > */ > public static final int SINGLE_VARIABLE_DECLARATION = 44; > > /** > * Node type constant indicating a node of type > * <code>StringLiteral</code>. > * @see StringLiteral > */ > public static final int STRING_LITERAL = 45; > > /** > * Node type constant indicating a node of type > * <code>SuperConstructorInvocation</code>. > * @see SuperConstructorInvocation > */ > public static final int SUPER_CONSTRUCTOR_INVOCATION = 46; > > /** > * Node type constant indicating a node of type > * <code>SuperFieldAccess</code>. > * @see SuperFieldAccess > */ > public static final int SUPER_FIELD_ACCESS = 47; > > /** > * Node type constant indicating a node of type > * <code>SuperMethodInvocation</code>. > * @see SuperMethodInvocation > */ > public static final int SUPER_METHOD_INVOCATION = 48; > > /** > * Node type constant indicating a node of type > * <code>SwitchCase</code>. > * @see SwitchCase > */ > public static final int SWITCH_CASE = 49; > > /** > * Node type constant indicating a node of type > * <code>SwitchStatement</code>. > * @see SwitchStatement > */ > public static final int SWITCH_STATEMENT = 50; > > /** > * Node type constant indicating a node of type > * <code>SynchronizedStatement</code>. > * @see SynchronizedStatement > */ > public static final int SYNCHRONIZED_STATEMENT = 51; > > /** > * Node type constant indicating a node of type > * <code>ThisExpression</code>. > * @see ThisExpression > */ > public static final int THIS_EXPRESSION = 52; > > /** > * Node type constant indicating a node of type > * <code>ThrowStatement</code>. > * @see ThrowStatement > */ > public static final int THROW_STATEMENT = 53; > > /** > * Node type constant indicating a node of type > * <code>TryStatement</code>. > * @see TryStatement > */ > public static final int TRY_STATEMENT = 54; > > /** > * Node type constant indicating a node of type > * <code>TypeDeclaration</code>. > * @see TypeDeclaration > */ > public static final int TYPE_DECLARATION = 55; > > /** > * Node type constant indicating a node of type > * <code>TypeDeclarationStatement</code>. > * @see TypeDeclarationStatement > */ > public static final int TYPE_DECLARATION_STATEMENT = 56; > > /** > * Node type constant indicating a node of type > * <code>TypeLiteral</code>. > * @see TypeLiteral > */ > public static final int TYPE_LITERAL = 57; > > /** > * Node type constant indicating a node of type > * <code>VariableDeclarationExpression</code>. > * @see VariableDeclarationExpression > */ > public static final int VARIABLE_DECLARATION_EXPRESSION = 58; > > /** > * Node type constant indicating a node of type > * <code>VariableDeclarationFragment</code>. > * @see VariableDeclarationFragment > */ > public static final int VARIABLE_DECLARATION_FRAGMENT = 59; > > /** > * Node type constant indicating a node of type > * <code>VariableDeclarationStatement</code>. > * @see VariableDeclarationStatement > */ > public static final int VARIABLE_DECLARATION_STATEMENT = 60; > > /** > * Node type constant indicating a node of type > * <code>WhileStatement</code>. > * @see WhileStatement > */ > public static final int WHILE_STATEMENT = 61; > > /** > * Node type constant indicating a node of type > * <code>InstanceofExpression</code>. > * @see InstanceofExpression > */ > public static final int INSTANCEOF_EXPRESSION = 62; > > /** > * Node type constant indicating a node of type > * <code>LineComment</code>. > * @see LineComment > * @since 3.0 > */ > public static final int LINE_COMMENT = 63; > > /** > * Node type constant indicating a node of type > * <code>BlockComment</code>. > * @see BlockComment > * @since 3.0 > */ > public static final int BLOCK_COMMENT = 64; > > /** > * Node type constant indicating a node of type > * <code>TagElement</code>. > * @see TagElement > * @since 3.0 > */ > public static final int TAG_ELEMENT = 65; > > /** > * Node type constant indicating a node of type > * <code>TextElement</code>. > * @see TextElement > * @since 3.0 > */ > public static final int TEXT_ELEMENT = 66; > > /** > * Node type constant indicating a node of type > * <code>MemberRef</code>. > * @see MemberRef > * @since 3.0 > */ > public static final int MEMBER_REF = 67; > > /** > * Node type constant indicating a node of type > * <code>MethodRef</code>. > * @see MethodRef > * @since 3.0 > */ > public static final int METHOD_REF = 68; > > /** > * Node type constant indicating a node of type > * <code>MethodRefParameter</code>. > * @see MethodRefParameter > * @since 3.0 > */ > public static final int METHOD_REF_PARAMETER = 69; > > /** > * Node type constant indicating a node of type > * <code>EnhancedForStatement</code>. > * @see EnhancedForStatement > * @since 3.1 > */ > public static final int ENHANCED_FOR_STATEMENT = 70; > > /** > * Node type constant indicating a node of type > * <code>EnumDeclaration</code>. > * @see EnumDeclaration > * @since 3.1 > */ > public static final int ENUM_DECLARATION = 71; > > /** > * Node type constant indicating a node of type > * <code>EnumConstantDeclaration</code>. > * @see EnumConstantDeclaration > * @since 3.1 > */ > public static final int ENUM_CONSTANT_DECLARATION = 72; > > /** > * Node type constant indicating a node of type > * <code>TypeParameter</code>. > * @see TypeParameter > * @since 3.1 > */ > public static final int TYPE_PARAMETER = 73; > > /** > * Node type constant indicating a node of type > * <code>ParameterizedType</code>. > * @see ParameterizedType > * @since 3.1 > */ > public static final int PARAMETERIZED_TYPE = 74; > > /** > * Node type constant indicating a node of type > * <code>QualifiedType</code>. > * @see QualifiedType > * @since 3.1 > */ > public static final int QUALIFIED_TYPE = 75; > > /** > * Node type constant indicating a node of type > * <code>WildcardType</code>. > * @see WildcardType > * @since 3.1 > */ > public static final int WILDCARD_TYPE = 76; > > /** > * Node type constant indicating a node of type > * <code>NormalAnnotation</code>. > * @see NormalAnnotation > * @since 3.1 > */ > public static final int NORMAL_ANNOTATION = 77; > > /** > * Node type constant indicating a node of type > * <code>MarkerAnnotation</code>. > * @see MarkerAnnotation > * @since 3.1 > */ > public static final int MARKER_ANNOTATION = 78; > > /** > * Node type constant indicating a node of type > * <code>SingleMemberAnnotation</code>. > * @see SingleMemberAnnotation > * @since 3.1 > */ > public static final int SINGLE_MEMBER_ANNOTATION = 79; > > /** > * Node type constant indicating a node of type > * <code>MemberValuePair</code>. > * @see MemberValuePair > * @since 3.1 > */ > public static final int MEMBER_VALUE_PAIR = 80; > > /** > * Node type constant indicating a node of type > * <code>AnnotationTypeDeclaration</code>. > * @see AnnotationTypeDeclaration > * @since 3.1 > */ > public static final int ANNOTATION_TYPE_DECLARATION = 81; > > /** > * Node type constant indicating a node of type > * <code>AnnotationTypeMemberDeclaration</code>. > * @see AnnotationTypeMemberDeclaration > * @since 3.1 > */ > public static final int ANNOTATION_TYPE_MEMBER_DECLARATION = 82; > > /** > * Node type constant indicating a node of type > * <code>Modifier</code>. > * @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 <code>ASTNode</code> subclass > * @exception IllegalArgumentException if <code>nodeType</code> 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. > * <p> > * N.B. This ia a private field, but declared as package-visible > * for more efficient access from inner classes. > * </p> > */ > final AST ast; > > /** > * Parent AST node, or <code>null</code> if this node is a root. > * Initially <code>null</code>. > */ > private ASTNode parent = null; > > /** > * An unmodifiable empty map (used to implement <code>properties()</code>). > */ > private static final Map<Object, Object> UNMODIFIABLE_EMPTY_MAP > = Collections.unmodifiableMap(new HashMap<Object, Object>(1)); > > /** > * Primary field used in representing node properties efficiently. > * If <code>null</code>, this node has no properties. > * If a <code>String</code>, this is the name of this node's sole property, > * and <code>property2</code> contains its value. > * If a <code>HashMap</code>, this is the table of property name-value > * mappings; <code>property2</code>, if non-null is its unmodifiable > * equivalent. > * Initially <code>null</code>. > * > * @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 <code>-1</code> if no source position information is available > * for this node; <code>-1</code> by default. > */ > private int startPosition = -1; > > /** > * A character length, or <code>0</code> if no source position > * information is recorded for this node; <code>0</code> by default. > */ > private int length = 0; > > /** > * Flag constant (bit mask, value 1) indicating that there is something > * not quite right with this AST node. > * <p> > * The standard parser (<code>ASTParser</code>) sets this > * flag on a node to indicate a syntax error detected in the vicinity. > * </p> > */ > public static final int MALFORMED = 1; > > /** > * Flag constant (bit mask, value 2) indicating that this is a node > * that was created by the parser (as opposed to one created by another > * party). > * <p> > * The standard parser (<code>ASTParser</code>) sets this > * flag on the nodes it creates. > * </p> > * @since 3.0 > */ > public static final int ORIGINAL = 2; > > /** > * Flag constant (bit mask, value 4) indicating that this node > * is unmodifiable. When a node is marked unmodifiable, the > * following operations result in a runtime exception: > * <ul> > * <li>Change a simple property of this node.</li> > * <li>Add or remove a child node from this node.</li> > * <li>Parent (or reparent) this node.</li> > * </ul> > * <p> > * The standard parser (<code>ASTParser</code>) 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. > * </p> > * @since 3.0 > */ > public static final int PROTECT = 4; > > /** > * int containing the node type in the top 16 bits and > * flags in the bottom 16 bits; none set by default. > * <p> > * N.B. This is a private field, but declared as package-visible > * for more efficient access from inner classes. > * </p> > * > * @see #MALFORMED > */ > int typeAndFlags = 0; > > /** > * Property of parent in which this node is a child, or <code>null</code> > * if this node is a root. Initially <code>null</code>. > * > * @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<E extends ASTNode> extends AbstractList<E> { > > /** > * The underlying list in which the nodes of this list are > * stored (element type: <code>ASTNode</code>). > * <p> > * Be stingy on storage - assume that list will be empty. > * </p> > * <p> > * This field declared default visibility (rather than private) > * so that accesses from <code>NodeList.Cursor</code> do not require > * a synthetic accessor method. > * </p> > */ > ArrayList<E> store = new ArrayList<E>(0); > > /** > * The property descriptor for this list. > */ > ChildListPropertyDescriptor propertyDescriptor; > > /** > * A cursor for iterating over the elements of the list. > * Does not lose its position if the list is changed during > * the iteration. > */ > class Cursor implements Iterator { > /** > * The position of the cursor between elements. If the value > * is N, then the cursor sits between the element at positions > * N-1 and N. Initially just before the first element of the > * list. > */ > private int position = 0; > > /* (non-Javadoc) > * Method declared on <code>Iterator</code>. > */ > public boolean hasNext() { > return this.position < NodeList.this.store.size(); > } > > /* (non-Javadoc) > * Method declared on <code>Iterator</code>. > */ > public Object next() { > Object result = NodeList.this.store.get(this.position); > this.position++; > return result; > } > > /* (non-Javadoc) > * Method declared on <code>Iterator</code>. > */ > 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: > * <code>Cursor</code>), or <code>null</code> if there are no > * active cursors. > * <p> > * 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. > * </p> > */ > private List<Cursor> 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 E get(int index) { > return this.store.get(index); > } > > /* (non-javadoc) > * @see List#set(int, java.lang.Object) > */ > public E set(int index, E 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 > E newChild = element; > E oldChild = 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); > > E 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, E 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 = 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 E 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 = 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); > E 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 > * <code>releaseCursor</code> when done. > * <p> > * This method is internally synchronized on this NodeList. > * It is thread-safe to create a cursor. > * </p> > * > * @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<Cursor>(1); > } > Cursor result = new Cursor(); > this.cursors.add(result); > return result; > } > } > > /** > * Releases the given cursor at the end of a visit. > * <p> > * This method is internally synchronized on this NodeList. > * It is thread-safe to release a cursor. > * </p> > * > * @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. > * <p> > * 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. > * </p> > * > * @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. > * <ul> > * <li>1 object header for the NodeList instance</li> > * <li>5 4-byte fields of the NodeList instance</li> > * <li>0 for cursors since null unless walk in progress</li> > * <li>1 object header for the ArrayList instance</li> > * <li>2 4-byte fields of the ArrayList instance</li> > * <li>1 object header for an Object[] instance</li> > * <li>4 bytes in array for each element</li> > * </ul> > * > * @return the size of this node list in bytes > */ > int memSize() { > int result = HEADERS + 5 * 4; > result += HEADERS + 2 * 4; > result += HEADERS + 4 * size(); > return result; > } > > /** > * Returns an estimate of the memory footprint in bytes of this node > * list and all its subtrees. > * > * @return the size of this list of subtrees in bytes > */ > int listSize() { > int result = memSize(); > for (Iterator it = iterator(); it.hasNext(); ) { > ASTNode child = (ASTNode) it.next(); > result += child.treeSize(); > } > return result; > } > } > > /** > * Creates a new AST node owned by the given AST. Once established, > * the relationship between an AST node and its owning AST does not change > * over the lifetime of the node. The new node has no parent node, > * and no properties. > * <p> > * N.B. This constructor is package-private; all subclasses my be > * declared in the same package; clients are unable to declare > * additional subclasses. > * </p> > * > * @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. > * <p> > * Note that the relationship between an AST node and its owing AST does > * not change over the lifetime of a node. > * </p> > * > * @return the AST that owns this node > */ > public final AST getAST() { > return this.ast; > } > > /** > * Returns this node's parent node, or <code>null</code> if this is the > * root node. > * <p> > * Note that the relationship between an AST node and its parent node > * may change over the lifetime of a node. > * </p> > * > * @return the parent of this node, or <code>null</code> if none > */ > public final ASTNode getParent() { > return this.parent; > } > > /** > * Returns the location of this node within its parent, > * or <code>null</code> if this is a root node. > * <p> > * <pre> > * 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); > * </pre> > * </p> > * <p> > * Note that the relationship between an AST node and its parent node > * may change over the lifetime of a node. > * </p> > * > * @return the location of this node in its parent, > * or <code>null</code> 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: > * <ul> > * <li>{@link SimplePropertyDescriptor} - the value of the given simple property, > * or <code>null</code> if none; primitive values are "boxed"</li> > * <li>{@link ChildPropertyDescriptor} - the child node (type <code>ASTNode</code>), > * or <code>null</code> if none</li> > * <li>{@link ChildListPropertyDescriptor} - the list (element type: {@link ASTNode})</li> > * </ul> > * > * @param property the property > * @return the value, or <code>null</code> 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: > * <ul> > * <li>{@link SimplePropertyDescriptor} - the new value of the given simple property, > * or <code>null</code> if none; primitive values are "boxed"</li> > * <li>{@link ChildPropertyDescriptor} - the new child node (type <code>ASTNode</code>), > * or <code>null</code> if none</li> > * <li>{@link ChildListPropertyDescriptor} - not allowed</li> > * </ul> > * > * @param property the property > * @param value the property value > * @exception RuntimeException if this node does not have the > * given property, or if the given property cannot be set > * @since 3.0 > */ > public final void setStructuralProperty(StructuralPropertyDescriptor property, Object value) { > if (property instanceof SimplePropertyDescriptor) { > SimplePropertyDescriptor p = (SimplePropertyDescriptor) property; > if (p.getValueType() == int.class) { > int arg = ((Integer) value).intValue(); > internalGetSetIntProperty(p, false, arg); > return; > } else if (p.getValueType() == boolean.class) { > boolean arg = ((Boolean) value).booleanValue(); > internalGetSetBooleanProperty(p, false, arg); > return; > } else { > if (value == null && p.isMandatory()) { > throw new IllegalArgumentException(); > } > internalGetSetObjectProperty(p, false, value); > return; > } > } > if (property instanceof ChildPropertyDescriptor) { > ChildPropertyDescriptor p = (ChildPropertyDescriptor) property; > ASTNode child = (ASTNode) value; > if (child == null && p.isMandatory()) { > throw new IllegalArgumentException(); > } > internalGetSetChildProperty(p, false, child); > return; > } > if (property instanceof ChildListPropertyDescriptor) { > throw new IllegalArgumentException("Cannot set the list of child list property"); //$NON-NLS-1$ > } > } > > /** > * Sets the value of the given int-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 int. > * > * @param property the property > * @param get <code>true</code> for a get operation, and > * <code>false</code> for a set operation > * @param value the new property value; ignored for get operations > * @return the value; always returns > * <code>0</code> 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 <code>true</code> for a get operation, and > * <code>false</code> for a set operation > * @param value the new property value; ignored for get operations > * @return the value; always returns > * <code>false</code> 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 <code>true</code> for a get operation, and > * <code>false</code> for a set operation > * @param value the new property value, or <code>null</code> if none; > * ignored for get operations > * @return the value, or <code>null</code> if none; always returns > * <code>null</code> 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 <code>true</code> for a get operation, and > * <code>false</code> for a set operation > * @param child the new child value, or <code>null</code> if none; > * always <code>null</code> for get operations > * @return the child, or <code>null</code> if none; always returns > * <code>null</code> 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<ASTNode> 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. > * <p> > * Note that property descriptors are a meta-level mechanism > * for manipulating ASTNodes in a generic way. They are > * unrelated to <code>get/setProperty</code>. > * </p> > * > * @return a list of property descriptors (element type: > * {@link StructuralPropertyDescriptor}) > * @since 3.0 > */ > public final List<StructuralPropertyDescriptor> structuralPropertiesForType() { > return internalStructuralPropertiesForType(this.ast.apiLevel); > } > > /** > * Returns a list of property descriptors for this node type. > * Clients must not modify the result. This abstract method > * must be implemented in each concrete AST node type. > * <p> > * 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. > * </p> > * > * @param apiLevel the API level; one of the <code>AST.JLS*</code> constants > * @return a list of property descriptors (element type: > * {@link StructuralPropertyDescriptor}) > * @since 3.0 > */ > abstract List<StructuralPropertyDescriptor> 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: <code>StructuralPropertyDescriptor</code>) > */ > 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. > * <p> > * 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 > * <code>ast.modifying()</code>. > * </p> > * > * @param parent the new parent of this node, or <code>null</code> if none > * @param property the location of this node in its parent, > * or <code>null</code> if <code>parent</code> is <code>null</code> > * @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 <code>List.remove</code>. > * If this node appears as the value of a child property of its > * parent, then this node is detached from its parent > * by passing <code>null</code> 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 <code>true</code> if cycles are possible and need > * to be checked, <code>false</code> if cycles are impossible and do > * not need to be checked > * @param nodeType a type constraint on child nodes, or <code>null</code> > * if no special check is required > * @exception IllegalArgumentException if: > * <ul> > * <li>the child is null</li> > * <li>the node belongs to a different AST</li> > * <li>the child has the incorrect node type</li> > * <li>the node already has a parent</li> > * <li>a cycle in would be created</li> > * </ul> > */ > static void checkNewChild(ASTNode node, ASTNode newChild, > boolean cycleCheck, Class nodeType) { > if (newChild.ast != node.ast) { > // new child is from a different AST > throw new IllegalArgumentException(); > } > if (newChild.getParent() != null) { > // new child currently has a different parent > throw new IllegalArgumentException(); > } > if (cycleCheck && newChild == node.getRoot()) { > // inserting new child would create a cycle > throw new IllegalArgumentException(); > } > Class childClass = newChild.getClass(); > if (nodeType != null && !nodeType.isAssignableFrom(childClass)) { > // new child is not of the right type > throw new ClassCastException(); > } > if ((newChild.typeAndFlags & PROTECT) != 0) { > // new child node is protected => cannot be parented > throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ > } > } > > /** > * Prelude portion of the "3 step program" for replacing the > * old child of this node with another node. > * Here is the code pattern found in all AST node subclasses: > * <pre> > * ASTNode oldChild = this.foo; > * preReplaceChild(oldChild, newFoo, FOO_PROPERTY); > * this.foo = newFoo; > * postReplaceChild(oldChild, newFoo, FOO_PROPERTY); > * </pre> > * 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. > * <p> > * This method calls <code>ast.modifying()</code> for the nodes affected. > * </p> > * > * @param oldChild the old child of this node, or <code>null</code> if > * there was no old child to replace > * @param newChild the new child of this node, or <code>null</code> if > * there is no replacement child > * @param property the property descriptor of this node describing > * the relationship between node and child > * @exception RuntimeException if: > * <ul> > * <li>the node belongs to a different AST</li> > * <li>the node already has a parent</li> > * <li>a cycle in would be created</li> > * <li>any of the nodes involved are unmodifiable</li> > * </ul> > * @since 3.0 > */ > final void preReplaceChild(ASTNode oldChild, ASTNode newChild, ChildPropertyDescriptor property) { > if ((this.typeAndFlags & PROTECT) != 0) { > // this node is protected => cannot gain or lose children > throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ > } > if (newChild != null) { > checkNewChild(this, newChild, property.cycleRisk, null); > } > // delink old child from parent > if (oldChild != null) { > if ((oldChild.typeAndFlags & PROTECT) != 0) { > // old child node is protected => cannot be unparented > throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ > } > if (newChild != null) { > this.ast.preReplaceChildEvent(this, oldChild, newChild, property); > } else { > this.ast.preRemoveChildEvent(this, oldChild, property); > } > oldChild.setParent(null, null); > } else { > if(newChild != null) { > this.ast.preAddChildEvent(this, newChild, property); > } > } > // link new child to parent > if (newChild != null) { > newChild.setParent(this, property); > // cannot notify postAddChildEvent until parent is linked to child too > } > } > > /** > * Postlude portion of the "3 step program" for replacing the > * old child of this node with another node. > * See {@link #preReplaceChild(ASTNode, ASTNode, ChildPropertyDescriptor)} > * for details. > * @since 3.0 > */ > final void postReplaceChild(ASTNode oldChild, ASTNode newChild, ChildPropertyDescriptor property) { > // link new child to parent > if (newChild != null) { > if (oldChild != null) { > this.ast.postReplaceChildEvent(this, oldChild, newChild, property); > } else { > this.ast.postAddChildEvent(this, newChild, property); > } > } else { > this.ast.postRemoveChildEvent(this, oldChild, property); > } > } > > /** > * Prelude portion of the "3 step program" for changing the > * value of a simple property of this node. > * Here is the code pattern found in all AST node subclasses: > * <pre> > * preValueChange(FOO_PROPERTY); > * this.foo = newFoo; > * postValueChange(FOO_PROPERTY); > * </pre> > * 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. > * <p> > * This method calls <code>ast.modifying()</code> for the node affected. > * </p> > * > * @param property the property descriptor of this node > * @exception RuntimeException if: > * <ul> > * <li>this node is unmodifiable</li> > * </ul> > * @since 3.0 > */ > final void preValueChange(SimplePropertyDescriptor property) { > if ((this.typeAndFlags & PROTECT) != 0) { > // this node is protected => cannot change valure of properties > throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ > } > this.ast.preValueChangeEvent(this, property); > this.ast.modifying(); > } > > /** > * Postlude portion of the "3 step program" for replacing the > * old child of this node with another node. > * See {@link #preValueChange(SimplePropertyDescriptor)} for details. > * @since 3.0 > */ > final void postValueChange(SimplePropertyDescriptor property) { > this.ast.postValueChangeEvent(this, property); > } > > /** > * Ensures that this node is modifiable (that is, not marked PROTECTED). > * If successful, calls ast.modifying(). > * @exception RuntimeException is not modifiable > */ > final void checkModifiable() { > if ((this.typeAndFlags & PROTECT) != 0) { > throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ > } > this.ast.modifying(); > } > > /** > * Begin lazy initialization of this node. > * Here is the code pattern found in all AST > * node subclasses: > * <pre> > * 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); > * } > * } > * } > * </pre> > * @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 <code>null</code> 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 <code>null</code> if none. > * > * @param propertyName the property name > * @return the property value, or <code>null</code> 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 <code>null</code> to clear it. > * <p> > * 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. > * </p> > * <p> > * 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. > * </p> > * > * @param propertyName the property name > * @param data the new property value, or <code>null</code> 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-<code>null</code> values. > * > * @return the table of property values keyed by property name > * (key type: <code>String</code>; value type: <code>Object</code>) > */ > public final Map<Object, Object> 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. > * <p> > * No flags are associated with newly created nodes. > * </p> > * <p> > * The flags are the bitwise-or of individual flags. > * The following flags are currently defined: > * <ul> > * <li>{@link #MALFORMED} - indicates node is syntactically > * malformed</li> > * <li>{@link #ORIGINAL} - indicates original node > * created by ASTParser</li> > * <li>{@link #PROTECT} - indicates node is protected > * from further modification</li> > * </ul> > * Other bit positions are reserved for future use. > * </p> > * > * @return the bitwise-or of individual flags > * @see #setFlags(int) > */ > public final int getFlags() { > return this.typeAndFlags & 0xFFFF; > } > > /** > * Sets the flags associated with this node to the given value. > * <p> > * The flags are the bitwise-or of individual flags. > * The following flags are currently defined: > * <ul> > * <li>{@link #MALFORMED} - indicates node is syntactically > * malformed</li> > * <li>{@link #ORIGINAL} - indicates original node > * created by ASTParser</li> > * <li>{@link #PROTECT} - indicates node is protected > * from further modification</li> > * </ul> > * Other bit positions are reserved for future use. > * </p> > * <p> > * Note that the flags are <em>not</em> considered a structural > * property of the node, and can be changed even if the > * node is marked as protected. > * </p> > * > * @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. > * <p> > * 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 > * <code>CastExpression</code> is <code>ASTNode.CAST_EXPRESSION</code>. > * </p> > * > * @return one of the node type constants > */ > public final int getNodeType() { > return this.typeAndFlags >>> 16; > } > > /** > * Sets the integer value identifying the type of this concrete AST node. > * The values are small positive integers, suitable for use in switch statements. > * > * @param nodeType one of the node type constants > */ > private void setNodeType(int nodeType) { > int old = this.typeAndFlags & 0xFFFF0000; > this.typeAndFlags = old | (nodeType << 16); > } > > /** > * Returns an integer value identifying the type of this concrete AST node. > * <p> > * This internal method is implemented in each of the > * concrete node subclasses. > * </p> > * > * @return one of the node type constants > */ > abstract int getNodeType0(); > > /** > * The <code>ASTNode</code> implementation of this <code>Object</code> > * method uses object identity (==). Use <code>subtreeMatch</code> 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 > } > > /** > * 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 <code>null</code> > * @return <code>true</code> if the subtree matches, or > * <code>false</code> 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. > * <p> > * This internal method is implemented in each of the > * concrete node subclasses. > * </p> > * > * @param matcher the matcher > * @param other the other object, or <code>null</code> > * @return <code>true</code> if the subtree matches, or > * <code>false</code> 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. > * <p> > * Source range information on the original nodes is automatically copied to the new > * nodes. Client properties (<code>properties</code>) are not carried over. > * </p> > * <p> > * The node's <code>AST</code> and the target <code>AST</code> must support > * the same API level. > * </p> > * > * @param target the AST that is to own the nodes in the result > * @param node the node to copy, or <code>null</code> if none > * @return the copied node, or <code>null</code> if <code>node</code> > * is <code>null</code> > */ > 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. > * <p> > * Source range information on the original nodes is automatically copied to the new > * nodes. Client properties (<code>properties</code>) are not carried over. > * </p> > * > * @param target the AST that is to own the nodes in the result > * @param nodes the list of nodes to copy > * (element type: <code>ASTNode</code>) > * @return the list of copied subtrees > * (element type: <code>ASTNode</code>) > */ > 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. > * <p> > * This method reports pre- and post-clone events, and dispatches > * to <code>clone0(AST)</code> which is reimplemented in node subclasses. > * </p> > * > * @param target the AST that is to own the nodes in the result > * @return the root node of the copies subtree > */ > final ASTNode clone(AST target) { > this.ast.preCloneNodeEvent(this); > ASTNode c = this.clone0(target); > this.ast.postCloneNodeEvent(this, c); > return c; > } > > /** > * 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. > * <p> > * This method must be implemented in subclasses. > * </p> > * <p> > * This method does not report pre- and post-clone events. > * All callers should instead call <code>clone(AST)</code> > * to ensure that pre- and post-clone events are reported. > * </p> > * <p> > * 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. > * </p> > * > * @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. > * <p> > * General template for implementation on each concrete ASTNode class: > * <pre> > * <code> > * 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); > * </code> > * </pre> > * Note that the caller (<code>accept</code>) take cares of invoking > * <code>visitor.preVisit(this)</code> and <code>visitor.postVisit(this)</code>. > * </p> > * > * @param visitor the visitor object > */ > abstract void accept0(ASTVisitor visitor); > > /** > * Accepts the given visitor on a visit of the current node. > * <p> > * This method should be used by the concrete implementations of > * <code>accept0</code> to traverse optional properties. Equivalent > * to <code>child.accept(visitor)</code> if <code>child</code> > * is not <code>null</code>. > * </p> > * > * @param visitor the visitor object > * @param child the child AST node to dispatch too, or <code>null</code> > * 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. > * <p> > * This method must be used by the concrete implementations of > * <code>accept</code> to traverse list-values properties; it > * encapsulates the proper handling of on-the-fly changes to the list. > * </p> > * > * @param visitor the visitor object > * @param children the child AST node to dispatch too, or <code>null</code> > * 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. > * <p> > * 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. > * </p> > * > * @return the 0-based character index, or <code>-1</code> > * 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. > * <p> > * 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. > * </p> > * > * @return a (possibly 0) length, or <code>0</code> > * 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. > * <p> > * See {@link ASTParser#setKind(int)} for details > * on precisely where source ranges are supposed to begin and end. > * </p> > * > * @param startPosition a 0-based character index, > * or <code>-1</code> if no source position information is > * available for this node > * @param length a (possibly 0) length, > * or <code>0</code> 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 > * <code>Object.toString</code> method. > * > * @return a debug string > */ > final String standardToString() { > return super.toString(); > } > > /** > * Appends a debug representation of this node to the given string buffer. > * <p> > * The <code>ASTNode</code> implementation of this method prints out the entire > * subtree. Subclasses may override to provide a more succinct representation. > * </p> > * > * @param buffer the string buffer to append to > */ > void appendDebugString(StringBuffer buffer) { > // print the subtree by default > appendPrintString(buffer); > } > > /** > * Appends a standard Java source code representation of this subtree to the given > * string buffer. > * > * @param buffer the string buffer to append to > */ > final void appendPrintString(StringBuffer buffer) { > NaiveASTFlattener printer = new NaiveASTFlattener(); > this.accept(printer); > buffer.append(printer.getResult()); > } > > /** > * Estimate of size of an object header in bytes. > */ > static final int HEADERS = 12; > > /** > * Approximate base size of an AST node instance in bytes, > * including object header and instance fields. > * That is, HEADERS + (# instance vars in ASTNode)*4. > */ > static final int BASE_NODE_SIZE = HEADERS + 7 * 4; > > /** > * Returns an estimate of the memory footprint, in bytes, > * of the given string. > * > * @param string the string to measure, or <code>null</code> > * @return the size of this string object in bytes, or > * 0 if the string is <code>null</code> > * @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. > * <p> > * 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. > * </p> > * > * @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(); >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 110594
: 27511