1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2008 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials
 
   4  * are made available under the terms of the Eclipse Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/epl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  12 package net.sourceforge.phpdt.core.dom;
 
  14 import java.util.ArrayList;
 
  15 import java.util.Iterator;
 
  16 import java.util.List;
 
  19  * Single variable declaration AST node type. Single variable
 
  20  * declaration nodes are used in a limited number of places, including formal
 
  21  * parameter lists and catch clauses. They are not used for field declarations
 
  22  * and regular variable declaration statements.
 
  25  * SingleVariableDeclaration:
 
  26  *    { Modifier } Type Identifier { <b>[</b><b>]</b> } [ <b>=</b> Expression ]
 
  28  * For JLS3, the modifier flags were replaced by
 
  29  * a list of modifier nodes (intermixed with annotations), and the variable arity
 
  30  * indicator was added:
 
  32  * SingleVariableDeclaration:
 
  33  *    { ExtendedModifier } Type [ <b>...</b> ] Identifier { <b>[</b><b>]</b> } [ <b>=</b> Expression ]
 
  37  * @noinstantiate This class is not intended to be instantiated by clients.
 
  39 public class SingleVariableDeclaration extends VariableDeclaration {
 
  42          * The "modifiers" structural property of this node type (JLS2 API only).
 
  45         public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = 
 
  46                 new SimplePropertyDescriptor(SingleVariableDeclaration.class, "modifiers", int.class, MANDATORY); //$NON-NLS-1$
 
  49          * The "modifiers" structural property of this node type (added in JLS3 API).
 
  52         public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = 
 
  53                 new ChildListPropertyDescriptor(SingleVariableDeclaration.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$
 
  56          * The "name" structural property of this node type.
 
  59         public static final ChildPropertyDescriptor NAME_PROPERTY = 
 
  60                 new ChildPropertyDescriptor(SingleVariableDeclaration.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
 
  63          * The "type" structural property of this node type.
 
  66         public static final ChildPropertyDescriptor TYPE_PROPERTY = 
 
  67                 new ChildPropertyDescriptor(SingleVariableDeclaration.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
 
  70          * The "varargs" structural property of this node type (added in JLS3 API).
 
  73         public static final SimplePropertyDescriptor VARARGS_PROPERTY = 
 
  74                 new SimplePropertyDescriptor(SingleVariableDeclaration.class, "varargs", boolean.class, MANDATORY); //$NON-NLS-1$
 
  77          * The "extraDimensions" structural property of this node type.
 
  80         public static final SimplePropertyDescriptor EXTRA_DIMENSIONS_PROPERTY = 
 
  81                 new SimplePropertyDescriptor(SingleVariableDeclaration.class, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$
 
  84          * The "initializer" structural property of this node type.
 
  87         public static final ChildPropertyDescriptor INITIALIZER_PROPERTY = 
 
  88                 new ChildPropertyDescriptor(SingleVariableDeclaration.class, "initializer", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$
 
  91          * A list of property descriptors (element type: 
 
  92          * {@link StructuralPropertyDescriptor}),
 
  93          * or null if uninitialized.
 
  96         private static final List PROPERTY_DESCRIPTORS_2_0;
 
  99          * A list of property descriptors (element type: 
 
 100          * {@link StructuralPropertyDescriptor}),
 
 101          * or null if uninitialized.
 
 104         private static final List PROPERTY_DESCRIPTORS_3_0;
 
 107                 List propertyList = new ArrayList(6);
 
 108                 createPropertyList(SingleVariableDeclaration.class, propertyList);
 
 109                 addProperty(MODIFIERS_PROPERTY, propertyList);
 
 110                 addProperty(TYPE_PROPERTY, propertyList);
 
 111                 addProperty(NAME_PROPERTY, propertyList);
 
 112                 addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList);
 
 113                 addProperty(INITIALIZER_PROPERTY, propertyList);
 
 114                 PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList);
 
 116                 propertyList = new ArrayList(7);
 
 117                 createPropertyList(SingleVariableDeclaration.class, propertyList);
 
 118                 addProperty(MODIFIERS2_PROPERTY, propertyList);
 
 119                 addProperty(TYPE_PROPERTY, propertyList);
 
 120                 addProperty(VARARGS_PROPERTY, propertyList);
 
 121                 addProperty(NAME_PROPERTY, propertyList);
 
 122                 addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList);
 
 123                 addProperty(INITIALIZER_PROPERTY, propertyList);
 
 124                 PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList);
 
 128          * Returns a list of structural property descriptors for this node type.
 
 129          * Clients must not modify the result.
 
 131          * @param apiLevel the API level; one of the
 
 132          * <code>AST.JLS*</code> constants
 
 133          * @return a list of property descriptors (element type: 
 
 134          * {@link StructuralPropertyDescriptor})
 
 137         public static List propertyDescriptors(int apiLevel) {
 
 138                 if (apiLevel == AST.JLS2_INTERNAL) {
 
 139                         return PROPERTY_DESCRIPTORS_2_0;
 
 141                         return PROPERTY_DESCRIPTORS_3_0;
 
 146          * The extended modifiers (element type: <code>IExtendedModifier</code>). 
 
 147          * Null in JLS2. Added in JLS3; defaults to an empty list
 
 152         private ASTNode.NodeList modifiers = null;
 
 155          * The modifiers; bit-wise or of Modifier flags.
 
 156          * Defaults to none. Not used in 3.0.
 
 158         private int modifierFlags = Modifier.NONE;
 
 161          * The variable name; lazily initialized; defaults to a unspecified,
 
 162          * legal Java identifier.
 
 164         private SimpleName variableName = null;
 
 167          * The type; lazily initialized; defaults to a unspecified,
 
 170         private Type type = null;
 
 173          * Indicates the last parameter of a variable arity method;
 
 178         private boolean variableArity = false;
 
 181          * The number of extra array dimensions that appear after the variable;
 
 186         private int extraArrayDimensions = 0;
 
 189          * The initializer expression, or <code>null</code> if none;
 
 192         private Expression optionalInitializer = null;
 
 195          * Creates a new AST node for a variable declaration owned by the given 
 
 196          * AST. By default, the variable declaration has: no modifiers, an 
 
 197          * unspecified (but legal) type, an unspecified (but legal) variable name, 
 
 198          * 0 dimensions after the variable; no initializer; not variable arity.
 
 200          * N.B. This constructor is package-private.
 
 203          * @param ast the AST that is to own this node
 
 205         SingleVariableDeclaration(AST ast) {
 
 207                 if (ast.apiLevel >= AST.JLS3) {
 
 208                         this.modifiers = new ASTNode.NodeList(MODIFIERS2_PROPERTY);
 
 212         /* (omit javadoc for this method)
 
 213          * Method declared on VariableDeclaration.
 
 216         final SimplePropertyDescriptor internalExtraDimensionsProperty() {
 
 217                 return EXTRA_DIMENSIONS_PROPERTY;
 
 220         /* (omit javadoc for this method)
 
 221          * Method declared on VariableDeclaration.
 
 224         final ChildPropertyDescriptor internalInitializerProperty() {
 
 225                 return INITIALIZER_PROPERTY;
 
 228         /* (omit javadoc for this method)
 
 229          * Method declared on VariableDeclaration.
 
 232         final ChildPropertyDescriptor internalNameProperty() {
 
 233                 return NAME_PROPERTY;
 
 236         /* (omit javadoc for this method)
 
 237          * Method declared on ASTNode.
 
 239         final List internalStructuralPropertiesForType(int apiLevel) {
 
 240                 return propertyDescriptors(apiLevel);
 
 243         /* (omit javadoc for this method)
 
 244          * Method declared on ASTNode.
 
 246         final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) {
 
 247                 if (property == MODIFIERS_PROPERTY) {
 
 249                                 return getModifiers();
 
 255                 if (property == EXTRA_DIMENSIONS_PROPERTY) {
 
 257                                 return getExtraDimensions();
 
 259                                 setExtraDimensions(value);
 
 263                 // allow default implementation to flag the error
 
 264                 return super.internalGetSetIntProperty(property, get, value);
 
 267         /* (omit javadoc for this method)
 
 268          * Method declared on ASTNode.
 
 270         final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) {
 
 271                 if (property == VARARGS_PROPERTY) {
 
 279                 // allow default implementation to flag the error
 
 280                 return super.internalGetSetBooleanProperty(property, get, value);
 
 283         /* (omit javadoc for this method)
 
 284          * Method declared on ASTNode.
 
 286         final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
 
 287                 if (property == NAME_PROPERTY) {
 
 291                                 setName((SimpleName) child);
 
 295                 if (property == TYPE_PROPERTY) {
 
 299                                 setType((Type) child);
 
 303                 if (property == INITIALIZER_PROPERTY) {
 
 305                                 return getInitializer();
 
 307                                 setInitializer((Expression) child);
 
 311                 // allow default implementation to flag the error
 
 312                 return super.internalGetSetChildProperty(property, get, child);
 
 315         /* (omit javadoc for this method)
 
 316          * Method declared on ASTNode.
 
 318         final List internalGetChildListProperty(ChildListPropertyDescriptor property) {
 
 319                 if (property == MODIFIERS2_PROPERTY) {
 
 322                 // allow default implementation to flag the error
 
 323                 return super.internalGetChildListProperty(property);
 
 326         /* (omit javadoc for this method)
 
 327          * Method declared on ASTNode.
 
 329         final int getNodeType0() {
 
 330                 return SINGLE_VARIABLE_DECLARATION;
 
 333         /* (omit javadoc for this method)
 
 334          * Method declared on ASTNode.
 
 336         ASTNode clone0(AST target) {
 
 337                 SingleVariableDeclaration result = new SingleVariableDeclaration(target);
 
 338                 result.setSourceRange(this.getStartPosition(), this.getLength());
 
 339                 if (this.ast.apiLevel == AST.JLS2_INTERNAL) {
 
 340                         result.setModifiers(getModifiers());
 
 342                         result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers()));
 
 343                         result.setVarargs(isVarargs());
 
 345                 result.setType((Type) getType().clone(target));
 
 346                 result.setExtraDimensions(getExtraDimensions());
 
 347                 result.setName((SimpleName) getName().clone(target));
 
 348                 result.setInitializer(
 
 349                         (Expression) ASTNode.copySubtree(target, getInitializer()));
 
 353         /* (omit javadoc for this method)
 
 354          * Method declared on ASTNode.
 
 356         final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
 
 357                 // dispatch to correct overloaded match method
 
 358                 return matcher.match(this, other);
 
 361         /* (omit javadoc for this method)
 
 362          * Method declared on ASTNode.
 
 364         void accept0(ASTVisitor visitor) {
 
 365                 boolean visitChildren = visitor.visit(this);
 
 367                         // visit children in normal left to right reading order
 
 368                         if (this.ast.apiLevel >= AST.JLS3) {
 
 369                                 acceptChildren(visitor, this.modifiers);
 
 371                         acceptChild(visitor, getType());
 
 372                         acceptChild(visitor, getName());
 
 373                         acceptChild(visitor, getInitializer());
 
 375                 visitor.endVisit(this);
 
 379          * Returns the live ordered list of modifiers and annotations
 
 380          * of this declaration (added in JLS3 API).
 
 382          * Note that the final modifier is the only meaningful modifier for local
 
 383          * variable and formal parameter declarations.
 
 386          * @return the live list of modifiers and annotations
 
 387          *    (element type: <code>IExtendedModifier</code>)
 
 388          * @exception UnsupportedOperationException if this operation is used in
 
 392         public List modifiers() {
 
 393                 // more efficient than just calling unsupportedIn2() to check
 
 394                 if (this.modifiers == null) {
 
 397                 return this.modifiers;
 
 401          * Returns the modifiers explicitly specified on this declaration.
 
 403          * In the JLS3 API, this method is a convenience method that
 
 404          * computes these flags from <code>modifiers()</code>.
 
 407          * @return the bit-wise or of <code>Modifier</code> constants
 
 410         public int getModifiers() {
 
 411                 // more efficient than checking getAST().API_LEVEL
 
 412                 if (this.modifiers == null) {
 
 413                         // JLS2 behavior - bona fide property
 
 414                         return this.modifierFlags;
 
 416                         // JLS3 behavior - convenient method
 
 417                         // performance could be improved by caching computed flags
 
 418                         // but this would require tracking changes to this.modifiers
 
 419                         int computedModifierFlags = Modifier.NONE;
 
 420                         for (Iterator it = modifiers().iterator(); it.hasNext(); ) {
 
 421                                 Object x = it.next();
 
 422                                 if (x instanceof Modifier) {
 
 423                                         computedModifierFlags |= ((Modifier) x).getKeyword().toFlagValue();
 
 426                         return computedModifierFlags;
 
 431          * Sets the modifiers explicitly specified on this declaration (JLS2 API only).
 
 433          * The following modifiers are meaningful for fields: public, private, protected,
 
 434          * static, final, volatile, and transient. For local variable and formal
 
 435          * parameter declarations, the only meaningful modifier is final.
 
 438          * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants)
 
 439          * @exception UnsupportedOperationException if this operation is used in
 
 440          * an AST later than JLS2
 
 442          * @deprecated In the JLS3 API, this method is replaced by 
 
 443          * {@link  #modifiers()} which contains a list of a <code>Modifier</code> nodes.
 
 445         public void setModifiers(int modifiers) {
 
 446                 internalSetModifiers(modifiers);
 
 450          * Internal synonym for deprecated method. Used to avoid
 
 451          * deprecation warnings.
 
 454         /*package*/ final void internalSetModifiers(int pmodifiers) {
 
 456                 preValueChange(MODIFIERS_PROPERTY);
 
 457                 this.modifierFlags = pmodifiers;
 
 458                 postValueChange(MODIFIERS_PROPERTY);
 
 461         /* (omit javadoc for this method)
 
 462          * Method declared on VariableDeclaration.
 
 464         public SimpleName getName() {
 
 465                 if (this.variableName == null) {
 
 466                         // lazy init must be thread-safe for readers
 
 467                         synchronized (this) {
 
 468                                 if (this.variableName == null) {
 
 470                                         this.variableName = new SimpleName(this.ast);
 
 471                                         postLazyInit(this.variableName, NAME_PROPERTY);
 
 475                 return this.variableName;
 
 478         /* (omit javadoc for this method)
 
 479          * Method declared on VariableDeclaration.
 
 481         public void setName(SimpleName variableName) {
 
 482                 if (variableName == null) {
 
 483                         throw new IllegalArgumentException();
 
 485                 ASTNode oldChild = this.variableName;
 
 486                 preReplaceChild(oldChild, variableName, NAME_PROPERTY);
 
 487                 this.variableName = variableName;
 
 488                 postReplaceChild(oldChild, variableName, NAME_PROPERTY);
 
 492          * Returns the type of the variable declared in this variable declaration,
 
 493          * exclusive of any extra array dimensions.
 
 497         public Type getType() {
 
 498                 if (this.type == null) {
 
 499                         // lazy init must be thread-safe for readers
 
 500                         synchronized (this) {
 
 501                                 if (this.type == null) {
 
 503                                         this.type = this.ast.newPrimitiveType(PrimitiveType.INT);
 
 504                                         postLazyInit(this.type, TYPE_PROPERTY);
 
 512          * Sets the type of the variable declared in this variable declaration to 
 
 513          * the given type, exclusive of any extra array dimensions.
 
 515          * @param type the new type
 
 516          * @exception IllegalArgumentException if:
 
 518          * <li>the node belongs to a different AST</li>
 
 519          * <li>the node already has a parent</li>
 
 522         public void setType(Type type) {
 
 524                         throw new IllegalArgumentException();
 
 526                 ASTNode oldChild = this.type;
 
 527                 preReplaceChild(oldChild, type, TYPE_PROPERTY);
 
 529                 postReplaceChild(oldChild, type, TYPE_PROPERTY);
 
 533          * Returns whether this declaration declares the last parameter of
 
 534          * a variable arity method (added in JLS3 API).
 
 536          * Note that the binding for the type <code>Foo</code>in the vararg method
 
 537          * declaration <code>void fun(Foo... args)</code> is always for the type as 
 
 538          * written; i.e., the type binding for <code>Foo</code>. However, if you
 
 539          * navigate from the method declaration to its method binding to the
 
 540          * type binding for its last parameter, the type binding for the vararg
 
 541          * parameter is always an array type (i.e., <code>Foo[]</code>) reflecting
 
 542          * the way vararg methods get compiled.
 
 545          * @return <code>true</code> if this is a variable arity parameter declaration,
 
 546          *    and <code>false</code> otherwise
 
 547          * @exception UnsupportedOperationException if this operation is used in
 
 551         public boolean isVarargs() {
 
 552                 // more efficient than just calling unsupportedIn2() to check
 
 553                 if (this.modifiers == null) {
 
 556                 return this.variableArity;
 
 560          * Sets whether this declaration declares the last parameter of
 
 561          * a variable arity method (added in JLS3 API).
 
 563          * @param variableArity <code>true</code> if this is a variable arity
 
 564          *    parameter declaration, and <code>false</code> otherwise
 
 567         public void setVarargs(boolean variableArity) {
 
 568                 // more efficient than just calling unsupportedIn2() to check
 
 569                 if (this.modifiers == null) {
 
 572                 preValueChange(VARARGS_PROPERTY);
 
 573                 this.variableArity = variableArity;
 
 574                 postValueChange(VARARGS_PROPERTY);
 
 577         /* (omit javadoc for this method)
 
 578          * Method declared on VariableDeclaration.
 
 581         public int getExtraDimensions() {
 
 582                 return this.extraArrayDimensions;
 
 585         /* (omit javadoc for this method)
 
 586          * Method declared on VariableDeclaration.
 
 589         public void setExtraDimensions(int dimensions) {
 
 590                 if (dimensions < 0) {
 
 591                         throw new IllegalArgumentException();
 
 593                 preValueChange(EXTRA_DIMENSIONS_PROPERTY);
 
 594                 this.extraArrayDimensions = dimensions;
 
 595                 postValueChange(EXTRA_DIMENSIONS_PROPERTY);
 
 598         /* (omit javadoc for this method)
 
 599          * Method declared on VariableDeclaration.
 
 601         public Expression getInitializer() {
 
 602                 return this.optionalInitializer;
 
 605         /* (omit javadoc for this method)
 
 606          * Method declared on VariableDeclaration.
 
 608         public void setInitializer(Expression initializer) {
 
 609                 // a SingleVariableDeclaration may occur inside an Expression 
 
 611                 ASTNode oldChild = this.optionalInitializer;
 
 612                 preReplaceChild(oldChild, initializer,INITIALIZER_PROPERTY);
 
 613                 this.optionalInitializer = initializer;
 
 614                 postReplaceChild(oldChild, initializer,INITIALIZER_PROPERTY);
 
 617         /* (omit javadoc for this method)
 
 618          * Method declared on ASTNode.
 
 621                 // treat Operator as free
 
 622                 return BASE_NODE_SIZE + 7 * 4;
 
 625         /* (omit javadoc for this method)
 
 626          * Method declared on ASTNode.
 
 631                         + (this.modifiers == null ? 0 : this.modifiers.listSize())
 
 632                         + (this.type == null ? 0 : getType().treeSize())
 
 633                         + (this.variableName == null ? 0 : getName().treeSize())
 
 634                         + (this.optionalInitializer == null ? 0 : getInitializer().treeSize());