001: /*******************************************************************************
002: * Copyright (c) 2003, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.core.dom;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: /**
016: * Type node for a qualified type (added in JLS3 API).
017: * <pre>
018: * QualifiedType:
019: * Type <b>.</b> SimpleName
020: * </pre>
021: * <p>
022: * Not all node arragements will represent legal Java constructs. In particular,
023: * it is nonsense if the type is an array type or primitive type. The normal use
024: * is when the type is a simple or parameterized type.
025: * </p>
026: * <p>
027: * A type like "A.B" can be represented either of two ways:
028: * <ol>
029: * <li>
030: * <code>QualifiedType(SimpleType(SimpleName("A")),SimpleName("B"))</code>
031: * </li>
032: * <li>
033: * <code>SimpleType(QualifiedName(SimpleName("A"),SimpleName("B")))</code>
034: * </li>
035: * </ol>
036: * The first form is preferred when "A" is known to be a type. However, a
037: * parser cannot always determine this. Clients should be prepared to handle
038: * either rather than make assumptions. (Note also that the first form
039: * became possible as of JLS3; only the second form existed in JLS2 API.)
040: * </p>
041: *
042: * @since 3.1
043: */
044: public class QualifiedType extends Type {
045: /**
046: * This index represents the position inside a parameterized qualified type.
047: */
048: int index;
049:
050: /**
051: * The "qualifier" structural property of this node type.
052: */
053: public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = new ChildPropertyDescriptor(
054: QualifiedType.class,
055: "qualifier", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
056:
057: /**
058: * The "name" structural property of this node type.
059: */
060: public static final ChildPropertyDescriptor NAME_PROPERTY = new ChildPropertyDescriptor(
061: QualifiedType.class,
062: "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
063:
064: /**
065: * A list of property descriptors (element type:
066: * {@link StructuralPropertyDescriptor}),
067: * or null if uninitialized.
068: */
069: private static final List PROPERTY_DESCRIPTORS;
070:
071: static {
072: List propertyList = new ArrayList(3);
073: createPropertyList(QualifiedType.class, propertyList);
074: addProperty(QUALIFIER_PROPERTY, propertyList);
075: addProperty(NAME_PROPERTY, propertyList);
076: PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
077: }
078:
079: /**
080: * Returns a list of structural property descriptors for this node type.
081: * Clients must not modify the result.
082: *
083: * @param apiLevel the API level; one of the
084: * <code>AST.JLS*</code> constants
085: * @return a list of property descriptors (element type:
086: * {@link StructuralPropertyDescriptor})
087: */
088: public static List propertyDescriptors(int apiLevel) {
089: return PROPERTY_DESCRIPTORS;
090: }
091:
092: /**
093: * The type node; lazily initialized; defaults to a type with
094: * an unspecfied, but legal, simple name.
095: */
096: private Type qualifier = null;
097:
098: /**
099: * The name being qualified; lazily initialized; defaults to a unspecified,
100: * legal Java identifier.
101: */
102: private SimpleName name = null;
103:
104: /**
105: * Creates a new unparented node for a qualified type owned by the
106: * given AST. By default, an unspecified, but legal, qualifier and name.
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: QualifiedType(AST ast) {
114: super (ast);
115: unsupportedIn2();
116: }
117:
118: /* (omit javadoc for this method)
119: * Method declared on ASTNode.
120: */
121: final List internalStructuralPropertiesForType(int apiLevel) {
122: return propertyDescriptors(apiLevel);
123: }
124:
125: /* (omit javadoc for this method)
126: * Method declared on ASTNode.
127: */
128: final ASTNode internalGetSetChildProperty(
129: ChildPropertyDescriptor property, boolean get, ASTNode child) {
130: if (property == QUALIFIER_PROPERTY) {
131: if (get) {
132: return getQualifier();
133: } else {
134: setQualifier((Type) child);
135: return null;
136: }
137: }
138: if (property == NAME_PROPERTY) {
139: if (get) {
140: return getName();
141: } else {
142: setName((SimpleName) child);
143: return null;
144: }
145: }
146: // allow default implementation to flag the error
147: return super .internalGetSetChildProperty(property, get, child);
148: }
149:
150: /* (omit javadoc for this method)
151: * Method declared on ASTNode.
152: */
153: final int getNodeType0() {
154: return QUALIFIED_TYPE;
155: }
156:
157: /* (omit javadoc for this method)
158: * Method declared on ASTNode.
159: */
160: ASTNode clone0(AST target) {
161: QualifiedType result = new QualifiedType(target);
162: result
163: .setSourceRange(this .getStartPosition(), this
164: .getLength());
165: result.setQualifier((Type) ((ASTNode) getQualifier())
166: .clone(target));
167: result
168: .setName((SimpleName) ((ASTNode) getName())
169: .clone(target));
170: return result;
171: }
172:
173: /* (omit javadoc for this method)
174: * Method declared on ASTNode.
175: */
176: final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
177: // dispatch to correct overloaded match method
178: return matcher.match(this , other);
179: }
180:
181: /* (omit javadoc for this method)
182: * Method declared on ASTNode.
183: */
184: void accept0(ASTVisitor visitor) {
185: boolean visitChildren = visitor.visit(this );
186: if (visitChildren) {
187: // visit children in normal left to right reading order
188: acceptChild(visitor, getQualifier());
189: acceptChild(visitor, getName());
190: }
191: visitor.endVisit(this );
192: }
193:
194: /**
195: * Returns the qualifier of this qualified type.
196: *
197: * @return the qualifier of this qualified type
198: */
199: public Type getQualifier() {
200: if (this .qualifier == null) {
201: // lazy init must be thread-safe for readers
202: synchronized (this ) {
203: if (this .qualifier == null) {
204: preLazyInit();
205: this .qualifier = new SimpleType(this .ast);
206: postLazyInit(this .qualifier, QUALIFIER_PROPERTY);
207: }
208: }
209: }
210: return this .qualifier;
211: }
212:
213: /**
214: * Sets the qualifier of this qualified type to the given type.
215: *
216: * @param type the new qualifier of this qualified type
217: * @exception IllegalArgumentException if:
218: * <ul>
219: * <li>the node belongs to a different AST</li>
220: * <li>the node already has a parent</li>
221: * </ul>
222: */
223: public void setQualifier(Type type) {
224: if (type == null) {
225: throw new IllegalArgumentException();
226: }
227: ASTNode oldChild = this .qualifier;
228: preReplaceChild(oldChild, type, QUALIFIER_PROPERTY);
229: this .qualifier = type;
230: postReplaceChild(oldChild, type, QUALIFIER_PROPERTY);
231: }
232:
233: /**
234: * Returns the name part of this qualified type.
235: *
236: * @return the name being qualified
237: */
238: public SimpleName getName() {
239: if (this .name == null) {
240: // lazy init must be thread-safe for readers
241: synchronized (this ) {
242: if (this .name == null) {
243: preLazyInit();
244: this .name = new SimpleName(this .ast);
245: postLazyInit(this .name, NAME_PROPERTY);
246: }
247: }
248: }
249: return this .name;
250: }
251:
252: /**
253: * Sets the name part of this qualified type to the given simple name.
254: *
255: * @param name the identifier of this qualified name
256: * @exception IllegalArgumentException if:
257: * <ul>
258: * <li>the node belongs to a different AST</li>
259: * <li>the node already has a parent</li>
260: * </ul>
261: */
262: public void setName(SimpleName name) {
263: if (name == null) {
264: throw new IllegalArgumentException();
265: }
266: ASTNode oldChild = this .name;
267: preReplaceChild(oldChild, name, NAME_PROPERTY);
268: this .name = name;
269: postReplaceChild(oldChild, name, NAME_PROPERTY);
270: }
271:
272: /* (omit javadoc for this method)
273: * Method declared on ASTNode.
274: */
275: int memSize() {
276: // treat Code as free
277: return BASE_NODE_SIZE + 3 * 4;
278: }
279:
280: /* (omit javadoc for this method)
281: * Method declared on ASTNode.
282: */
283: int treeSize() {
284: return memSize()
285: + (this .qualifier == null ? 0 : getQualifier()
286: .treeSize())
287: + (this .name == null ? 0 : getName().treeSize());
288: }
289: }
|