1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2000, 2021 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 | * Contributors: |
11 | * IBM Corporation - initial API and implementation |
12 | *******************************************************************************/ |
13 | |
14 | package org.eclipse.jdt.core.dom; |
15 | |
16 | import java.util.ArrayList; |
17 | import java.util.List; |
18 | |
19 | /** |
20 | * Switch case AST node type. A switch case is a special kind of node used only |
21 | * in switch statements. It is a <code>Statement</code> in name only. |
22 | * <pre> |
23 | * SwitchCase: |
24 | * <b>case</b> Expression <b>:</b> |
25 | * <b>default</b> <b>:</b> |
26 | * |
27 | * Switch case allows multiple expressions and '->' as part of Java 12 preview feature (JEP 325) |
28 | * <b>case</b> [ Expression { <b>,</b> Expression } ] <b>{ : | ->}</b> |
29 | * <b>default</b> <b>{ : | ->}</b> |
30 | * </pre> |
31 | * |
32 | * @since 2.0 |
33 | * @noinstantiate This class is not intended to be instantiated by clients. |
34 | */ |
35 | @SuppressWarnings("rawtypes") |
36 | public class SwitchCase extends Statement { |
37 | |
38 | /** |
39 | * The "expression" structural property of this node type (child type: {@link Expression}). |
40 | * @since 3.0 |
41 | * @deprecated In the JLS 12 15.28.1 API, this property is replaced by {@link #EXPRESSIONS2_PROPERTY }. |
42 | */ |
43 | public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = |
44 | new ChildPropertyDescriptor(SwitchCase.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ |
45 | |
46 | /** |
47 | * The "expression" structural property of this node type (child type: {@link Expression}). (added in JEP 325). |
48 | * @since 3.18 |
49 | */ |
50 | public static final ChildListPropertyDescriptor EXPRESSIONS2_PROPERTY = |
51 | new ChildListPropertyDescriptor(SwitchCase.class, "expression", Expression.class, CYCLE_RISK); //$NON-NLS-1$); |
52 | |
53 | /** |
54 | * The "switchLabeledRule" structural property of this node type (type: {@link Boolean}). |
55 | * @since 3.18 |
56 | */ |
57 | public static final SimplePropertyDescriptor SWITCH_LABELED_RULE_PROPERTY = |
58 | new SimplePropertyDescriptor(SwitchCase.class, "switchLabeledRule", boolean.class, MANDATORY); //$NON-NLS-1$ |
59 | |
60 | /** |
61 | * A list of property descriptors (element type: |
62 | * {@link StructuralPropertyDescriptor}), |
63 | * or null if uninitialized. |
64 | */ |
65 | private static final List PROPERTY_DESCRIPTORS; |
66 | |
67 | /** |
68 | * A list of property descriptors (element type: |
69 | * {@link StructuralPropertyDescriptor}), |
70 | * or null if uninitialized. |
71 | */ |
72 | private static final List PROPERTY_DESCRIPTORS_13; |
73 | |
74 | static { |
75 | List propertyList = new ArrayList(2); |
76 | createPropertyList(SwitchCase.class, propertyList); |
77 | addProperty(EXPRESSION_PROPERTY, propertyList); |
78 | PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); |
79 | |
80 | propertyList = new ArrayList(2); |
81 | createPropertyList(SwitchCase.class, propertyList); |
82 | addProperty(EXPRESSIONS2_PROPERTY , propertyList); |
83 | addProperty(SWITCH_LABELED_RULE_PROPERTY, propertyList); |
84 | PROPERTY_DESCRIPTORS_13 = reapPropertyList(propertyList); |
85 | } |
86 | |
87 | /** |
88 | * Returns a list of structural property descriptors for this node type. |
89 | * Clients must not modify the result. |
90 | * |
91 | * @param apiLevel the API level; one of the |
92 | * <code>AST.JLS*</code> constants |
93 | * @return a list of property descriptors (element type: |
94 | * {@link StructuralPropertyDescriptor}) |
95 | * @since 3.0 |
96 | */ |
97 | public static List propertyDescriptors(int apiLevel) { |
98 | if (apiLevel >= AST.JLS14_INTERNAL) { |
99 | return PROPERTY_DESCRIPTORS_13; |
100 | } |
101 | return PROPERTY_DESCRIPTORS; |
102 | } |
103 | |
104 | /** |
105 | * The expression; <code>null</code> for none; lazily initialized (but |
106 | * does <b>not</b> default to none). |
107 | * @see #expressionInitialized |
108 | */ |
109 | private Expression optionalExpression = null; |
110 | |
111 | /** |
112 | * <code>true</code> indicates "->" and <code>false</code> indicates ":". |
113 | */ |
114 | private boolean switchLabeledRule = false; |
115 | |
116 | |
117 | /** |
118 | * The expression list; <code>empty</code> for none; |
119 | */ |
120 | private ASTNode.NodeList expressions = null; |
121 | |
122 | /** |
123 | * Indicates whether <code>optionalExpression</code> has been initialized. |
124 | */ |
125 | private boolean expressionInitialized = false; |
126 | |
127 | /** |
128 | * Creates a new AST node for a switch case pseudo-statement owned by the |
129 | * given AST. By default, there is no expression, but legal, and switchLabeledRule |
130 | * is false which indicates ":". |
131 | * |
132 | * @param ast the AST that is to own this node |
133 | */ |
134 | SwitchCase(AST ast) { |
135 | super(ast); |
136 | if (ast.apiLevel >= AST.JLS14_INTERNAL) { |
137 | this.expressions = new ASTNode.NodeList(EXPRESSIONS2_PROPERTY ); |
138 | } |
139 | } |
140 | |
141 | @Override |
142 | final List internalStructuralPropertiesForType(int apiLevel) { |
143 | return propertyDescriptors(apiLevel); |
144 | } |
145 | |
146 | @Override |
147 | final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { |
148 | if (property == SWITCH_LABELED_RULE_PROPERTY) { |
149 | if (get) { |
150 | return isSwitchLabeledRule(); |
151 | } else { |
152 | setSwitchLabeledRule(value); |
153 | return false; |
154 | } |
155 | } |
156 | // allow default implementation to flag the error |
157 | return super.internalGetSetBooleanProperty(property, get, value); |
158 | } |
159 | |
160 | @Override |
161 | final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { |
162 | if (property == EXPRESSION_PROPERTY) { |
163 | if (get) { |
164 | return getExpression(); |
165 | } else { |
166 | setExpression((Expression) child); |
167 | return null; |
168 | } |
169 | } |
170 | // allow default implementation to flag the error |
171 | return super.internalGetSetChildProperty(property, get, child); |
172 | } |
173 | |
174 | @Override |
175 | final List internalGetChildListProperty(ChildListPropertyDescriptor property) { |
176 | if (property == EXPRESSIONS2_PROPERTY ) { |
177 | return expressions(); |
178 | } |
179 | // allow default implementation to flag the error |
180 | return super.internalGetChildListProperty(property); |
181 | } |
182 | |
183 | @Override |
184 | final int getNodeType0() { |
185 | return SWITCH_CASE; |
186 | } |
187 | |
188 | @SuppressWarnings("unchecked") |
189 | @Override |
190 | ASTNode clone0(AST target) { |
191 | SwitchCase result = new SwitchCase(target); |
192 | result.setSourceRange(getStartPosition(), getLength()); |
193 | result.copyLeadingComment(this); |
194 | if (this.ast.apiLevel >= AST.JLS14_INTERNAL) { |
195 | result.expressions().addAll( |
196 | ASTNode.copySubtrees(target, expressions())); |
197 | } else { |
198 | result.setExpression( |
199 | (Expression) ASTNode.copySubtree(target, getExpression())); |
200 | } |
201 | return result; |
202 | } |
203 | |
204 | @Override |
205 | final boolean subtreeMatch0(ASTMatcher matcher, Object other) { |
206 | // dispatch to correct overloaded match method |
207 | return matcher.match(this, other); |
208 | } |
209 | |
210 | @Override |
211 | void accept0(ASTVisitor visitor) { |
212 | boolean visitChildren = visitor.visit(this); |
213 | if (visitChildren) { |
214 | if (this.ast.apiLevel >= AST.JLS14_INTERNAL) { |
215 | acceptChildren(visitor, this.expressions); |
216 | } else { |
217 | acceptChild(visitor, getExpression()); |
218 | } |
219 | } |
220 | visitor.endVisit(this); |
221 | } |
222 | |
223 | /** |
224 | * Returns the expression of this switch case, or |
225 | * <code>null</code> if there is none (the "default:" case). |
226 | * |
227 | * @return the expression node, or <code>null</code> if there is none |
228 | * @deprecated use expressions() (see JLS 12) |
229 | */ |
230 | public Expression getExpression() { |
231 | if (!this.expressionInitialized) { |
232 | // lazy init must be thread-safe for readers |
233 | synchronized (this) { |
234 | if (!this.expressionInitialized) { |
235 | preLazyInit(); |
236 | this.optionalExpression = new SimpleName(this.ast); |
237 | this.expressionInitialized = true; |
238 | postLazyInit(this.optionalExpression, EXPRESSION_PROPERTY); |
239 | } |
240 | } |
241 | } |
242 | return this.optionalExpression; |
243 | } |
244 | |
245 | /** |
246 | * Returns the list of expressions of this switch case, or |
247 | * <code>empty</code> if there is none (the "default:" case). |
248 | * |
249 | * @return the list of expression nodes |
250 | * (element type: {@link Expression}) |
251 | * @exception UnsupportedOperationException if this operation is used below JLS14 |
252 | * @since 3.22 |
253 | */ |
254 | public List expressions() { |
255 | if (this.expressions == null) { |
256 | unsupportedBelow14(); |
257 | } |
258 | return this.expressions; |
259 | } |
260 | |
261 | /** |
262 | * Sets the expression of this switch case, or clears it (turns it into |
263 | * the "default:" case). |
264 | * |
265 | * @param expression the expression node, or <code>null</code> to |
266 | * turn it into the "default:" case |
267 | * @exception IllegalArgumentException if: |
268 | * <ul> |
269 | * <li>the node belongs to a different AST</li> |
270 | * <li>the node already has a parent</li> |
271 | * <li>a cycle in would be created</li> |
272 | * </ul> |
273 | * @deprecated see JLS 12 |
274 | */ |
275 | public void setExpression(Expression expression) { |
276 | ASTNode oldChild = this.optionalExpression; |
277 | preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); |
278 | this.optionalExpression = expression; |
279 | this.expressionInitialized = true; |
280 | postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); |
281 | } |
282 | |
283 | /** |
284 | * Sets the switchLabeledRule of this switch case as <code>true</code> or <code>false</code>. |
285 | * <code>true</code> indicates "->" and <code>false</code> indicates ":". |
286 | |
287 | * @param switchLabeledRule <code>true</code> or <code>false</code> |
288 | * @exception UnsupportedOperationException if this operation is used below JLS14 |
289 | * @since 3.22 |
290 | */ |
291 | public void setSwitchLabeledRule(boolean switchLabeledRule) { |
292 | unsupportedBelow14(); |
293 | preValueChange(SWITCH_LABELED_RULE_PROPERTY); |
294 | this.switchLabeledRule = switchLabeledRule; |
295 | postValueChange(SWITCH_LABELED_RULE_PROPERTY); |
296 | } |
297 | |
298 | /** |
299 | * Gets the switchLabeledRule of this switch case as <code>true</code> or <code>false</code>. |
300 | *<code>true</code> indicates "->" and <code>false</code> indicates ":". |
301 | * |
302 | * @return switchLabeledRule <code>true</code> or <code>false</code> |
303 | * @exception UnsupportedOperationException if this operation is used below JLS14 |
304 | * @since 3.22 |
305 | */ |
306 | public boolean isSwitchLabeledRule() { |
307 | unsupportedBelow14(); |
308 | return this.switchLabeledRule; |
309 | } |
310 | |
311 | /** |
312 | * Returns whether this switch case represents the "default:" case. |
313 | * <p> |
314 | * This convenience method is equivalent to |
315 | * <code>getExpression() == null</code> or <code>expressions().isEmpty()</code>. |
316 | * </p> |
317 | * |
318 | * @return <code>true</code> if this is the default switch case, and |
319 | * <code>false</code> if this is a non-default switch case |
320 | */ |
321 | public boolean isDefault() { |
322 | if (this.ast.apiLevel >= AST.JLS14_INTERNAL) { |
323 | return expressions().isEmpty(); |
324 | } |
325 | return getExpression() == null; |
326 | } |
327 | |
328 | @Override |
329 | int memSize() { |
330 | return super.memSize() + 2 * 4; |
331 | } |
332 | |
333 | @Override |
334 | int treeSize() { |
335 | return |
336 | memSize() |
337 | + (this.optionalExpression == null ? 0 : this.optionalExpression.treeSize()); |
338 | } |
339 | |
340 | |
341 | } |
342 |
Members