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