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