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.HashMap; 19 import java.util.List; 20 import java.util.Map; 21 22 /** 23 * Assignment expression AST node type. 24 * 25 * <pre> 26 * Assignment: 27 * Expression AssignmentOperator Expression 28 * </pre> 29 * 30 * @since 2.0 31 * @noinstantiate This class is not intended to be instantiated by clients. 32 */ 33 @SuppressWarnings({"rawtypes", "unchecked"}) 34 public class Assignment extends Expression { 35 36 /** 37 * Assignment operators (typesafe enumeration). 38 * <pre> 39 * AssignmentOperator:<code> 40 * <b>=</b> ASSIGN 41 * <b>+=</b> PLUS_ASSIGN 42 * <b>-=</b> MINUS_ASSIGN 43 * <b>*=</b> TIMES_ASSIGN 44 * <b>/=</b> DIVIDE_ASSIGN 45 * <b>&=</b> BIT_AND_ASSIGN 46 * <b>|=</b> BIT_OR_ASSIGN 47 * <b>^=</b> BIT_XOR_ASSIGN 48 * <b>%=</b> REMAINDER_ASSIGN 49 * <b><<=</b> LEFT_SHIFT_ASSIGN 50 * <b>>>=</b> RIGHT_SHIFT_SIGNED_ASSIGN 51 * <b>>>>=</b> RIGHT_SHIFT_UNSIGNED_ASSIGN</code> 52 * </pre> 53 */ 54 public static class Operator { 55 56 /** 57 * The name of the operator 58 */ 59 private String op; 60 61 /** 62 * Creates a new assignment operator with the given name. 63 * <p> 64 * Note: this constructor is private. The only instances 65 * ever created are the ones for the standard operators. 66 * </p> 67 * 68 * @param op the character sequence for the operator 69 */ Operator(String op)70 private Operator(String op) { 71 this.op = op; 72 } 73 74 /** 75 * Returns the character sequence for the operator. 76 * 77 * @return the character sequence for the operator 78 */ 79 @Override toString()80 public String toString() { 81 return this.op; 82 } 83 84 /** = operator. */ 85 public static final Operator ASSIGN = new Operator("=");//$NON-NLS-1$ 86 /** += operator. */ 87 public static final Operator PLUS_ASSIGN = new Operator("+=");//$NON-NLS-1$ 88 /** -= operator. */ 89 public static final Operator MINUS_ASSIGN = new Operator("-=");//$NON-NLS-1$ 90 /** *= operator. */ 91 public static final Operator TIMES_ASSIGN = new Operator("*=");//$NON-NLS-1$ 92 /** /= operator. */ 93 public static final Operator DIVIDE_ASSIGN = new Operator("/=");//$NON-NLS-1$ 94 /** &= operator. */ 95 public static final Operator BIT_AND_ASSIGN = new Operator("&=");//$NON-NLS-1$ 96 /** |= operator. */ 97 public static final Operator BIT_OR_ASSIGN = new Operator("|=");//$NON-NLS-1$ 98 /** ^= operator. */ 99 public static final Operator BIT_XOR_ASSIGN = new Operator("^=");//$NON-NLS-1$ 100 /** %= operator. */ 101 public static final Operator REMAINDER_ASSIGN = new Operator("%=");//$NON-NLS-1$ 102 /** <<== operator. */ 103 public static final Operator LEFT_SHIFT_ASSIGN = 104 new Operator("<<=");//$NON-NLS-1$ 105 /** >>= operator. */ 106 public static final Operator RIGHT_SHIFT_SIGNED_ASSIGN = 107 new Operator(">>=");//$NON-NLS-1$ 108 /** >>>= operator. */ 109 public static final Operator RIGHT_SHIFT_UNSIGNED_ASSIGN = 110 new Operator(">>>=");//$NON-NLS-1$ 111 112 /** 113 * Returns the assignment operator corresponding to the given string, 114 * or <code>null</code> if none. 115 * <p> 116 * <code>toOperator</code> is the converse of <code>toString</code>: 117 * that is, <code>Operator.toOperator(op.toString()) == op</code> for all 118 * operators <code>op</code>. 119 * </p> 120 * 121 * @param token the character sequence for the operator 122 * @return the assignment operator, or <code>null</code> if none 123 */ toOperator(String token)124 public static Operator toOperator(String token) { 125 return (Operator) CODES.get(token); 126 } 127 128 /** 129 * Map from token to operator (key type: <code>String</code>; 130 * value type: <code>Operator</code>). 131 */ 132 private static final Map CODES; 133 static { 134 CODES = new HashMap(20); 135 Operator[] ops = { 136 ASSIGN, 137 PLUS_ASSIGN, 138 MINUS_ASSIGN, 139 TIMES_ASSIGN, 140 DIVIDE_ASSIGN, 141 BIT_AND_ASSIGN, 142 BIT_OR_ASSIGN, 143 BIT_XOR_ASSIGN, 144 REMAINDER_ASSIGN, 145 LEFT_SHIFT_ASSIGN, 146 RIGHT_SHIFT_SIGNED_ASSIGN, 147 RIGHT_SHIFT_UNSIGNED_ASSIGN 148 }; 149 for (int i = 0; i < ops.length; i++) { CODES.put(ops[i].toString(), ops[i])150 CODES.put(ops[i].toString(), ops[i]); 151 } 152 } 153 } 154 155 /** 156 * The "leftHandSide" structural property of this node type (child type: {@link Expression}). 157 * @since 3.0 158 */ 159 public static final ChildPropertyDescriptor LEFT_HAND_SIDE_PROPERTY = 160 new ChildPropertyDescriptor(Assignment.class, "leftHandSide", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ 161 162 /** 163 * The "operator" structural property of this node type (type: {@link Assignment.Operator}). 164 * @since 3.0 165 */ 166 public static final SimplePropertyDescriptor OPERATOR_PROPERTY = 167 new SimplePropertyDescriptor(Assignment.class, "operator", Assignment.Operator.class, MANDATORY); //$NON-NLS-1$ 168 169 /** 170 * The "rightHandSide" structural property of this node type (child type: {@link Expression}). 171 * @since 3.0 172 */ 173 public static final ChildPropertyDescriptor RIGHT_HAND_SIDE_PROPERTY = 174 new ChildPropertyDescriptor(Assignment.class, "rightHandSide", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ 175 176 /** 177 * A list of property descriptors (element type: 178 * {@link StructuralPropertyDescriptor}), 179 * or null if uninitialized. 180 */ 181 private static final List PROPERTY_DESCRIPTORS; 182 183 static { 184 List properyList = new ArrayList(4); createPropertyList(Assignment.class, properyList)185 createPropertyList(Assignment.class, properyList); addProperty(LEFT_HAND_SIDE_PROPERTY, properyList)186 addProperty(LEFT_HAND_SIDE_PROPERTY, properyList); addProperty(OPERATOR_PROPERTY, properyList)187 addProperty(OPERATOR_PROPERTY, properyList); addProperty(RIGHT_HAND_SIDE_PROPERTY, properyList)188 addProperty(RIGHT_HAND_SIDE_PROPERTY, properyList); 189 PROPERTY_DESCRIPTORS = reapPropertyList(properyList); 190 } 191 192 /** 193 * Returns a list of structural property descriptors for this node type. 194 * Clients must not modify the result. 195 * 196 * @param apiLevel the API level; one of the 197 * <code>AST.JLS*</code> constants 198 199 * @return a list of property descriptors (element type: 200 * {@link StructuralPropertyDescriptor}) 201 * @since 3.0 202 */ propertyDescriptors(int apiLevel)203 public static List propertyDescriptors(int apiLevel) { 204 return PROPERTY_DESCRIPTORS; 205 } 206 207 /** 208 * The assignment operator; defaults to Assignment.Operator.ASSIGN 209 */ 210 private Assignment.Operator assignmentOperator = Assignment.Operator.ASSIGN; 211 212 /** 213 * The left hand side; lazily initialized; defaults to an unspecified, 214 * but legal, simple name. 215 */ 216 private Expression leftHandSide = null; 217 218 /** 219 * The right hand side; lazily initialized; defaults to an unspecified, 220 * but legal, simple name. 221 */ 222 private Expression rightHandSide = null; 223 224 /** 225 * Creates a new AST node for an assignment expression owned by the given 226 * AST. By default, the node has an assignment operator, and unspecified 227 * left and right hand sides. 228 * 229 * @param ast the AST that is to own this node 230 */ Assignment(AST ast)231 Assignment(AST ast) { 232 super(ast); 233 } 234 235 @Override internalStructuralPropertiesForType(int apiLevel)236 final List internalStructuralPropertiesForType(int apiLevel) { 237 return propertyDescriptors(apiLevel); 238 } 239 240 @Override internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value)241 final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { 242 if (property == OPERATOR_PROPERTY) { 243 if (get) { 244 return getOperator(); 245 } else { 246 setOperator((Operator) value); 247 return null; 248 } 249 } 250 // allow default implementation to flag the error 251 return super.internalGetSetObjectProperty(property, get, value); 252 } 253 254 @Override internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child)255 final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { 256 if (property == LEFT_HAND_SIDE_PROPERTY) { 257 if (get) { 258 return getLeftHandSide(); 259 } else { 260 setLeftHandSide((Expression) child); 261 return null; 262 } 263 } 264 if (property == RIGHT_HAND_SIDE_PROPERTY) { 265 if (get) { 266 return getRightHandSide(); 267 } else { 268 setRightHandSide((Expression) child); 269 return null; 270 } 271 } 272 // allow default implementation to flag the error 273 return super.internalGetSetChildProperty(property, get, child); 274 } 275 276 @Override getNodeType0()277 final int getNodeType0() { 278 return ASSIGNMENT; 279 } 280 281 @Override clone0(AST target)282 ASTNode clone0(AST target) { 283 Assignment result = new Assignment(target); 284 result.setSourceRange(getStartPosition(), getLength()); 285 result.setOperator(getOperator()); 286 result.setLeftHandSide((Expression) getLeftHandSide().clone(target)); 287 result.setRightHandSide((Expression) getRightHandSide().clone(target)); 288 return result; 289 } 290 291 @Override subtreeMatch0(ASTMatcher matcher, Object other)292 final boolean subtreeMatch0(ASTMatcher matcher, Object other) { 293 // dispatch to correct overloaded match method 294 return matcher.match(this, other); 295 } 296 297 @Override accept0(ASTVisitor visitor)298 void accept0(ASTVisitor visitor) { 299 boolean visitChildren = visitor.visit(this); 300 if (visitChildren) { 301 // visit children in normal left to right reading order 302 acceptChild(visitor, getLeftHandSide()); 303 acceptChild(visitor, getRightHandSide()); 304 } 305 visitor.endVisit(this); 306 } 307 308 /** 309 * Returns the operator of this assignment expression. 310 * 311 * @return the assignment operator 312 */ getOperator()313 public Assignment.Operator getOperator() { 314 return this.assignmentOperator; 315 } 316 317 /** 318 * Sets the operator of this assignment expression. 319 * 320 * @param assignmentOperator the assignment operator 321 * @exception IllegalArgumentException if the argument is incorrect 322 */ setOperator(Assignment.Operator assignmentOperator)323 public void setOperator(Assignment.Operator assignmentOperator) { 324 if (assignmentOperator == null) { 325 throw new IllegalArgumentException(); 326 } 327 preValueChange(OPERATOR_PROPERTY); 328 this.assignmentOperator = assignmentOperator; 329 postValueChange(OPERATOR_PROPERTY); 330 } 331 332 /** 333 * Returns the left hand side of this assignment expression. 334 * 335 * @return the left hand side node 336 */ getLeftHandSide()337 public Expression getLeftHandSide() { 338 if (this.leftHandSide == null) { 339 // lazy init must be thread-safe for readers 340 synchronized (this) { 341 if (this.leftHandSide == null) { 342 preLazyInit(); 343 this.leftHandSide= new SimpleName(this.ast); 344 postLazyInit(this.leftHandSide, LEFT_HAND_SIDE_PROPERTY); 345 } 346 } 347 } 348 return this.leftHandSide; 349 } 350 351 /** 352 * Sets the left hand side of this assignment expression. 353 * 354 * @param expression the left hand side node 355 * @exception IllegalArgumentException if: 356 * <ul> 357 * <li>the node belongs to a different AST</li> 358 * <li>the node already has a parent</li> 359 * <li>a cycle in would be created</li> 360 * </ul> 361 */ setLeftHandSide(Expression expression)362 public void setLeftHandSide(Expression expression) { 363 if (expression == null) { 364 throw new IllegalArgumentException(); 365 } 366 // an Assignment may occur inside a Expression - must check cycles 367 ASTNode oldChild = this.leftHandSide; 368 preReplaceChild(oldChild, expression, LEFT_HAND_SIDE_PROPERTY); 369 this.leftHandSide = expression; 370 postReplaceChild(oldChild, expression, LEFT_HAND_SIDE_PROPERTY); 371 } 372 373 /** 374 * Returns the right hand side of this assignment expression. 375 * 376 * @return the right hand side node 377 */ getRightHandSide()378 public Expression getRightHandSide() { 379 if (this.rightHandSide == null) { 380 // lazy init must be thread-safe for readers 381 synchronized (this) { 382 if (this.rightHandSide == null) { 383 preLazyInit(); 384 this.rightHandSide= new SimpleName(this.ast); 385 postLazyInit(this.rightHandSide, RIGHT_HAND_SIDE_PROPERTY); 386 } 387 } 388 } 389 return this.rightHandSide; 390 } 391 392 /** 393 * Sets the right hand side of this assignment expression. 394 * 395 * @param expression the right hand side node 396 * @exception IllegalArgumentException if: 397 * <ul> 398 * <li>the node belongs to a different AST</li> 399 * <li>the node already has a parent</li> 400 * <li>a cycle in would be created</li> 401 * </ul> 402 */ setRightHandSide(Expression expression)403 public void setRightHandSide(Expression expression) { 404 if (expression == null) { 405 throw new IllegalArgumentException(); 406 } 407 // an Assignment may occur inside a Expression - must check cycles 408 ASTNode oldChild = this.rightHandSide; 409 preReplaceChild(oldChild, expression, RIGHT_HAND_SIDE_PROPERTY); 410 this.rightHandSide = expression; 411 postReplaceChild(oldChild, expression, RIGHT_HAND_SIDE_PROPERTY); 412 } 413 414 @Override memSize()415 int memSize() { 416 // treat Code as free 417 return BASE_NODE_SIZE + 3 * 4; 418 } 419 420 @Override treeSize()421 int treeSize() { 422 return 423 memSize() 424 + (this.leftHandSide == null ? 0 : getLeftHandSide().treeSize()) 425 + (this.rightHandSide == null ? 0 : getRightHandSide().treeSize()); 426 } 427 } 428 429