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.List; |
19 | |
20 | /** |
21 | * If statement AST node type. |
22 | * <pre> |
23 | * IfStatement: |
24 | * <b>if</b> <b>(</b> Expression <b>)</b> Statement [ <b>else</b> Statement] |
25 | * </pre> |
26 | * |
27 | * @since 2.0 |
28 | * @noinstantiate This class is not intended to be instantiated by clients. |
29 | */ |
30 | @SuppressWarnings("rawtypes") |
31 | public class IfStatement extends Statement { |
32 | |
33 | /** |
34 | * The "expression" structural property of this node type (child type: {@link Expression}). |
35 | * @since 3.0 |
36 | */ |
37 | public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = |
38 | new ChildPropertyDescriptor(IfStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ |
39 | |
40 | /** |
41 | * The "thenStatement" structural property of this node type (child type: {@link Statement}). |
42 | * @since 3.0 |
43 | */ |
44 | public static final ChildPropertyDescriptor THEN_STATEMENT_PROPERTY = |
45 | new ChildPropertyDescriptor(IfStatement.class, "thenStatement", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ |
46 | |
47 | /** |
48 | * The "elseStatement" structural property of this node type (child type: {@link Statement}). |
49 | * @since 3.0 |
50 | */ |
51 | public static final ChildPropertyDescriptor ELSE_STATEMENT_PROPERTY = |
52 | new ChildPropertyDescriptor(IfStatement.class, "elseStatement", Statement.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ |
53 | |
54 | /** |
55 | * A list of property descriptors (element type: |
56 | * {@link StructuralPropertyDescriptor}), |
57 | * or null if uninitialized. |
58 | */ |
59 | private static final List PROPERTY_DESCRIPTORS; |
60 | |
61 | static { |
62 | List properyList = new ArrayList(4); |
63 | createPropertyList(IfStatement.class, properyList); |
64 | addProperty(EXPRESSION_PROPERTY, properyList); |
65 | addProperty(THEN_STATEMENT_PROPERTY, properyList); |
66 | addProperty(ELSE_STATEMENT_PROPERTY, properyList); |
67 | PROPERTY_DESCRIPTORS = reapPropertyList(properyList); |
68 | } |
69 | |
70 | /** |
71 | * Returns a list of structural property descriptors for this node type. |
72 | * Clients must not modify the result. |
73 | * |
74 | * @param apiLevel the API level; one of the |
75 | * <code>AST.JLS*</code> constants |
76 | |
77 | * @return a list of property descriptors (element type: |
78 | * {@link StructuralPropertyDescriptor}) |
79 | * @since 3.0 |
80 | */ |
81 | public static List propertyDescriptors(int apiLevel) { |
82 | return PROPERTY_DESCRIPTORS; |
83 | } |
84 | |
85 | /** |
86 | * The expression; lazily initialized; defaults to an unspecified, but |
87 | * legal, expression. |
88 | */ |
89 | private Expression expression = null; |
90 | |
91 | /** |
92 | * The then statement; lazily initialized; defaults to an unspecified, but |
93 | * legal, statement. |
94 | */ |
95 | private Statement thenStatement = null; |
96 | |
97 | /** |
98 | * The else statement; <code>null</code> for none; defaults to none. |
99 | */ |
100 | private Statement optionalElseStatement = null; |
101 | |
102 | /** |
103 | * Creates a new unparented if statement node owned by the given |
104 | * AST. By default, the expresssion is unspecified, |
105 | * but legal, the then statement is an empty block, and there is no else |
106 | * statement. |
107 | * <p> |
108 | * N.B. This constructor is package-private. |
109 | * </p> |
110 | * |
111 | * @param ast the AST that is to own this node |
112 | */ |
113 | IfStatement(AST ast) { |
114 | super(ast); |
115 | } |
116 | |
117 | @Override |
118 | final List internalStructuralPropertiesForType(int apiLevel) { |
119 | return propertyDescriptors(apiLevel); |
120 | } |
121 | |
122 | @Override |
123 | final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { |
124 | if (property == EXPRESSION_PROPERTY) { |
125 | if (get) { |
126 | return getExpression(); |
127 | } else { |
128 | setExpression((Expression) child); |
129 | return null; |
130 | } |
131 | } |
132 | if (property == THEN_STATEMENT_PROPERTY) { |
133 | if (get) { |
134 | return getThenStatement(); |
135 | } else { |
136 | setThenStatement((Statement) child); |
137 | return null; |
138 | } |
139 | } |
140 | if (property == ELSE_STATEMENT_PROPERTY) { |
141 | if (get) { |
142 | return getElseStatement(); |
143 | } else { |
144 | setElseStatement((Statement) child); |
145 | return null; |
146 | } |
147 | } |
148 | // allow default implementation to flag the error |
149 | return super.internalGetSetChildProperty(property, get, child); |
150 | } |
151 | |
152 | @Override |
153 | final int getNodeType0() { |
154 | return IF_STATEMENT; |
155 | } |
156 | |
157 | @Override |
158 | ASTNode clone0(AST target) { |
159 | IfStatement result = new IfStatement(target); |
160 | result.setSourceRange(getStartPosition(), getLength()); |
161 | result.copyLeadingComment(this); |
162 | result.setExpression((Expression) getExpression().clone(target)); |
163 | result.setThenStatement( |
164 | (Statement) getThenStatement().clone(target)); |
165 | result.setElseStatement( |
166 | (Statement) ASTNode.copySubtree(target, getElseStatement())); |
167 | return result; |
168 | } |
169 | |
170 | @Override |
171 | final boolean subtreeMatch0(ASTMatcher matcher, Object other) { |
172 | // dispatch to correct overloaded match method |
173 | return matcher.match(this, other); |
174 | } |
175 | |
176 | @Override |
177 | void accept0(ASTVisitor visitor) { |
178 | boolean visitChildren = visitor.visit(this); |
179 | if (visitChildren) { |
180 | // visit children in normal left to right reading order |
181 | acceptChild(visitor, getExpression()); |
182 | acceptChild(visitor, getThenStatement()); |
183 | acceptChild(visitor, getElseStatement()); |
184 | } |
185 | visitor.endVisit(this); |
186 | } |
187 | |
188 | /** |
189 | * Returns the expression of this if statement. |
190 | * |
191 | * @return the expression node |
192 | */ |
193 | public Expression getExpression() { |
194 | if (this.expression == null) { |
195 | // lazy init must be thread-safe for readers |
196 | synchronized (this) { |
197 | if (this.expression == null) { |
198 | preLazyInit(); |
199 | this.expression = new SimpleName(this.ast); |
200 | postLazyInit(this.expression, EXPRESSION_PROPERTY); |
201 | } |
202 | } |
203 | } |
204 | return this.expression; |
205 | } |
206 | |
207 | /** |
208 | * Sets the condition of this if statement. |
209 | * |
210 | * @param expression the expression node |
211 | * @exception IllegalArgumentException if: |
212 | * <ul> |
213 | * <li>the node belongs to a different AST</li> |
214 | * <li>the node already has a parent</li> |
215 | * <li>a cycle in would be created</li> |
216 | * </ul> |
217 | */ |
218 | public void setExpression(Expression expression) { |
219 | if (expression == null) { |
220 | throw new IllegalArgumentException(); |
221 | } |
222 | ASTNode oldChild = this.expression; |
223 | preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); |
224 | this.expression = expression; |
225 | postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); |
226 | } |
227 | |
228 | /** |
229 | * Returns the "then" part of this if statement. |
230 | * |
231 | * @return the "then" statement node |
232 | */ |
233 | public Statement getThenStatement() { |
234 | if (this.thenStatement == null) { |
235 | // lazy init must be thread-safe for readers |
236 | synchronized (this) { |
237 | if (this.thenStatement == null) { |
238 | preLazyInit(); |
239 | this.thenStatement = new Block(this.ast); |
240 | postLazyInit(this.thenStatement, THEN_STATEMENT_PROPERTY); |
241 | } |
242 | } |
243 | } |
244 | return this.thenStatement; |
245 | } |
246 | |
247 | /** |
248 | * Sets the "then" part of this if statement. |
249 | * <p> |
250 | * Special note: The Java language does not allow a local variable declaration |
251 | * to appear as the "then" part of an if statement (they may only appear within a |
252 | * block). However, the AST will allow a <code>VariableDeclarationStatement</code> |
253 | * as the thenStatement of a <code>IfStatement</code>. To get something that will |
254 | * compile, be sure to embed the <code>VariableDeclarationStatement</code> |
255 | * inside a <code>Block</code>. |
256 | * </p> |
257 | * |
258 | * @param statement the "then" statement node |
259 | * @exception IllegalArgumentException if: |
260 | * <ul> |
261 | * <li>the node belongs to a different AST</li> |
262 | * <li>the node already has a parent</li> |
263 | * <li>a cycle in would be created</li> |
264 | * </ul> |
265 | */ |
266 | public void setThenStatement(Statement statement) { |
267 | if (statement == null) { |
268 | throw new IllegalArgumentException(); |
269 | } |
270 | ASTNode oldChild = this.thenStatement; |
271 | preReplaceChild(oldChild, statement, THEN_STATEMENT_PROPERTY); |
272 | this.thenStatement = statement; |
273 | postReplaceChild(oldChild, statement, THEN_STATEMENT_PROPERTY); |
274 | } |
275 | |
276 | /** |
277 | * Returns the "else" part of this if statement, or <code>null</code> if |
278 | * this if statement has <b>no</b> "else" part. |
279 | * <p> |
280 | * Note that there is a subtle difference between having no else |
281 | * statement and having an empty statement ("{}") or null statement (";"). |
282 | * </p> |
283 | * |
284 | * @return the "else" statement node, or <code>null</code> if none |
285 | */ |
286 | public Statement getElseStatement() { |
287 | return this.optionalElseStatement; |
288 | } |
289 | |
290 | /** |
291 | * Sets or clears the "else" part of this if statement. |
292 | * <p> |
293 | * Note that there is a subtle difference between having no else part |
294 | * (as in <code>"if(true){}"</code>) and having an empty block (as in |
295 | * "if(true){}else{}") or null statement (as in "if(true){}else;"). |
296 | * </p> |
297 | * <p> |
298 | * Special note: The Java language does not allow a local variable declaration |
299 | * to appear as the "else" part of an if statement (they may only appear within a |
300 | * block). However, the AST will allow a <code>VariableDeclarationStatement</code> |
301 | * as the elseStatement of a <code>IfStatement</code>. To get something that will |
302 | * compile, be sure to embed the <code>VariableDeclarationStatement</code> |
303 | * inside a <code>Block</code>. |
304 | * </p> |
305 | * |
306 | * @param statement the "else" statement node, or <code>null</code> if |
307 | * there is none |
308 | * @exception IllegalArgumentException if: |
309 | * <ul> |
310 | * <li>the node belongs to a different AST</li> |
311 | * <li>the node already has a parent</li> |
312 | * <li>a cycle in would be created</li> |
313 | * </ul> |
314 | */ |
315 | public void setElseStatement(Statement statement) { |
316 | ASTNode oldChild = this.optionalElseStatement; |
317 | preReplaceChild(oldChild, statement, ELSE_STATEMENT_PROPERTY); |
318 | this.optionalElseStatement = statement; |
319 | postReplaceChild(oldChild, statement, ELSE_STATEMENT_PROPERTY); |
320 | } |
321 | |
322 | @Override |
323 | int memSize() { |
324 | return super.memSize() + 3 * 4; |
325 | } |
326 | |
327 | @Override |
328 | int treeSize() { |
329 | return |
330 | memSize() |
331 | + (this.expression == null ? 0 : getExpression().treeSize()) |
332 | + (this.thenStatement == null ? 0 : getThenStatement().treeSize()) |
333 | + (this.optionalElseStatement == null ? 0 : getElseStatement().treeSize()); |
334 | } |
335 | } |
336 | |
337 |
Members