blob: cab38e1009ad16c9aff034f96d7a11f354cf61a1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 NumberFour AG
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* NumberFour AG - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.javascript.typeinfo;
import static org.eclipse.dltk.javascript.typeinfo.model.TypeInfoModelFactory.eINSTANCE;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.dltk.annotations.NonNull;
import org.eclipse.dltk.annotations.Nullable;
import org.eclipse.dltk.internal.javascript.ti.TypeInferencerVisitor;
import org.eclipse.dltk.javascript.core.Types;
import org.eclipse.dltk.javascript.typeinfo.model.ArrayType;
import org.eclipse.dltk.javascript.typeinfo.model.ClassType;
import org.eclipse.dltk.javascript.typeinfo.model.Constructor;
import org.eclipse.dltk.javascript.typeinfo.model.JSType;
import org.eclipse.dltk.javascript.typeinfo.model.MapType;
import org.eclipse.dltk.javascript.typeinfo.model.Member;
import org.eclipse.dltk.javascript.typeinfo.model.ParameterizedType;
import org.eclipse.dltk.javascript.typeinfo.model.RType;
import org.eclipse.dltk.javascript.typeinfo.model.RecordType;
import org.eclipse.dltk.javascript.typeinfo.model.SimpleType;
import org.eclipse.dltk.javascript.typeinfo.model.Type;
import org.eclipse.dltk.javascript.typeinfo.model.TypeInfoModelLoader;
import org.eclipse.dltk.javascript.typeinfo.model.TypeKind;
import org.eclipse.dltk.javascript.typeinfo.model.TypeVariable;
import org.eclipse.dltk.javascript.typeinfo.model.TypeVariableReference;
import org.eclipse.dltk.javascript.typeinfo.model.UndefinedType;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
public class TypeUtil {
@Nullable
public static SimpleType ref(@Nullable Type type) {
if (type == null) {
return null;
}
final SimpleType ref = eINSTANCE.createSimpleType();
ref.setTarget(type);
return ref;
}
@Nullable
public static ClassType classType(@Nullable Type type) {
if (type == null) {
return null;
}
final ClassType ref = eINSTANCE.createClassType();
ref.setTarget(type);
return ref;
}
public static JSType ref(String typeName) {
return ref(type(typeName));
}
public static Type type(String typeName) {
final Type type = TypeInfoModelLoader.getInstance().getType(typeName);
if (type != null) {
return type;
}
return createProxy(typeName);
}
public static ArrayType arrayOf(String itemType) {
return arrayOf(ref(itemType));
}
public static ArrayType arrayOf(JSType itemType) {
final ArrayType arrayType = eINSTANCE.createArrayType();
arrayType.setItemType(itemType != null ? itemType : ref(Types.OBJECT));
return arrayType;
}
public static MapType mapOf(String keyType, String valueType) {
return mapOf(keyType != null ? ref(keyType) : null, ref(valueType));
}
public static MapType mapOf(JSType keyType, JSType valueType) {
final MapType mapType = eINSTANCE.createMapType();
mapType.setKeyType(keyType != null ? keyType : ref(Types.STRING));
mapType.setValueType(valueType != null ? valueType : ref(Types.OBJECT));
return mapType;
}
/**
* @deprecated Use {@link #parameterizedType(String,JSType...)} instead
*/
public static ParameterizedType genericType(String baseType,
JSType... typeParameters) {
return parameterizedType(type(baseType), typeParameters);
}
public static ParameterizedType parameterizedType(Type targetType,
JSType... typeParameters) {
final ParameterizedType genericType = eINSTANCE
.createParameterizedType();
genericType.setTarget(targetType);
for (JSType typeParameter : typeParameters) {
genericType.getActualTypeArguments().add(typeParameter);
}
return genericType;
}
public static IRType extractArrayItemType(IRType type) {
if (type instanceof IRArrayType) {
return ((IRArrayType) type).getItemType();
} else if (type instanceof IRMapType) {
return ((IRMapType) type).getValueType();
} else if (type != null && type.getName().equals(ITypeNames.XML)) {
return type;
} else if (type != null && type.getName().equals(ITypeNames.XMLLIST)) {
return E4XTypes.XML;
} else {
return null;
}
}
public static String getName(JSType type) {
return type != null ? type.getName() : null;
}
public static String getName(IRType type) {
return type != null ? type.getName() : null;
}
public static String getName(Type type) {
if (type.isProxy()) {
return URI.decode(((InternalEObject) type).eProxyURI().fragment());
} else {
return type.getName();
}
}
private static final String PROXY_SCHEME = "proxy";
private static final String PROXY_OPAQUE_PART = "dltk/javascript/typeinfo/type";
/**
* @param typeName
* @return
*/
public static Type createProxy(String typeName) {
return createProxy(createProxyURI(typeName));
}
public static Type createProxy(URI uri) {
final Type type = eINSTANCE.createType();
type.setName(uri.fragment());
((InternalEObject) type).eSetProxyURI(uri);
return type;
}
public static URI createProxyURI(String typeName) {
if (typeName == null)
throw new NullPointerException("Type name is null");
return URI.createGenericURI(PROXY_SCHEME, PROXY_OPAQUE_PART,
URI.encodeFragment(typeName, false));
}
/**
* @param type
* @return
*/
public static Type createProxy(Type type) {
final Type result = eINSTANCE.createType();
if (type.isProxy()) {
((InternalEObject) result).eSetProxyURI(((InternalEObject) type)
.eProxyURI());
} else {
final String typeName = type.getName();
result.setName(typeName);
((InternalEObject) result).eSetProxyURI(createProxyURI(typeName));
}
return result;
}
public static boolean isTypeProxy(URI uri) {
return PROXY_SCHEME.equals(uri.scheme())
&& PROXY_OPAQUE_PART.equals(uri.opaquePart());
}
public static URI createProxyResourceURI() {
return URI.createGenericURI(PROXY_SCHEME, PROXY_OPAQUE_PART, null);
}
public static EObject resolve(InternalEObject proxy, EObject objectContext) {
if (proxy.eIsProxy()) {
final Resource resource = objectContext.eResource();
if (resource != null) {
final ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet instanceof TypeInfoResourceSet) {
return ((TypeInfoResourceSet) resourceSet).resolve(proxy,
objectContext, resource);
}
}
return EcoreUtil.resolve(proxy, objectContext);
} else {
return proxy;
}
}
/**
* Tests if the declaring type of the specified member should be displayed
* in completion, etc.
*
* @param member
* @return
*/
public static boolean isDeclaringTypeVisible(Member member) {
return member.getDeclaringType() != null
&& !(((EObject) member.getDeclaringType()).eContainer() instanceof RecordType);
}
/**
* Tests if the specified type expression should be displayed in completion,
* etc.
*
* @param type
* @return
*/
public static boolean isValueTypeVisible(JSType type) {
if (type == null) {
return false;
} else if (type instanceof UndefinedType) {
return false;
} else if (type instanceof RecordType) {
return false;
} else {
return true;
}
}
/**
* Return {@link TypeKind} of the simple type in the specified runtime type
* or <code>null</code>.
*
* @param type
* @return
*/
public static TypeKind kind(IRType type) {
if (type != null) {
if (type instanceof IRSimpleType) {
final Type t = ((IRSimpleType) type).getTarget();
if (t != null) {
return t.getKind();
}
} else if (type instanceof IRClassType) {
final Type t = ((IRClassType) type).getTarget();
if (t != null) {
return t.getKind();
}
}
}
return null;
}
public static List<Constructor> findConstructors(Type type) {
final Set<Type> types = new HashSet<Type>();
while (types.add(type)) {
final List<Constructor> constructors = type.getConstructors();
if (!constructors.isEmpty()) {
return constructors;
}
if (!type.isInheritConstructors()) {
break;
}
type = type.getSuperType();
if (type == null) {
break;
}
}
return Collections.emptyList();
}
public static List<IRConstructor> findConstructors(IRTypeDeclaration type) {
final Set<IRTypeDeclaration> types = new HashSet<IRTypeDeclaration>();
while (types.add(type)) {
final List<IRConstructor> constructors = type.getConstructors();
if (!constructors.isEmpty()) {
return constructors;
}
if (!type.getSource().isInheritConstructors()) {
break;
}
type = type.getSuperType();
if (type == null) {
break;
}
}
return Collections.emptyList();
}
/**
* Creates EMF-based type expression, equivalent to the specified
* {@link IRType}.
*
* @param type
* nullable
* @return
*/
@Deprecated
public static JSType createRType(IRType type) {
if (type == null) {
return null;
}
final RType result = eINSTANCE.createRType();
result.setRuntimeType(type);
return result;
}
/**
* Creates {@link TypeVariableReference} referencing the specified
* {@link TypeVariable}.
*/
@NonNull
public static TypeVariableReference reference(@NonNull TypeVariable variable) {
final TypeVariableReference reference = eINSTANCE
.createTypeVariableReference();
reference.setVariable(variable);
return reference;
}
/**
* Checks if the specified type expression contains type variables.
*/
public static boolean containsTypeVariables(JSType type) {
if (type != null) {
final Boolean result = TypeInferencerVisitor.GENERIC_TYPE_EXPRESSION
.doSwitch(type);
return result != null && result.booleanValue();
}
return false;
}
}