public ArrayType createArrayType(TType elementType, int dimensions) { Assert.isTrue(!elementType.isArrayType()); Assert.isTrue(!elementType.isAnonymous()); Assert.isTrue(dimensions > 0); int index = dimensions - 1; Map arrayTypes = getArrayTypesMap(index); ArrayType result = (ArrayType) arrayTypes.get(elementType); if (result != null) return result; result = new ArrayType( this, BindingKey.createArrayTypeBindingKey(elementType.getBindingKey(), dimensions)); arrayTypes.put(elementType, result); result.initialize(elementType, dimensions); return result; }
public class TypeEnvironment { private static class ProjectKeyPair { private final IJavaScriptProject fProject; private final String fBindingKey; public ProjectKeyPair(IJavaScriptProject project, String bindingKey) { fProject = project; fBindingKey = bindingKey; } public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof ProjectKeyPair)) return false; ProjectKeyPair otherPair = (ProjectKeyPair) other; return fProject.equals(otherPair.fProject) && fBindingKey.equals(otherPair.fBindingKey); } public int hashCode() { return fProject.hashCode() + fBindingKey.hashCode(); } } /** Type code for the primitive type "int". */ public final PrimitiveType INT = new PrimitiveType( this, PrimitiveType.INT, BindingKey.createTypeBindingKey("int")); // $NON-NLS-1$ /** Type code for the primitive type "char". */ public final PrimitiveType CHAR = new PrimitiveType( this, PrimitiveType.CHAR, BindingKey.createTypeBindingKey("char")); // $NON-NLS-1$ /** Type code for the primitive type "boolean". */ public final PrimitiveType BOOLEAN = new PrimitiveType( this, PrimitiveType.BOOLEAN, BindingKey.createTypeBindingKey("boolean")); // $NON-NLS-1$ /** Type code for the primitive type "short". */ public final PrimitiveType SHORT = new PrimitiveType( this, PrimitiveType.SHORT, BindingKey.createTypeBindingKey("short")); // $NON-NLS-1$ /** Type code for the primitive type "long". */ public final PrimitiveType LONG = new PrimitiveType( this, PrimitiveType.LONG, BindingKey.createTypeBindingKey("long")); // $NON-NLS-1$ /** Type code for the primitive type "float". */ public final PrimitiveType FLOAT = new PrimitiveType( this, PrimitiveType.FLOAT, BindingKey.createTypeBindingKey("float")); // $NON-NLS-1$ /** Type code for the primitive type "double". */ public final PrimitiveType DOUBLE = new PrimitiveType( this, PrimitiveType.DOUBLE, BindingKey.createTypeBindingKey("double")); // $NON-NLS-1$ /** Type code for the primitive type "byte". */ public final PrimitiveType BYTE = new PrimitiveType( this, PrimitiveType.BYTE, BindingKey.createTypeBindingKey("byte")); // $NON-NLS-1$ /** Type code for the primitive type "null". */ public final NullType NULL = new NullType(this); public final VoidType VOID = new VoidType(this); final PrimitiveType[] PRIMITIVE_TYPES = {INT, CHAR, BOOLEAN, SHORT, LONG, FLOAT, DOUBLE, BYTE}; private static final String[] BOXED_PRIMITIVE_NAMES = new String[] { "java.lang.Integer", //$NON-NLS-1$ "java.lang.Character", //$NON-NLS-1$ "java.lang.Boolean", //$NON-NLS-1$ "java.lang.Short", //$NON-NLS-1$ "java.lang.Long", //$NON-NLS-1$ "java.lang.Float", //$NON-NLS-1$ "java.lang.Double", //$NON-NLS-1$ "java.lang.Byte" }; //$NON-NLS-1$ private TType OBJECT_TYPE = null; private Map /*<TType, ArrayType>*/[] fArrayTypes = new Map[] {new HashMap()}; private Map /*<IJavaScriptElement, StandardType>*/ fStandardTypes = new HashMap(); private Map /*<IJavaScriptElement, GenericType>*/ fGenericTypes = new HashMap(); private Map /*<ProjectKeyPair, ParameterizedType>*/ fParameterizedTypes = new HashMap(); private Map /*<IJavaScriptElement, RawType>*/ fRawTypes = new HashMap(); private Map /*<ProjectKeyPair, CaptureType>*/ fCaptureTypes = new HashMap(); private UnboundWildcardType fUnboundWildcardType = null; private static final int MAX_ENTRIES = 1024; private Map /*<TypeTuple, Boolean>*/ fSubTypeCache = new LinkedHashMap(50, 0.75f, true) { private static final long serialVersionUID = 1L; protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; } }; /** * Map from TType to its known subtypes, or <code>null</code> iff subtype information was not * requested in the constructor. */ private Map /*<TType, List<TType>>*/ fSubTypes; public static ITypeBinding[] createTypeBindings(TType[] types, IJavaScriptProject project) { final Map mapping = new HashMap(); List keys = new ArrayList(); for (int i = 0; i < types.length; i++) { TType type = types[i]; String bindingKey = type.getBindingKey(); mapping.put(bindingKey, type); keys.add(bindingKey); } ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setProject(project); parser.setResolveBindings(true); parser.createASTs( new IJavaScriptUnit[0], (String[]) keys.toArray(new String[keys.size()]), new ASTRequestor() { public void acceptBinding(String bindingKey, IBinding binding) { mapping.put(bindingKey, binding); } }, null); ITypeBinding[] result = new ITypeBinding[types.length]; for (int i = 0; i < types.length; i++) { TType type = types[i]; String bindingKey = type.getBindingKey(); Object value = mapping.get(bindingKey); if (value instanceof ITypeBinding) { result[i] = (ITypeBinding) value; } } return result; } public TypeEnvironment() { this(false); } public TypeEnvironment(boolean rememberSubtypes) { if (rememberSubtypes) { fSubTypes = new HashMap(); } } Map /*<TypeTuple, Boolean>*/ getSubTypeCache() { return fSubTypeCache; } public TType create(ITypeBinding binding) { if (binding.isPrimitive()) { return createPrimitiveType(binding); } else if (binding.isArray()) { return createArrayType(binding); } if ("null".equals(binding.getName())) // $NON-NLS-1$ return NULL; return createStandardType(binding); } public TType[] create(ITypeBinding[] bindings) { TType[] result = new TType[bindings.length]; for (int i = 0; i < bindings.length; i++) { result[i] = create(bindings[i]); } return result; } /** * Returns the TType for java.lang.Object. * * <p>Warning: currently returns <code>null</code> unless this type environment has already * created its first hierarchy type. * * @return the TType for java.lang.Object */ public TType getJavaLangObject() { return OBJECT_TYPE; } void initializeJavaLangObject(ITypeBinding object) { if (OBJECT_TYPE != null) return; TType objectType = createStandardType(object); Assert.isTrue(objectType.isJavaLangObject()); } PrimitiveType createUnBoxed(StandardType type) { String name = type.getPlainPrettySignature(); for (int i = 0; i < BOXED_PRIMITIVE_NAMES.length; i++) { if (BOXED_PRIMITIVE_NAMES[i].equals(name)) return PRIMITIVE_TYPES[i]; } return null; } StandardType createBoxed(PrimitiveType type, IJavaScriptProject focus) { String fullyQualifiedName = BOXED_PRIMITIVE_NAMES[type.getId()]; try { IType javaElementType = focus.findType(fullyQualifiedName); StandardType result = (StandardType) fStandardTypes.get(javaElementType); if (result != null) return result; ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setProject(focus); IBinding[] bindings = parser.createBindings(new IJavaScriptElement[] {javaElementType}, null); return createStandardType((ITypeBinding) bindings[0]); } catch (JavaScriptModelException e) { // fall through } return null; } Map /*<TType, List<TType>>*/ getSubTypes() { return fSubTypes; } private void cacheSubType(TType supertype, TType result) { if (fSubTypes == null) return; if (supertype == null) supertype = OBJECT_TYPE; ArrayList subtypes = (ArrayList) fSubTypes.get(supertype); if (subtypes == null) { subtypes = new ArrayList(5); fSubTypes.put(supertype, subtypes); } else { Assert.isTrue(!subtypes.contains(result)); } subtypes.add(result); } private void cacheSubTypes(TType[] interfaces, TType result) { for (int i = 0; i < interfaces.length; i++) { cacheSubType(interfaces[i], result); } } private TType createPrimitiveType(ITypeBinding binding) { String name = binding.getName(); String[] names = PrimitiveType.NAMES; for (int i = 0; i < names.length; i++) { if (name.equals(names[i])) { return PRIMITIVE_TYPES[i]; } } Assert.isTrue(false, "Primitive type " + name + "unkown"); // $NON-NLS-1$//$NON-NLS-2$ return null; } private ArrayType createArrayType(ITypeBinding binding) { int index = binding.getDimensions() - 1; TType elementType = create(binding.getElementType()); Map /*<TType, ArrayType>*/ arrayTypes = getArrayTypesMap(index); ArrayType result = (ArrayType) arrayTypes.get(elementType); if (result != null) return result; result = new ArrayType(this); arrayTypes.put(elementType, result); result.initialize(binding, elementType); return result; } public ArrayType createArrayType(TType elementType, int dimensions) { Assert.isTrue(!elementType.isArrayType()); Assert.isTrue(!elementType.isAnonymous()); Assert.isTrue(dimensions > 0); int index = dimensions - 1; Map arrayTypes = getArrayTypesMap(index); ArrayType result = (ArrayType) arrayTypes.get(elementType); if (result != null) return result; result = new ArrayType( this, BindingKey.createArrayTypeBindingKey(elementType.getBindingKey(), dimensions)); arrayTypes.put(elementType, result); result.initialize(elementType, dimensions); return result; } private Map /*<TType, ArrayType>*/ getArrayTypesMap(int index) { int oldLength = fArrayTypes.length; if (index >= oldLength) { Map[] newArray = new Map[index + 1]; System.arraycopy(fArrayTypes, 0, newArray, 0, oldLength); fArrayTypes = newArray; } Map arrayTypes = fArrayTypes[index]; if (arrayTypes == null) { arrayTypes = new HashMap(); fArrayTypes[index] = arrayTypes; } return arrayTypes; } private StandardType createStandardType(ITypeBinding binding) { IJavaScriptElement javaElement = binding.getJavaElement(); StandardType result = (StandardType) fStandardTypes.get(javaElement); if (result != null) return result; result = new StandardType(this); fStandardTypes.put(javaElement, result); result.initialize(binding, (IType) javaElement); if (OBJECT_TYPE == null && result.isJavaLangObject()) OBJECT_TYPE = result; return result; } private GenericType createGenericType(ITypeBinding binding) { IJavaScriptElement javaElement = binding.getJavaElement(); GenericType result = (GenericType) fGenericTypes.get(javaElement); if (result != null) return result; result = new GenericType(this); fGenericTypes.put(javaElement, result); result.initialize(binding, (IType) javaElement); cacheSubType(result.getSuperclass(), result); cacheSubTypes(result.getInterfaces(), result); return result; } private RawType createRawType(ITypeBinding binding) { IJavaScriptElement javaElement = binding.getJavaElement(); RawType result = (RawType) fRawTypes.get(javaElement); if (result != null) return result; result = new RawType(this); fRawTypes.put(javaElement, result); result.initialize(binding, (IType) javaElement); cacheSubType(result.getSuperclass(), result); cacheSubTypes(result.getInterfaces(), result); return result; } private TType createUnboundWildcardType(ITypeBinding binding) { if (fUnboundWildcardType == null) { fUnboundWildcardType = new UnboundWildcardType(this); fUnboundWildcardType.initialize(binding); } return fUnboundWildcardType; } private CaptureType createCaptureType(ITypeBinding binding) { IJavaScriptProject javaProject = binding.getDeclaringClass().getJavaElement().getJavaScriptProject(); String bindingKey = binding.getKey(); ProjectKeyPair pair = new ProjectKeyPair(javaProject, bindingKey); CaptureType result = (CaptureType) fCaptureTypes.get(pair); if (result != null) return result; result = new CaptureType(this); fCaptureTypes.put(pair, result); result.initialize(binding, javaProject); return result; } }