/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.jsdt.internal.compiler.lookup; import org.eclipse.wst.jsdt.core.compiler.CharOperation; /* * Not all fields defined by this type (& its subclasses) are initialized when it is created. * Some are initialized only when needed. * * Accessors have been provided for some public fields so all TypeBindings have the same API... * but access public fields directly whenever possible. * Non-public fields have accessors which should be used everywhere you expect the field to be initialized. * * null is NOT a valid value for a non-public field... it just means the field is not initialized. */ abstract public class TypeBinding extends Binding { public int id = TypeIds.NoId; public long tagBits = 0; // See values in the interface TagBits below /** Base type definitions */ public final static BaseTypeBinding INT = new BaseTypeBinding( TypeIds.T_int, TypeConstants.INT, new char[] { 'I' }); public final static BaseTypeBinding SHORT = new BaseTypeBinding( TypeIds.T_short, TypeConstants.SHORT, new char[] { 'S' }); public final static BaseTypeBinding CHAR = new BaseTypeBinding( TypeIds.T_char, TypeConstants.CHAR, new char[] { 'C' }); public final static BaseTypeBinding LONG = new BaseTypeBinding( TypeIds.T_long, TypeConstants.LONG, new char[] { 'J' }); public final static BaseTypeBinding FLOAT = new BaseTypeBinding( TypeIds.T_float, TypeConstants.FLOAT, new char[] { 'F' }); public final static BaseTypeBinding DOUBLE = new BaseTypeBinding( TypeIds.T_double, TypeConstants.DOUBLE, new char[] { 'D' }); public final static BaseTypeBinding BOOLEAN = new BaseTypeBinding( TypeIds.T_boolean, TypeConstants.BOOLEAN, new char[] { 'Z' }); public final static BaseTypeBinding NULL = new BaseTypeBinding( TypeIds.T_null, TypeConstants.NULL, new char[] { 'N' }); // N stands // for // null // even // if it // is // never // internally // used public final static BaseTypeBinding VOID = new BaseTypeBinding( TypeIds.T_void, TypeConstants.VOID, new char[] { 'V' }); public final static BaseTypeBinding UNDEFINED = new BaseTypeBinding( TypeIds.T_undefined, TypeConstants.UNDEFINED, new char[] { 'U' }); // N // stands // for // null // even // if // it // is // never // internally // used public final static BaseTypeBinding ANY = new BaseTypeBinding( TypeIds.T_any, TypeConstants.ANY, new char[] { 'A' }); public final static BaseTypeBinding UNKNOWN = new BaseTypeBinding( TypeIds.T_any, TypeConstants.ANY, new char[] { 'A' }); /** * Match a well-known type id to its binding */ public static final TypeBinding wellKnownType(Scope scope, int id) { switch (id) { case TypeIds.T_boolean: return TypeBinding.BOOLEAN; case TypeIds.T_char: return TypeBinding.CHAR; case TypeIds.T_short: return TypeBinding.SHORT; case TypeIds.T_double: return TypeBinding.DOUBLE; case TypeIds.T_float: return TypeBinding.FLOAT; case TypeIds.T_int: return TypeBinding.INT; case TypeIds.T_long: return TypeBinding.LONG; case TypeIds.T_JavaLangObject: return scope.getJavaLangObject(); case TypeIds.T_JavaLangString: return scope.getJavaLangString(); default: return null; } } /* * Answer true if the receiver can be instantiated */ public boolean canBeInstantiated() { return !isBaseType(); } /** * Answer the receiver's constant pool name. NOTE: This method should only * be used during/after code gen. e.g. 'java/lang/Object' */ public abstract char[] constantPoolName(); public String debugName() { return new String(readableName()); } /* * Answer the receiver's dimensions - 0 for non-array types */ public int dimensions() { return 0; } /* * Answer the receiver's enclosing type... null if the receiver is a top * level type. */ public ReferenceBinding enclosingType() { return null; } /** * Find supertype which erases to a given well-known type, or null if not * found (using id avoids triggering the load of well-known type: 73740) * NOTE: only works for erasures of well-known types, as random other types * may share same id though being distincts. * */ public ReferenceBinding findSuperTypeErasingTo(int wellKnownErasureID, boolean erasureIsClass) { if (!(this instanceof ReferenceBinding)) return null; ReferenceBinding reference = (ReferenceBinding) this; // do not allow type variables to match with erasures for free if (reference.id == wellKnownErasureID || (this.id == wellKnownErasureID)) return reference; ReferenceBinding currentType = reference; // iterate superclass to avoid recording interfaces if searched // supertype is class if (erasureIsClass) { while ((currentType = currentType.superclass()) != null) { if (currentType.id == wellKnownErasureID || (currentType.id == wellKnownErasureID)) return currentType; } return null; } // ReferenceBinding[] interfacesToVisit = null; // int nextPosition = 0; // do { // } while ((currentType = currentType.superclass()) != null); // // for (int i = 0; i < nextPosition; i++) { // currentType = interfacesToVisit[i]; // if (currentType.id == wellKnownErasureID // || (currentType.id == wellKnownErasureID)) // return currentType; // } return null; } /** * Find supertype which erases to a given type, or null if not found */ public TypeBinding findSuperTypeWithSameErasure(TypeBinding otherType) { if (this == otherType) return this; if (otherType == null) return null; switch (kind()) { case Binding.ARRAY_TYPE: ArrayBinding arrayType = (ArrayBinding) this; int otherDim = otherType.dimensions(); if (arrayType.dimensions != otherDim) { switch (otherType.id) { case TypeIds.T_JavaLangObject: return otherType; } if (otherDim < arrayType.dimensions && otherType.leafComponentType().id == TypeIds.T_JavaLangObject) { return otherType; // X[][] has Object[] as an implicit // supertype } return null; } if (!(arrayType.leafComponentType instanceof ReferenceBinding)) return null; TypeBinding leafSuperType = arrayType.leafComponentType .findSuperTypeWithSameErasure(otherType.leafComponentType()); if (leafSuperType == null) return null; return arrayType.environment().createArrayType(leafSuperType, arrayType.dimensions); case Binding.TYPE: if (this == otherType || (this == otherType)) return this; ReferenceBinding currentType = (ReferenceBinding) this; while ((currentType = currentType.superclass()) != null) { if (currentType == otherType || (currentType == otherType)) return currentType; } return null; } return null; } /** * Returns the type to use for generic cast, or null if none required */ public TypeBinding genericCast(TypeBinding otherType) { if (this == otherType) return null; return otherType; } public abstract PackageBinding getPackage(); public final boolean isAnonymousType() { return (this.tagBits & TagBits.IsAnonymousType) != 0; } public final boolean isObjectLiteralType() { return (this.tagBits & TagBits.IsObjectLiteralType) != 0; } /* * Answer true if the receiver is an array */ public final boolean isArrayType() { return (this.tagBits & TagBits.IsArrayType) != 0; } /* * Answer true if the receiver is a base type */ public final boolean isBaseType() { return (this.tagBits & TagBits.IsBaseType) != 0; } public boolean isBasicType() { if ((this.tagBits & TagBits.IsBaseType) != 0) return true; return id <= TypeIds.T_last_basic; } public boolean isClass() { return false; } /* * Answer true if the receiver type can be assigned to the argument type * (right) */ public abstract boolean isCompatibleWith(TypeBinding right); /** * 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; return false; } /* * Answer true if the receiver's hierarchy has problems (always false for * arrays & base types) */ public final boolean isHierarchyInconsistent() { return (this.tagBits & TagBits.HierarchyHasProblems) != 0; } /** * Returns true if a type is intersecting with another one, */ public boolean isIntersectingWith(TypeBinding otherType) { return this == otherType; } public final boolean isLocalType() { return (this.tagBits & TagBits.IsLocalType) != 0; } public final boolean isMemberType() { return (this.tagBits & TagBits.IsMemberType) != 0; } public final boolean isNestedType() { return (this.tagBits & TagBits.IsNestedType) != 0; } public final boolean isAnyType() { return id == TypeIds.T_any; } public final boolean isNumericType() { switch (id) { case TypeIds.T_int: case TypeIds.T_float: case TypeIds.T_double: case TypeIds.T_short: case TypeIds.T_long: case TypeIds.T_char: return true; default: return false; } } /** * Returns true if the two types are statically known to be different at * compile-time, e.g. a type variable is not provably known to be distinct * from another type */ public boolean isProvablyDistinctFrom(TypeBinding otherType, int depth) { if (this == otherType) return false; if (depth > 1) return true; return this != otherType; } /** * JLS(3) 4.7. Note: Foo<?>.Bar is also reifiable */ public boolean isReifiable() { TypeBinding leafType = leafComponentType(); if (!(leafType instanceof ReferenceBinding)) return true; ReferenceBinding current = (ReferenceBinding) leafType; do { if (current.isStatic()) return true; if (current.isLocalType()) { // NestedTypeBinding nestedType = (NestedTypeBinding) // current.erasure(); // if (nestedType.scope.methodScope().isStatic) return true; return true; } } while ((current = current.enclosingType()) != null); return true; } /** * Returns true if a given type may be thrown */ public boolean isThrowable() { return false; } // JLS3: 4.5.1.1 public boolean isTypeArgumentContainedBy(TypeBinding otherType) { if (this == otherType) return true; return false; } /** * Returns true if the type is a subclass of java.lang.Error or * java.lang.RuntimeException */ public boolean isUncheckedException(boolean includeSupertype) { return false; } /* * API Answer the receiver's binding type from Binding.BindingID. */ public int kind() { return Binding.TYPE; } public TypeBinding leafComponentType() { return this; } /** * Meant to be invoked on compatible types, to figure if unchecked * conversion is necessary */ public boolean needsUncheckedConversion(TypeBinding targetType) { if (this == targetType) return false; targetType = targetType.leafComponentType(); if (!(targetType instanceof ReferenceBinding)) return false; TypeBinding currentType = this.leafComponentType(); TypeBinding match = currentType .findSuperTypeWithSameErasure(targetType); if (!(match instanceof ReferenceBinding)) return false; return false; } /** * Answer the qualified name of the receiver's package separated by periods * or an empty string if its the default package. * * For example, {java.util}. */ public char[] qualifiedPackageName() { PackageBinding packageBinding = getPackage(); return packageBinding == null || packageBinding.compoundName == CharOperation.NO_CHAR_CHAR ? CharOperation.NO_CHAR : packageBinding.readableName(); } /** * 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 abstract char[] qualifiedSourceName(); /** * Answer the receiver classfile signature. Arrays & base types do not * distinguish between signature() & constantPoolName(). NOTE: This method * should only be used during/after code gen. */ public char[] signature() { return constantPoolName(); } public abstract char[] sourceName(); public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment environment) { // subclasses must override if they wrap another type binding } public boolean isFunctionType() { return false; } public char[] getFileName() { return new char[] {}; } /** * Compare two type bindings. If all members of the other bindngs are a * member of this type, return this type. * * @param other * @return */ public TypeBinding reconcileAnonymous(TypeBinding other) { return null; } }