/******************************************************************************* | |
* Copyright (c) 2000, 2004 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.wst.jsdt.internal.compiler.lookup; | |
import java.util.Map; | |
import org.eclipse.wst.jsdt.core.compiler.CharOperation; | |
import org.eclipse.wst.jsdt.internal.compiler.impl.Constant; | |
public final class ArrayBinding extends TypeBinding { | |
// creation and initialization of the length field | |
// the declaringClass of this field is intentionally set to null so it can be distinguished. | |
public static final FieldBinding ArrayLength = new FieldBinding(LENGTH, IntBinding, AccPublic | AccFinal, null, Constant.NotAConstant); | |
public TypeBinding leafComponentType; | |
public int dimensions; | |
LookupEnvironment environment; | |
char[] constantPoolName; | |
char[] genericTypeSignature; | |
public ArrayBinding(TypeBinding type, int dimensions, LookupEnvironment environment) { | |
this.tagBits |= IsArrayType; | |
this.leafComponentType = type; | |
this.dimensions = dimensions; | |
this.environment = environment; | |
if (type instanceof UnresolvedReferenceBinding) | |
((UnresolvedReferenceBinding) type).addWrapper(this); | |
else | |
this.tagBits |= type.tagBits & (HasTypeVariable | HasWildcard); | |
} | |
/** | |
* Collect the substitutes into a map for certain type variables inside the receiver type | |
* e.g. Collection<T>.findSubstitute(T, Collection<List<X>>): T --> List<X> | |
*/ | |
public void collectSubstitutes(TypeBinding otherType, Map substitutes) { | |
if (otherType.isArrayType()) { | |
int otherDim = otherType.dimensions(); | |
if (otherDim == this.dimensions) { | |
this.leafComponentType.collectSubstitutes(otherType.leafComponentType(), substitutes); | |
} else if (otherDim > this.dimensions) { | |
ArrayBinding otherReducedType = this.environment.createArrayType(otherType.leafComponentType(), otherDim - this.dimensions); | |
this.leafComponentType.collectSubstitutes(otherReducedType, substitutes); | |
} | |
} | |
} | |
/** | |
* Answer the receiver's constant pool name. | |
* NOTE: This method should only be used during/after code gen. | |
* e.g. '[Ljava/lang/Object;' | |
*/ | |
public char[] constantPoolName() { | |
if (constantPoolName != null) | |
return constantPoolName; | |
char[] brackets = new char[dimensions]; | |
for (int i = dimensions - 1; i >= 0; i--) brackets[i] = '['; | |
return constantPoolName = CharOperation.concat(brackets, leafComponentType.signature()); | |
} | |
public String debugName() { | |
StringBuffer brackets = new StringBuffer(dimensions * 2); | |
for (int i = dimensions; --i >= 0;) | |
brackets.append("[]"); //$NON-NLS-1$ | |
return leafComponentType.debugName() + brackets.toString(); | |
} | |
public int dimensions() { | |
return this.dimensions; | |
} | |
/* Answer an array whose dimension size is one less than the receiver. | |
* | |
* When the receiver's dimension size is one then answer the leaf component type. | |
*/ | |
public TypeBinding elementsType() { | |
if (this.dimensions == 1) return this.leafComponentType; | |
return this.environment.createArrayType(this.leafComponentType, this.dimensions - 1); | |
} | |
/** | |
* @see org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding#erasure() | |
*/ | |
public TypeBinding erasure() { | |
TypeBinding erasedType = this.leafComponentType.erasure(); | |
if (this.leafComponentType != erasedType) | |
return this.environment.createArrayType(erasedType, this.dimensions); | |
return this; | |
} | |
public LookupEnvironment environment() { | |
return this.environment; | |
} | |
public char[] genericTypeSignature() { | |
if (this.genericTypeSignature == null) { | |
char[] brackets = new char[dimensions]; | |
for (int i = dimensions - 1; i >= 0; i--) brackets[i] = '['; | |
this.genericTypeSignature = CharOperation.concat(brackets, leafComponentType.genericTypeSignature()); | |
} | |
return this.genericTypeSignature; | |
} | |
public PackageBinding getPackage() { | |
return leafComponentType.getPackage(); | |
} | |
public int hashCode() { | |
return this.leafComponentType == null ? super.hashCode() : this.leafComponentType.hashCode(); | |
} | |
/* Answer true if the receiver type can be assigned to the argument type (right) | |
*/ | |
public boolean isCompatibleWith(TypeBinding right) { | |
if (this == right) | |
return true; | |
if (right.isArrayType()) { | |
ArrayBinding rightArray = (ArrayBinding) right; | |
if (rightArray.leafComponentType.isBaseType()) | |
return false; // relying on the fact that all equal arrays are identical | |
if (dimensions == rightArray.dimensions) | |
return leafComponentType.isCompatibleWith(rightArray.leafComponentType); | |
if (dimensions < rightArray.dimensions) | |
return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into 'Object[]' | |
} else { | |
if (right.isBaseType()) | |
return false; | |
if (right.isWildcard()) { | |
return ((WildcardBinding) right).boundCheck(this); | |
} | |
} | |
//Check dimensions - Java does not support explicitly sized dimensions for types. | |
//However, if it did, the type checking support would go here. | |
switch (right.leafComponentType().id) { | |
case T_JavaLangObject : | |
case T_JavaLangCloneable : | |
case T_JavaIoSerializable : | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Returns true if a type is identical to another one, | |
* or for generic types, true if compared to its raw type. | |
*/ | |
public boolean isEquivalentTo(TypeBinding otherType) { | |
if (this == otherType) return true; | |
if (otherType == null) return false; | |
if (otherType.isWildcard()) // wildcard | |
return ((WildcardBinding) otherType).boundCheck(this); | |
return false; | |
} | |
public TypeBinding leafComponentType(){ | |
return leafComponentType; | |
} | |
/* API | |
* Answer the problem id associated with the receiver. | |
* NoError if the receiver is a valid binding. | |
*/ | |
public int problemId() { | |
return leafComponentType.problemId(); | |
} | |
/** | |
* Answer the source name for the type. | |
* In the case of member types, as the qualified name from its top level type. | |
* For example, for a member type N defined inside M & A: "A.M.N". | |
*/ | |
public char[] qualifiedSourceName() { | |
char[] brackets = new char[dimensions * 2]; | |
for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { | |
brackets[i] = ']'; | |
brackets[i - 1] = '['; | |
} | |
return CharOperation.concat(leafComponentType.qualifiedSourceName(), brackets); | |
} | |
public char[] readableName() /* java.lang.Object[] */ { | |
char[] brackets = new char[dimensions * 2]; | |
for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { | |
brackets[i] = ']'; | |
brackets[i - 1] = '['; | |
} | |
return CharOperation.concat(leafComponentType.readableName(), brackets); | |
} | |
public char[] shortReadableName(){ | |
char[] brackets = new char[dimensions * 2]; | |
for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { | |
brackets[i] = ']'; | |
brackets[i - 1] = '['; | |
} | |
return CharOperation.concat(leafComponentType.shortReadableName(), brackets); | |
} | |
public char[] sourceName() { | |
char[] brackets = new char[dimensions * 2]; | |
for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { | |
brackets[i] = ']'; | |
brackets[i - 1] = '['; | |
} | |
return CharOperation.concat(leafComponentType.sourceName(), brackets); | |
} | |
public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment env) { | |
if (this.leafComponentType == unresolvedType) { | |
this.leafComponentType = resolvedType.isGenericType() ? env.createRawType(resolvedType, null) : resolvedType; | |
this.tagBits |= this.leafComponentType.tagBits & (HasTypeVariable | HasWildcard); | |
} | |
} | |
public String toString() { | |
return leafComponentType != null ? debugName() : "NULL TYPE ARRAY"; //$NON-NLS-1$ | |
} | |
} |