001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.internal.compiler.lookup;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.impl.Constant;
015:
016: public final class ArrayBinding extends TypeBinding {
017: // creation and initialization of the length field
018: // the declaringClass of this field is intentionally set to null so it can be distinguished.
019: public static final FieldBinding ArrayLength = new FieldBinding(
020: TypeConstants.LENGTH, TypeBinding.INT,
021: ClassFileConstants.AccPublic | ClassFileConstants.AccFinal,
022: null, Constant.NotAConstant);
023:
024: public TypeBinding leafComponentType;
025: public int dimensions;
026: LookupEnvironment environment;
027: char[] constantPoolName;
028: char[] genericTypeSignature;
029:
030: public ArrayBinding(TypeBinding type, int dimensions,
031: LookupEnvironment environment) {
032: this .tagBits |= TagBits.IsArrayType;
033: this .leafComponentType = type;
034: this .dimensions = dimensions;
035: this .environment = environment;
036: if (type instanceof UnresolvedReferenceBinding)
037: ((UnresolvedReferenceBinding) type).addWrapper(this ,
038: environment);
039: else
040: this .tagBits |= type.tagBits
041: & (TagBits.HasTypeVariable | TagBits.HasDirectWildcard);
042: }
043:
044: /**
045: * Collect the substitutes into a map for certain type variables inside the receiver type
046: * e.g. Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> List<X>
047: * Constraints:
048: * A << F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_EXTENDS (1))
049: * A = F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_EQUAL (0))
050: * A >> F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_SUPER (2))
051: */
052: public void collectSubstitutes(Scope scope, TypeBinding actualType,
053: InferenceContext inferenceContext, int constraint) {
054:
055: if ((this .tagBits & TagBits.HasTypeVariable) == 0)
056: return;
057: if (actualType == TypeBinding.NULL)
058: return;
059:
060: switch (actualType.kind()) {
061: case Binding.ARRAY_TYPE:
062: int actualDim = actualType.dimensions();
063: if (actualDim == this .dimensions) {
064: this .leafComponentType.collectSubstitutes(scope,
065: actualType.leafComponentType(),
066: inferenceContext, constraint);
067: } else if (actualDim > this .dimensions) {
068: ArrayBinding actualReducedType = this .environment
069: .createArrayType(
070: actualType.leafComponentType(),
071: actualDim - this .dimensions);
072: this .leafComponentType
073: .collectSubstitutes(scope, actualReducedType,
074: inferenceContext, constraint);
075: }
076: break;
077: case Binding.TYPE_PARAMETER:
078: //TypeVariableBinding variable = (TypeVariableBinding) otherType;
079: // TODO (philippe) should consider array bounds, and recurse
080: break;
081: }
082: }
083:
084: /*
085: * brakets leafUniqueKey
086: * p.X[][] --> [[Lp/X;
087: */
088: public char[] computeUniqueKey(boolean isLeaf) {
089: char[] brackets = new char[dimensions];
090: for (int i = dimensions - 1; i >= 0; i--)
091: brackets[i] = '[';
092: return CharOperation.concat(brackets, this .leafComponentType
093: .computeUniqueKey(isLeaf));
094: }
095:
096: /**
097: * Answer the receiver's constant pool name.
098: * NOTE: This method should only be used during/after code gen.
099: * e.g. '[Ljava/lang/Object;'
100: */
101: public char[] constantPoolName() {
102: if (constantPoolName != null)
103: return constantPoolName;
104:
105: char[] brackets = new char[dimensions];
106: for (int i = dimensions - 1; i >= 0; i--)
107: brackets[i] = '[';
108: return constantPoolName = CharOperation.concat(brackets,
109: leafComponentType.signature());
110: }
111:
112: public String debugName() {
113: StringBuffer brackets = new StringBuffer(dimensions * 2);
114: for (int i = dimensions; --i >= 0;)
115: brackets.append("[]"); //$NON-NLS-1$
116: return leafComponentType.debugName() + brackets.toString();
117: }
118:
119: public int dimensions() {
120: return this .dimensions;
121: }
122:
123: /* Answer an array whose dimension size is one less than the receiver.
124: *
125: * When the receiver's dimension size is one then answer the leaf component type.
126: */
127:
128: public TypeBinding elementsType() {
129: if (this .dimensions == 1)
130: return this .leafComponentType;
131: return this .environment.createArrayType(this .leafComponentType,
132: this .dimensions - 1);
133: }
134:
135: /**
136: * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#erasure()
137: */
138: public TypeBinding erasure() {
139: TypeBinding erasedType = this .leafComponentType.erasure();
140: if (this .leafComponentType != erasedType)
141: return this .environment.createArrayType(erasedType,
142: this .dimensions);
143: return this ;
144: }
145:
146: public LookupEnvironment environment() {
147: return this .environment;
148: }
149:
150: public char[] genericTypeSignature() {
151:
152: if (this .genericTypeSignature == null) {
153: char[] brackets = new char[dimensions];
154: for (int i = dimensions - 1; i >= 0; i--)
155: brackets[i] = '[';
156: this .genericTypeSignature = CharOperation.concat(brackets,
157: leafComponentType.genericTypeSignature());
158: }
159: return this .genericTypeSignature;
160: }
161:
162: public PackageBinding getPackage() {
163: return leafComponentType.getPackage();
164: }
165:
166: public int hashCode() {
167: return this .leafComponentType == null ? super .hashCode()
168: : this .leafComponentType.hashCode();
169: }
170:
171: /* Answer true if the receiver type can be assigned to the argument type (right)
172: */
173: public boolean isCompatibleWith(TypeBinding otherType) {
174: if (this == otherType)
175: return true;
176:
177: switch (otherType.kind()) {
178: case Binding.ARRAY_TYPE:
179: ArrayBinding otherArray = (ArrayBinding) otherType;
180: if (otherArray.leafComponentType.isBaseType())
181: return false; // relying on the fact that all equal arrays are identical
182: if (dimensions == otherArray.dimensions)
183: return leafComponentType
184: .isCompatibleWith(otherArray.leafComponentType);
185: if (dimensions < otherArray.dimensions)
186: return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into 'Object[]'
187: break;
188: case Binding.BASE_TYPE:
189: return false;
190: case Binding.WILDCARD_TYPE:
191: return ((WildcardBinding) otherType).boundCheck(this );
192:
193: case Binding.TYPE_PARAMETER:
194: // check compatibility with capture of ? super X
195: if (otherType.isCapture()) {
196: CaptureBinding otherCapture = (CaptureBinding) otherType;
197: TypeBinding otherLowerBound;
198: if ((otherLowerBound = otherCapture.lowerBound) != null) {
199: if (!otherLowerBound.isArrayType())
200: return false;
201: return this .isCompatibleWith(otherLowerBound);
202: }
203: }
204: return false;
205:
206: }
207: //Check dimensions - Java does not support explicitly sized dimensions for types.
208: //However, if it did, the type checking support would go here.
209: switch (otherType.leafComponentType().id) {
210: case TypeIds.T_JavaLangObject:
211: case TypeIds.T_JavaLangCloneable:
212: case TypeIds.T_JavaIoSerializable:
213: return true;
214: }
215: return false;
216: }
217:
218: public int kind() {
219: return ARRAY_TYPE;
220: }
221:
222: public TypeBinding leafComponentType() {
223: return leafComponentType;
224: }
225:
226: /* API
227: * Answer the problem id associated with the receiver.
228: * NoError if the receiver is a valid binding.
229: */
230: public int problemId() {
231: return leafComponentType.problemId();
232: }
233:
234: /**
235: * Answer the source name for the type.
236: * In the case of member types, as the qualified name from its top level type.
237: * For example, for a member type N defined inside M & A: "A.M.N".
238: */
239:
240: public char[] qualifiedSourceName() {
241: char[] brackets = new char[dimensions * 2];
242: for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
243: brackets[i] = ']';
244: brackets[i - 1] = '[';
245: }
246: return CharOperation.concat(leafComponentType
247: .qualifiedSourceName(), brackets);
248: }
249:
250: public char[] readableName() /* java.lang.Object[] */{
251: char[] brackets = new char[dimensions * 2];
252: for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
253: brackets[i] = ']';
254: brackets[i - 1] = '[';
255: }
256: return CharOperation.concat(leafComponentType.readableName(),
257: brackets);
258: }
259:
260: public char[] shortReadableName() {
261: char[] brackets = new char[dimensions * 2];
262: for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
263: brackets[i] = ']';
264: brackets[i - 1] = '[';
265: }
266: return CharOperation.concat(leafComponentType
267: .shortReadableName(), brackets);
268: }
269:
270: public char[] sourceName() {
271: char[] brackets = new char[dimensions * 2];
272: for (int i = dimensions * 2 - 1; i >= 0; i -= 2) {
273: brackets[i] = ']';
274: brackets[i - 1] = '[';
275: }
276: return CharOperation.concat(leafComponentType.sourceName(),
277: brackets);
278: }
279:
280: public void swapUnresolved(
281: UnresolvedReferenceBinding unresolvedType,
282: ReferenceBinding resolvedType, LookupEnvironment env) {
283: if (this .leafComponentType == unresolvedType) {
284: this .leafComponentType = env
285: .convertUnresolvedBinaryToRawType(resolvedType);
286: this .tagBits |= this .leafComponentType.tagBits
287: & (TagBits.HasTypeVariable | TagBits.HasDirectWildcard);
288: }
289: }
290:
291: public String toString() {
292: return leafComponentType != null ? debugName()
293: : "NULL TYPE ARRAY"; //$NON-NLS-1$
294: }
295: }
|