f6ce5f39ed51b53b9223fd860f1ffb036061b09a
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / VariableDeclarationExpression.java
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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.core.dom;
13
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17
18 /**
19  * Local variable declaration expression AST node type.
20  * <p>
21  * This kind of node collects together several variable declaration fragments
22  * (<code>VariableDeclarationFragment</code>) into a single expression
23  * (<code>Expression</code>), all sharing the same modifiers and base type.
24  * This type of node can be used as the initializer of a
25  * <code>ForStatement</code>, or wrapped in an <code>ExpressionStatement</code>
26  * to form the equivalent of a <code>VariableDeclarationStatement</code>.
27  * </p>
28  * For JLS2:
29  * <pre>
30  * VariableDeclarationExpression:
31  *    { Modifier } Type VariableDeclarationFragment
32  *         { <b>,</b> VariableDeclarationFragment } 
33  * </pre>
34  * For JLS3, the modifier flags were replaced by
35  * a list of modifier nodes (intermixed with annotations):
36  * <pre>
37  * VariableDeclarationExpression:
38  *    { ExtendedModifier } Type VariableDeclarationFragment
39  *         { <b>,</b> VariableDeclarationFragment } 
40  * </pre>
41  * 
42  * @since 2.0
43  * @noinstantiate This class is not intended to be instantiated by clients.
44  */
45 public class VariableDeclarationExpression extends Expression {
46
47         /**
48          * The "modifiers" structural property of this node type (JLS2 API only).
49          * @since 3.0
50          */
51         public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = 
52                 new SimplePropertyDescriptor(VariableDeclarationExpression.class, "modifiers", int.class, MANDATORY); //$NON-NLS-1$
53         
54         /**
55          * The "modifiers" structural property of this node type (added in JLS3 API).
56          * @since 3.1
57          */
58         public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = 
59                 new ChildListPropertyDescriptor(VariableDeclarationExpression.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$
60         
61         /**
62          * The "type" structural property of this node type.
63          * @since 3.0
64          */
65         public static final ChildPropertyDescriptor TYPE_PROPERTY = 
66                 new ChildPropertyDescriptor(VariableDeclarationExpression.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
67
68         /**
69          * The "fragments" structural property of this node type).
70          * @since 3.0
71          */
72         public static final ChildListPropertyDescriptor FRAGMENTS_PROPERTY = 
73                 new ChildListPropertyDescriptor(VariableDeclarationExpression.class, "fragments", VariableDeclarationFragment.class, CYCLE_RISK); //$NON-NLS-1$
74
75         /**
76          * A list of property descriptors (element type: 
77          * {@link StructuralPropertyDescriptor}),
78          * or null if uninitialized.
79          * @since 3.0
80          */
81         private static final List PROPERTY_DESCRIPTORS_2_0;
82         
83         /**
84          * A list of property descriptors (element type: 
85          * {@link StructuralPropertyDescriptor}),
86          * or null if uninitialized.
87          * @since 3.1
88          */
89         private static final List PROPERTY_DESCRIPTORS_3_0;
90         
91         static {
92                 List propertyList = new ArrayList(4);
93                 createPropertyList(VariableDeclarationExpression.class, propertyList);
94                 addProperty(MODIFIERS_PROPERTY, propertyList);
95                 addProperty(TYPE_PROPERTY, propertyList);
96                 addProperty(FRAGMENTS_PROPERTY, propertyList);
97                 PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList);
98                 
99                 propertyList = new ArrayList(4);
100                 createPropertyList(VariableDeclarationExpression.class, propertyList);
101                 addProperty(MODIFIERS2_PROPERTY, propertyList);
102                 addProperty(TYPE_PROPERTY, propertyList);
103                 addProperty(FRAGMENTS_PROPERTY, propertyList);
104                 PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList);
105         }
106
107         /**
108          * Returns a list of structural property descriptors for this node type.
109          * Clients must not modify the result.
110          * 
111          * @param apiLevel the API level; one of the
112          * <code>AST.JLS*</code> constants
113
114          * @return a list of property descriptors (element type: 
115          * {@link StructuralPropertyDescriptor})
116          * @since 3.0
117          */
118         public static List propertyDescriptors(int apiLevel) {
119                 if (apiLevel == AST.JLS2_INTERNAL) {
120                         return PROPERTY_DESCRIPTORS_2_0;
121                 } else {
122                         return PROPERTY_DESCRIPTORS_3_0;
123                 }
124         }
125                         
126         /**
127          * The extended modifiers (element type: <code>IExtendedModifier</code>). 
128          * Null in JLS2. Added in JLS3; defaults to an empty list
129          * (see constructor).
130          * @since 3.0
131          */
132         private ASTNode.NodeList modifiers = null;
133         
134         /**
135          * The modifier flags; bit-wise or of Modifier flags.
136          * Defaults to none. Not used in 3.0.
137          */
138         private int modifierFlags = Modifier.NONE;
139                 
140         /**
141          * The base type; lazily initialized; defaults to an unspecified,
142          * legal type.
143          */
144         private Type baseType = null;
145
146         /**
147          * The list of variable declaration fragments (element type: 
148          * <code VariableDeclarationFragment</code>).  Defaults to an empty list.
149          */
150         private ASTNode.NodeList variableDeclarationFragments = 
151                 new ASTNode.NodeList(FRAGMENTS_PROPERTY);
152
153         /**
154          * Creates a new unparented local variable declaration expression node
155          * owned by the given AST.  By default, the variable declaration has: no
156          * modifiers, an unspecified (but legal) type, and an empty list of variable
157          * declaration fragments (which is syntactically illegal).
158          * <p>
159          * N.B. This constructor is package-private.
160          * </p>
161          * 
162          * @param ast the AST that is to own this node
163          */
164         VariableDeclarationExpression(AST ast) {
165                 super(ast);
166                 if (ast.apiLevel >= AST.JLS3) {
167                         this.modifiers = new ASTNode.NodeList(MODIFIERS2_PROPERTY);
168                 }
169         }
170
171         /* (omit javadoc for this method)
172          * Method declared on ASTNode.
173          */
174         final List internalStructuralPropertiesForType(int apiLevel) {
175                 return propertyDescriptors(apiLevel);
176         }
177         
178         /* (omit javadoc for this method)
179          * Method declared on ASTNode.
180          */
181         final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) {
182                 if (property == MODIFIERS_PROPERTY) {
183                         if (get) {
184                                 return getModifiers();
185                         } else {
186                                 setModifiers(value);
187                                 return 0;
188                         }
189                 }
190                 // allow default implementation to flag the error
191                 return super.internalGetSetIntProperty(property, get, value);
192         }
193         
194         /* (omit javadoc for this method)
195          * Method declared on ASTNode.
196          */
197         final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
198                 if (property == TYPE_PROPERTY) {
199                         if (get) {
200                                 return getType();
201                         } else {
202                                 setType((Type) child);
203                                 return null;
204                         }
205                 }
206                 // allow default implementation to flag the error
207                 return super.internalGetSetChildProperty(property, get, child);
208         }
209         
210         /* (omit javadoc for this method)
211          * Method declared on ASTNode.
212          */
213         final List internalGetChildListProperty(ChildListPropertyDescriptor property) {
214                 if (property == MODIFIERS2_PROPERTY) {
215                         return modifiers();
216                 }
217                 if (property == FRAGMENTS_PROPERTY) {
218                         return fragments();
219                 }
220                 // allow default implementation to flag the error
221                 return super.internalGetChildListProperty(property);
222         }
223         
224         /* (omit javadoc for this method)
225          * Method declared on ASTNode.
226          */
227         final int getNodeType0() {
228                 return VARIABLE_DECLARATION_EXPRESSION;
229         }
230
231         /* (omit javadoc for this method)
232          * Method declared on ASTNode.
233          */
234         ASTNode clone0(AST target) {
235                 VariableDeclarationExpression result = 
236                         new VariableDeclarationExpression(target);
237                 result.setSourceRange(this.getStartPosition(), this.getLength());
238                 if (this.ast.apiLevel == AST.JLS2_INTERNAL) {
239                         result.setModifiers(getModifiers());
240                 }
241                 if (this.ast.apiLevel >= AST.JLS3) {
242                         result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers()));
243                 }
244                 result.setType((Type) getType().clone(target));
245                 result.fragments().addAll(
246                         ASTNode.copySubtrees(target, fragments()));
247                 return result;
248
249         }
250         
251         /* (omit javadoc for this method)
252          * Method declared on ASTNode.
253          */
254         final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
255                 // dispatch to correct overloaded match method
256                 return matcher.match(this, other);
257         }
258
259         /* (omit javadoc for this method)
260          * Method declared on ASTNode.
261          */
262         void accept0(ASTVisitor visitor) {
263                 boolean visitChildren = visitor.visit(this);
264                 if (visitChildren) {
265                         // visit children in normal left to right reading order
266                         if (this.ast.apiLevel >= AST.JLS3) {
267                                 acceptChildren(visitor, this.modifiers);
268                         }
269                         acceptChild(visitor, getType());
270                         acceptChildren(visitor, variableDeclarationFragments);
271                 }
272                 visitor.endVisit(this);
273         }
274         
275         /**
276          * Returns the live ordered list of modifiers and annotations
277          * of this declaration (added in JLS3 API).
278          * <p>
279          * Note that the final modifier is the only meaningful modifier for local
280          * variable declarations.
281          * </p>
282          * 
283          * @return the live list of modifiers and annotations
284          *    (element type: <code>IExtendedModifier</code>)
285          * @exception UnsupportedOperationException if this operation is used in
286          * a JLS2 AST
287          * @since 3.1
288          */ 
289         public List modifiers() {
290                 // more efficient than just calling unsupportedIn2() to check
291                 if (this.modifiers == null) {
292                         unsupportedIn2();
293                 }
294                 return this.modifiers;
295         }
296         
297         /**
298          * Returns the modifiers explicitly specified on this declaration.
299          * <p>
300          * In the JLS3 API, this method is a convenience method that
301          * computes these flags from <code>modifiers()</code>.
302          * </p>
303          * 
304          * @return the bit-wise or of <code>Modifier</code> constants
305          * @see Modifier
306          */ 
307         public int getModifiers() {
308                 // more efficient than checking getAST().API_LEVEL
309                 if (this.modifiers == null) {
310                         // JLS2 behavior - bona fide property
311                         return this.modifierFlags;
312                 } else {
313                         // JLS3 behavior - convenient method
314                         // performance could be improved by caching computed flags
315                         // but this would require tracking changes to this.modifiers
316                         int computedModifierFlags = Modifier.NONE;
317                         for (Iterator it = modifiers().iterator(); it.hasNext(); ) {
318                                 Object x = it.next();
319                                 if (x instanceof Modifier) {
320                                         computedModifierFlags |= ((Modifier) x).getKeyword().toFlagValue();
321                                 }
322                         }
323                         return computedModifierFlags;
324                 }
325         }
326
327         /**
328          * Sets the modifiers explicitly specified on this declaration (JLS2 API only).
329          * <p>
330          * Note that the final modifier is the only meaningful modifier for local
331          * variable declarations.
332          * </p>
333          * 
334          * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants)
335          * @exception UnsupportedOperationException if this operation is used in
336          * an AST later than JLS2
337          * @see Modifier
338          * @deprecated In the JLS3 API, this method is replaced by 
339          * {@link  #modifiers()} which contains a list of a <code>Modifier</code> nodes.
340          */ 
341         public void setModifiers(int modifiers) {
342                 internalSetModifiers(modifiers);
343         }
344         
345         /**
346          * Internal synonym for deprecated method. Used to avoid
347          * deprecation warnings.
348          * @since 3.1
349          */
350         /*package*/ final void internalSetModifiers(int pmodifiers) {
351             supportedOnlyIn2();
352                 preValueChange(MODIFIERS_PROPERTY);
353                 this.modifierFlags = pmodifiers;
354                 postValueChange(MODIFIERS_PROPERTY);
355         }
356
357         /**
358          * Returns the base type declared in this variable declaration.
359          * <p>
360          * N.B. The individual child variable declaration fragments may specify 
361          * additional array dimensions. So the type of the variable are not 
362          * necessarily exactly this type.
363          * </p>
364          * 
365          * @return the base type
366          */ 
367         public Type getType() {
368                 if (this.baseType == null) {
369                         // lazy init must be thread-safe for readers
370                         synchronized (this) {
371                                 if (this.baseType == null) {
372                                         preLazyInit();
373                                         this.baseType = this.ast.newPrimitiveType(PrimitiveType.INT);
374                                         postLazyInit(this.baseType, TYPE_PROPERTY);
375                                 }
376                         }
377                 }
378                 return this.baseType;
379         }
380
381         /**
382          * Sets the base type declared in this variable declaration to the given
383          * type.
384          * 
385          * @param type the new base type
386          * @exception IllegalArgumentException if:
387          * <ul>
388          * <li>the node belongs to a different AST</li>
389          * <li>the node already has a parent</li>
390          * </ul>
391          */ 
392         public void setType(Type type) {
393                 if (type == null) {
394                         throw new IllegalArgumentException();
395                 }
396                 ASTNode oldChild = this.baseType;
397                 preReplaceChild(oldChild, type, TYPE_PROPERTY);
398                 this.baseType = type;
399                 postReplaceChild(oldChild, type, TYPE_PROPERTY);
400         }
401
402         /**
403          * Returns the live list of variable declaration fragments in this 
404          * expression. Adding and removing nodes from this list affects this node
405          * dynamically. All nodes in this list must be 
406          * <code>VariableDeclarationFragment</code>s; attempts to add any other
407          * type of node will trigger an exception.
408          * 
409          * @return the live list of variable declaration fragments in this 
410          *    expression (element type: <code>VariableDeclarationFragment</code>)
411          */ 
412         public List fragments() {
413                 return this.variableDeclarationFragments;
414         }
415
416         /* (omit javadoc for this method)
417          * Method declared on ASTNode.
418          */
419         int memSize() {
420                 // treat Operator as free
421                 return BASE_NODE_SIZE + 4 * 4;
422         }
423         
424         /* (omit javadoc for this method)
425          * Method declared on ASTNode.
426          */
427         int treeSize() {
428                 return 
429                         memSize()
430                         + (this.modifiers == null ? 0 : this.modifiers.listSize())
431                         + (this.baseType == null ? 0 : getType().treeSize())
432                         + this.variableDeclarationFragments.listSize();
433         }
434 }
435