d38f31170777543898dc9ed361ae3a709600ea67
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / core / dom / FieldAccess.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.core.dom;
13
14 import java.util.ArrayList;
15 import java.util.List;
16
17 /**
18  * Field access expression AST node type.
19  *
20  * <pre>
21  * FieldAccess: 
22  *              Expression <b>.</b> Identifier
23  * </pre>
24  * 
25  * <p>
26  * Note that there are several kinds of expressions that resemble field access
27  * expressions: qualified names, this expressions, and super field access
28  * expressions. The following guidelines help with correct usage:
29  * <ul>
30  *   <li>An expression like "foo.this" can only be represented as a this
31  *   expression (<code>ThisExpression</code>) containing a simple name.
32  *   "this" is a keyword, and therefore invalid as an identifier.</li>
33  *   <li>An expression like "this.foo" can only be represented as a field
34  *   access expression (<code>FieldAccess</code>) containing a this expression
35  *   and a simple name. Again, this is because "this" is a keyword, and
36  *   therefore invalid as an identifier.</li>
37  *   <li>An expression with "super" can only be represented as a super field
38  *   access expression (<code>SuperFieldAccess</code>). "super" is a also
39  *   keyword, and therefore invalid as an identifier.</li>
40  *   <li>An expression like "foo.bar" can be represented either as a
41  *   qualified name (<code>QualifiedName</code>) or as a field access
42  *   expression (<code>FieldAccess</code>) containing simple names. Either
43  *   is acceptable, and there is no way to choose between them without
44  *   information about what the names resolve to
45  *   (<code>ASTParser</code> may return either).</li>
46  *   <li>Other expressions ending in an identifier, such as "foo().bar" can
47  *   only be represented as field access expressions
48  *   (<code>FieldAccess</code>).</li>
49  * </ul>
50  * </p>
51  * 
52  * @see QualifiedName
53  * @see ThisExpression
54  * @see SuperFieldAccess
55  * @since 2.0
56  * @noinstantiate This class is not intended to be instantiated by clients.
57  */
58 public class FieldAccess extends Expression {
59         
60         /**
61          * The "expression" structural property of this node type.
62          * @since 3.0
63          */
64         public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = 
65                 new ChildPropertyDescriptor(FieldAccess.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
66
67         /**
68          * The "name" structural property of this node type.
69          * @since 3.0
70          */
71         public static final ChildPropertyDescriptor NAME_PROPERTY = 
72                 new ChildPropertyDescriptor(FieldAccess.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
73
74         /**
75          * A list of property descriptors (element type: 
76          * {@link StructuralPropertyDescriptor}),
77          * or null if uninitialized.
78          */
79         private static final List PROPERTY_DESCRIPTORS;
80         
81         static {
82                 List properyList = new ArrayList(3);
83                 createPropertyList(FieldAccess.class, properyList);
84                 addProperty(EXPRESSION_PROPERTY, properyList);
85                 addProperty(NAME_PROPERTY, properyList);
86                 PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
87         }
88
89         /**
90          * Returns a list of structural property descriptors for this node type.
91          * Clients must not modify the result.
92          * 
93          * @param apiLevel the API level; one of the
94          * <code>AST.JLS*</code> constants
95
96          * @return a list of property descriptors (element type: 
97          * {@link StructuralPropertyDescriptor})
98          * @since 3.0
99          */
100         public static List propertyDescriptors(int apiLevel) {
101                 return PROPERTY_DESCRIPTORS;
102         }
103                         
104         /**
105          * The expression; lazily initialized; defaults to an unspecified,
106          * but legal, simple name.
107          */
108         private Expression expression = null;
109
110         /**
111          * The field; lazily initialized; defaults to an unspecified,
112          * but legal, simple field name.
113          */
114         private SimpleName fieldName = null;
115
116         /**
117          * Creates a new unparented node for a field access expression owned by the
118          * given AST. By default, the expression and field are both unspecified,
119          * but legal, names.
120          * <p>
121          * N.B. This constructor is package-private.
122          * </p>
123          * 
124          * @param ast the AST that is to own this node
125          */
126         FieldAccess(AST ast) {
127                 super(ast);
128         }
129
130         /* (omit javadoc for this method)
131          * Method declared on ASTNode.
132          */
133         final List internalStructuralPropertiesForType(int apiLevel) {
134                 return propertyDescriptors(apiLevel);
135         }
136         
137         /* (omit javadoc for this method)
138          * Method declared on ASTNode.
139          */
140         final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
141                 if (property == EXPRESSION_PROPERTY) {
142                         if (get) {
143                                 return getExpression();
144                         } else {
145                                 setExpression((Expression) child);
146                                 return null;
147                         }
148                 }
149                 if (property == NAME_PROPERTY) {
150                         if (get) {
151                                 return getName();
152                         } else {
153                                 setName((SimpleName) child);
154                                 return null;
155                         }
156                 }
157                 // allow default implementation to flag the error
158                 return super.internalGetSetChildProperty(property, get, child);
159         }
160         
161         /* (omit javadoc for this method)
162          * Method declared on ASTNode.
163          */
164         final int getNodeType0() {
165                 return FIELD_ACCESS;
166         }
167
168         /* (omit javadoc for this method)
169          * Method declared on ASTNode.
170          */
171         ASTNode clone0(AST target) {
172                 FieldAccess result = new FieldAccess(target);
173                 result.setSourceRange(this.getStartPosition(), this.getLength());
174                 result.setExpression((Expression) getExpression().clone(target));
175                 result.setName((SimpleName) getName().clone(target));
176                 return result;
177         }
178
179         /* (omit javadoc for this method)
180          * Method declared on ASTNode.
181          */
182         final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
183                 // dispatch to correct overloaded match method
184                 return matcher.match(this, other);
185         }
186
187         /* (omit javadoc for this method)
188          * Method declared on ASTNode.
189          */
190         void accept0(ASTVisitor visitor) {
191                 boolean visitChildren = visitor.visit(this);
192                 if (visitChildren) {
193                         // visit children in normal left to right reading order
194                         acceptChild(visitor, getExpression());
195                         acceptChild(visitor, getName());
196                 }
197                 visitor.endVisit(this);
198         }
199         
200         /**
201          * Returns the expression of this field access expression.
202          * 
203          * @return the expression node
204          */ 
205         public Expression getExpression() {
206                 if (this.expression == null) {
207                         // lazy init must be thread-safe for readers
208                         synchronized (this) {
209                                 if (this.expression == null) {
210                                         preLazyInit();
211                                         this.expression = new SimpleName(this.ast);
212                                         postLazyInit(this.expression, EXPRESSION_PROPERTY);
213                                 }
214                         }
215                 }
216                 return this.expression;
217         }
218                 
219         /**
220          * Sets the expression of this field access expression.
221          * 
222          * @param expression the new expression
223          * @exception IllegalArgumentException if:
224          * <ul>
225          * <li>the node belongs to a different AST</li>
226          * <li>the node already has a parent</li>
227          * <li>a cycle in would be created</li>
228          * </ul>
229          */ 
230         public void setExpression(Expression expression) {
231                 if (expression == null) {
232                         throw new IllegalArgumentException();
233                 }
234                 ASTNode oldChild = this.expression;
235                 preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY);
236                 this.expression = expression;
237                 postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY);
238         }
239
240         /**
241          * Returns the name of the field accessed in this field access expression.
242          * 
243          * @return the field name
244          */ 
245         public SimpleName getName() {
246                 if (this.fieldName == null) {
247                         // lazy init must be thread-safe for readers
248                         synchronized (this) {
249                                 if (this.fieldName == null) {
250                                         preLazyInit();
251                                         this.fieldName = new SimpleName(this.ast);
252                                         postLazyInit(this.fieldName, NAME_PROPERTY);
253                                 }
254                         }
255                 }
256                 return this.fieldName;
257         }
258                 
259         /**
260          * Sets the name of the field accessed in this field access expression.
261          * 
262          * @param fieldName the field name
263          * @exception IllegalArgumentException if:
264          * <ul>
265          * <li>the node belongs to a different AST</li>
266          * <li>the node already has a parent</li>
267          * </ul>
268          */ 
269         public void setName(SimpleName fieldName) {
270                 if (fieldName == null) {
271                         throw new IllegalArgumentException();
272                 }
273                 ASTNode oldChild = this.fieldName;
274                 preReplaceChild(oldChild, fieldName, NAME_PROPERTY);
275                 this.fieldName = fieldName;
276                 postReplaceChild(oldChild, fieldName, NAME_PROPERTY);
277         }
278
279         /* (omit javadoc for this method)
280          * Method declared on ASTNode.
281          */
282         int memSize() {
283                 // treat Code as free
284                 return BASE_NODE_SIZE + 2 * 4;
285         }
286         
287         /**
288          * Resolves and returns the binding for the field accessed by this
289          * expression.
290          * <p>
291          * Note that bindings are generally unavailable unless requested when the
292          * AST is being built.
293          * </p>
294          *
295          * @return the variable binding, or <code>null</code> if the binding cannot
296          * be resolved
297          * @since 3.0
298          */
299         public IVariableBinding resolveFieldBinding() {
300                 return this.ast.getBindingResolver().resolveField(this);
301         }
302         
303         /* (omit javadoc for this method)
304          * Method declared on ASTNode.
305          */
306         int treeSize() {
307                 return 
308                         memSize()
309                         + (this.expression == null ? 0 : getExpression().treeSize())
310                         + (this.fieldName == null ? 0 : getName().treeSize());
311         }
312 }
313