1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2000, 2019 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.List; |
18 | |
19 | /** |
20 | * Abstract base class of all AST node types that declare a single |
21 | * variable. |
22 | * <pre> |
23 | * VariableDeclaration: |
24 | * SingleVariableDeclaration |
25 | * VariableDeclarationFragment |
26 | * </pre> |
27 | * |
28 | * @see SingleVariableDeclaration |
29 | * @see VariableDeclarationFragment |
30 | * @since 2.0 |
31 | */ |
32 | @SuppressWarnings({"rawtypes"}) |
33 | public abstract class VariableDeclaration extends ASTNode { |
34 | |
35 | /** |
36 | * The variable name; lazily initialized; defaults to an unspecified, |
37 | * legal Java identifier. |
38 | */ |
39 | SimpleName variableName = null; |
40 | |
41 | /** |
42 | * The number of extra array dimensions that appear after the variable; |
43 | * defaults to 0. Not used in JLS8 and later. |
44 | * |
45 | * @since 2.1 |
46 | * @deprecated In JLS8 and later, use {@link #extraDimensions} instead. |
47 | */ |
48 | int extraArrayDimensions = 0; |
49 | |
50 | /** |
51 | * List of extra dimensions this node has with optional annotations |
52 | * (element type: {@link Dimension}). |
53 | * Null before JLS8. Added in JLS8; defaults to an empty list |
54 | * (see constructor). |
55 | * |
56 | * @since 3.10 |
57 | */ |
58 | ASTNode.NodeList extraDimensions = null; |
59 | |
60 | /** |
61 | * The initializer expression, or <code>null</code> if none; |
62 | * defaults to none. |
63 | */ |
64 | Expression optionalInitializer = null; |
65 | |
66 | /** |
67 | * Creates and returns a structural property descriptor for the |
68 | * "name" property declared on the given concrete node type (child type: {@link SimpleName}). |
69 | * |
70 | * @return the property descriptor |
71 | */ |
72 | static final ChildPropertyDescriptor internalNamePropertyFactory(Class nodeClass) { |
73 | return new ChildPropertyDescriptor(nodeClass, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ |
74 | } |
75 | |
76 | /** |
77 | * Creates and returns a structural property descriptor for the |
78 | * "extraDimensions" property declared on the given concrete node type (type: {@link Integer}). |
79 | * |
80 | * @return the property descriptor |
81 | * @deprecated In JLS8 and later, use {@link #internalExtraDimensions2PropertyFactory(Class)} instead. |
82 | */ |
83 | static final SimplePropertyDescriptor internalExtraDimensionsPropertyFactory(Class nodeClass) { |
84 | return new SimplePropertyDescriptor(nodeClass, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$ |
85 | } |
86 | |
87 | /** |
88 | * Creates and returns a structural property descriptor for the |
89 | * "extraDimensions2" property declared on the given concrete node type (element type: {@link Dimension}). |
90 | * |
91 | * @return the property descriptor |
92 | */ |
93 | static final ChildListPropertyDescriptor internalExtraDimensions2PropertyFactory(Class nodeClass) { |
94 | return new ChildListPropertyDescriptor(nodeClass, "extraDimensions2", Dimension.class, CYCLE_RISK); //$NON-NLS-1$ |
95 | } |
96 | |
97 | /** |
98 | * Creates and returns a structural property descriptor for the |
99 | * "initializer" property declared on the given concrete node type (child type: {@link Expression}). |
100 | * |
101 | * @return the property descriptor |
102 | */ |
103 | static final ChildPropertyDescriptor internalInitializerPropertyFactory(Class nodeClass) { |
104 | return new ChildPropertyDescriptor(nodeClass, "initializer", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ |
105 | } |
106 | |
107 | /** |
108 | * Returns structural property descriptor for the "name" property |
109 | * of this node (child type: {@link SimpleName}). |
110 | * |
111 | * @return the property descriptor |
112 | * @since 3.1 |
113 | */ |
114 | abstract ChildPropertyDescriptor internalNameProperty(); |
115 | |
116 | /** |
117 | * Returns the structural property descriptor for the "name" property |
118 | * of this node (child type: {@link SimpleName}). |
119 | * |
120 | * @return the property descriptor |
121 | * @since 3.1 |
122 | */ |
123 | public final ChildPropertyDescriptor getNameProperty() { |
124 | return internalNameProperty(); |
125 | } |
126 | |
127 | |
128 | /** |
129 | * Returns the structural property descriptor for the "extraDimensions" property |
130 | * of this node (type: {@link Integer}) (below JLS8 only). |
131 | * |
132 | * @return the property descriptor |
133 | * @since 3.1 |
134 | * @deprecated In JLS8 and later, use {@link #internalExtraDimensions2Property()} instead. |
135 | */ |
136 | abstract SimplePropertyDescriptor internalExtraDimensionsProperty(); |
137 | |
138 | /** |
139 | * Returns the structural property descriptor for the "extraDimensions" property |
140 | * of this node (type: {@link Integer}) (below JLS8 only). |
141 | * |
142 | * @return the property descriptor |
143 | * @since 3.1 |
144 | * @deprecated In JLS8 and later, use {@link #getExtraDimensions2Property()} instead. |
145 | */ |
146 | public final SimplePropertyDescriptor getExtraDimensionsProperty() { |
147 | return internalExtraDimensionsProperty(); |
148 | } |
149 | |
150 | /** |
151 | * Returns the structural property descriptor for the "extraDimensions" property |
152 | * of this node (element type: {@link Dimension}) (added in JLS8 API). |
153 | * |
154 | * @return the property descriptor |
155 | * @since 3.10 |
156 | */ |
157 | abstract ChildListPropertyDescriptor internalExtraDimensions2Property(); |
158 | |
159 | /** |
160 | * Returns the structural property descriptor for the "extraDimensions" property |
161 | * of this node (element type: {@link Dimension}) (added in JLS8 API). |
162 | * |
163 | * @return the property descriptor |
164 | * @since 3.10 |
165 | */ |
166 | public final ChildListPropertyDescriptor getExtraDimensions2Property() { |
167 | return internalExtraDimensions2Property(); |
168 | } |
169 | |
170 | /** |
171 | * Returns structural property descriptor for the "initializer" property |
172 | * of this node (child type: {@link Expression}). |
173 | * |
174 | * @return the property descriptor |
175 | * @since 3.1 |
176 | */ |
177 | abstract ChildPropertyDescriptor internalInitializerProperty(); |
178 | |
179 | /** |
180 | * Returns structural property descriptor for the "initializer" property |
181 | * of this node (child type: {@link Expression}). |
182 | * |
183 | * @return the property descriptor |
184 | * @since 3.1 |
185 | */ |
186 | public final ChildPropertyDescriptor getInitializerProperty() { |
187 | return internalInitializerProperty(); |
188 | } |
189 | |
190 | /** |
191 | * Creates a new AST node for a variable declaration owned by the given AST. |
192 | * <p> |
193 | * N.B. This constructor is package-private. |
194 | * </p> |
195 | * |
196 | * @param ast the AST that is to own this node |
197 | */ |
198 | VariableDeclaration(AST ast) { |
199 | super(ast); |
200 | if (ast.apiLevel >= AST.JLS8_INTERNAL) { |
201 | this.extraDimensions = new ASTNode.NodeList(getExtraDimensions2Property()); |
202 | } |
203 | } |
204 | |
205 | /** |
206 | * Returns the name of the variable declared in this variable declaration. |
207 | * |
208 | * @return the variable name node |
209 | */ |
210 | public SimpleName getName() { |
211 | if (this.variableName == null) { |
212 | // lazy init must be thread-safe for readers |
213 | synchronized (this) { |
214 | if (this.variableName == null) { |
215 | preLazyInit(); |
216 | this.variableName = new SimpleName(this.ast); |
217 | postLazyInit(this.variableName, internalNameProperty()); |
218 | } |
219 | } |
220 | } |
221 | return this.variableName; |
222 | } |
223 | |
224 | /** |
225 | * Sets the name of the variable declared in this variable declaration |
226 | * to the given name. |
227 | * |
228 | * @param variableName the new variable name |
229 | * @exception IllegalArgumentException if: |
230 | * <ul> |
231 | * <li>the node belongs to a different AST</li> |
232 | * <li>the node already has a parent</li> |
233 | * </ul> |
234 | */ |
235 | public void setName(SimpleName variableName) { |
236 | if (variableName == null) { |
237 | throw new IllegalArgumentException(); |
238 | } |
239 | ChildPropertyDescriptor p = internalNameProperty(); |
240 | ASTNode oldChild = this.variableName; |
241 | preReplaceChild(oldChild, variableName, p); |
242 | this.variableName = variableName; |
243 | postReplaceChild(oldChild, variableName, p); |
244 | } |
245 | |
246 | /** |
247 | * Returns the number of extra array dimensions over and above the |
248 | * explicitly-specified type. |
249 | * <p> |
250 | * For example, <code>int x[][]</code> has a type of |
251 | * <code>int</code> and two extra array dimensions; |
252 | * <code>int[][] x</code> has a type of <code>int[][]</code> |
253 | * and zero extra array dimensions. The two constructs have different |
254 | * ASTs, even though there are really syntactic variants of the same |
255 | * variable declaration. |
256 | * </p> |
257 | * <p> |
258 | * In the JLS8 API, this method is a convenience method that |
259 | * counts {@link #extraDimensions()}. |
260 | * </p> |
261 | * |
262 | * @return the number of extra array dimensions |
263 | * @since 2.1 |
264 | */ |
265 | public int getExtraDimensions() { |
266 | // more efficient than checking getAST().API_LEVEL |
267 | if (this.extraDimensions == null) { |
268 | // JLS2,3,4 behavior - bona fide property |
269 | return this.extraArrayDimensions; |
270 | } else { |
271 | return this.extraDimensions.size(); |
272 | } |
273 | } |
274 | |
275 | /** |
276 | * Sets the number of extra array dimensions over and above the |
277 | * explicitly-specified type. |
278 | * <p> |
279 | * For example, <code>int x[][]</code> has a type of |
280 | * <code>int</code> and two extra array dimensions; |
281 | * <code>int[][] x</code> has a type of <code>int[][]</code> |
282 | * and zero extra array dimensions. The two constructs have different |
283 | * ASTs, even though there are really syntactic variants of the same |
284 | * variable declaration. |
285 | * </p> |
286 | * |
287 | * @param dimensions the number of array dimensions |
288 | * @exception IllegalArgumentException if the number of dimensions is |
289 | * negative |
290 | * @exception UnsupportedOperationException if this operation is used in |
291 | * a JLS8 or later AST |
292 | * @deprecated In the JLS8 API, this method is replaced by |
293 | * {@link #extraDimensions()} which contains a list of {@link Dimension} nodes. |
294 | * @since 2.1 |
295 | */ |
296 | public void setExtraDimensions(int dimensions) { |
297 | internalSetExtraDimensions(dimensions); |
298 | } |
299 | |
300 | /** |
301 | * Internal synonym for deprecated method. Used to avoid |
302 | * deprecation warnings. |
303 | * @since 3.10 |
304 | */ |
305 | final void internalSetExtraDimensions(int dimensions) { |
306 | // more efficient than just calling supportedOnlyIn2_3_4() to check |
307 | if (this.extraDimensions != null) { |
308 | supportedOnlyIn2_3_4(); |
309 | } |
310 | if (dimensions < 0) { |
311 | throw new IllegalArgumentException(); |
312 | } |
313 | SimplePropertyDescriptor p = internalExtraDimensionsProperty(); |
314 | preValueChange(p); |
315 | this.extraArrayDimensions = dimensions; |
316 | postValueChange(p); |
317 | } |
318 | |
319 | /** |
320 | * Returns the live ordered list of extra dimensions with optional annotations (added in JLS8 API). |
321 | * |
322 | * @return the live list of extra dimensions with optional annotations (element type: {@link Dimension}) |
323 | * @exception UnsupportedOperationException if this operation is used below JLS8 |
324 | * @since 3.10 |
325 | */ |
326 | public List extraDimensions() { |
327 | // more efficient than just calling unsupportedIn2_3_4() to check |
328 | if (this.extraDimensions == null) { |
329 | unsupportedIn2_3_4(); |
330 | } |
331 | return this.extraDimensions; |
332 | } |
333 | |
334 | /** |
335 | * Returns the initializer of this variable declaration, or |
336 | * <code>null</code> if there is none. |
337 | * |
338 | * @return the initializer expression node, or <code>null</code> if |
339 | * there is none |
340 | */ |
341 | public Expression getInitializer() { |
342 | return this.optionalInitializer; |
343 | } |
344 | |
345 | /** |
346 | * Sets or clears the initializer of this variable declaration. |
347 | * |
348 | * @param initializer the initializer expression node, or <code>null</code> |
349 | * if there is none |
350 | * @exception IllegalArgumentException if: |
351 | * <ul> |
352 | * <li>the node belongs to a different AST</li> |
353 | * <li>the node already has a parent</li> |
354 | * <li>a cycle in would be created</li> |
355 | * </ul> |
356 | */ |
357 | public void setInitializer(Expression initializer) { |
358 | ChildPropertyDescriptor p = internalInitializerProperty(); |
359 | ASTNode oldChild = this.optionalInitializer; |
360 | preReplaceChild(oldChild, initializer, p); |
361 | this.optionalInitializer = initializer; |
362 | postReplaceChild(oldChild, initializer, p); |
363 | } |
364 | |
365 | /** |
366 | * Resolves and returns the binding for the variable declared in this |
367 | * variable declaration. |
368 | * <p> |
369 | * Note that bindings are generally unavailable unless requested when the |
370 | * AST is being built. |
371 | * </p> |
372 | * |
373 | * @return the binding, or <code>null</code> if the binding cannot be |
374 | * resolved |
375 | */ |
376 | public IVariableBinding resolveBinding() { |
377 | return this.ast.getBindingResolver().resolveVariable(this); |
378 | } |
379 | } |
380 |
Members