blob: 15752be3dc88a9edc0cddc4998dc863578337504 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 xored software, Inc.
*
* 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:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.internal.javascript.ti;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.eclipse.core.runtime.Assert;
import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.javascript.ast.Script;
import org.eclipse.dltk.javascript.core.JavaScriptPlugin;
import org.eclipse.dltk.javascript.parser.JSProblem;
import org.eclipse.dltk.javascript.parser.JSProblemReporter;
import org.eclipse.dltk.javascript.typeinference.IValueCollection;
import org.eclipse.dltk.javascript.typeinference.IValueReference;
import org.eclipse.dltk.javascript.typeinference.ReferenceKind;
import org.eclipse.dltk.javascript.typeinfo.AttributeKey;
import org.eclipse.dltk.javascript.typeinfo.IElementResolver;
import org.eclipse.dltk.javascript.typeinfo.IMemberEvaluator;
import org.eclipse.dltk.javascript.typeinfo.IModelBuilder;
import org.eclipse.dltk.javascript.typeinfo.IRSimpleType;
import org.eclipse.dltk.javascript.typeinfo.IRType;
import org.eclipse.dltk.javascript.typeinfo.ITypeInfoContext;
import org.eclipse.dltk.javascript.typeinfo.ITypeProvider;
import org.eclipse.dltk.javascript.typeinfo.ITypeSystem;
import org.eclipse.dltk.javascript.typeinfo.JSTypeSet;
import org.eclipse.dltk.javascript.typeinfo.OriginReference;
import org.eclipse.dltk.javascript.typeinfo.ReferenceSource;
import org.eclipse.dltk.javascript.typeinfo.TypeInfoManager;
import org.eclipse.dltk.javascript.typeinfo.TypeMode;
import org.eclipse.dltk.javascript.typeinfo.TypeUtil;
import org.eclipse.dltk.javascript.typeinfo.model.GenericType;
import org.eclipse.dltk.javascript.typeinfo.model.Member;
import org.eclipse.dltk.javascript.typeinfo.model.Property;
import org.eclipse.dltk.javascript.typeinfo.model.RType;
import org.eclipse.dltk.javascript.typeinfo.model.SimpleType;
import org.eclipse.dltk.javascript.typeinfo.model.Type;
import org.eclipse.dltk.javascript.typeinfo.model.TypeInfoModelFactory;
import org.eclipse.dltk.javascript.typeinfo.model.TypeInfoModelLoader;
import org.eclipse.dltk.javascript.typeinfo.model.TypeInfoModelPackage;
import org.eclipse.dltk.javascript.typeinfo.model.TypeKind;
import org.eclipse.dltk.javascript.typeinfo.model.TypeVariable;
import org.eclipse.dltk.javascript.typeinfo.model.TypeVariableClassType;
import org.eclipse.dltk.javascript.typeinfo.model.TypeVariableReference;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
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.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
public class TypeInferencer2 implements ITypeInferenceContext {
private TypeInferencerVisitor visitor;
private ReferenceSource source;
private void initializeVisitor() {
if (visitor == null) {
visitor = new TypeInferencerVisitor(this);
}
visitor.initialize();
}
public void setVisitor(TypeInferencerVisitor visitor) {
this.visitor = visitor;
}
public void setModelElement(IModelElement modelElement) {
setSource(new ReferenceSource(modelElement));
}
public void setSource(ReferenceSource source) {
this.source = source;
}
private static final boolean DEBUG = false;
public void doInferencing(Script script) {
if (DEBUG)
System.out.println("Visiting "
+ source
+ " with "
+ (visitor != null ? visitor.getClass().getName()
: "Default") + " in "
+ Thread.currentThread().getName());
final TypeInferencer2 saved = CURRENT.get();
try {
CURRENT.set(this);
elements.clear();
modelBuilders = null;
typeProviders = null;
initializeVisitor();
visitor.visit(script);
visitor.done();
// IValueCollection collection = visitor.getCollection();
// visitor = null;
// return collection;
} catch (PositionReachedException e) {
// visitor = null;
throw e;
} catch (RuntimeException e) {
log(e);
} catch (AssertionError e) {
log(e);
} finally {
CURRENT.set(saved);
}
// return null;
}
protected void log(Throwable e) {
final JSProblemReporter reporter = visitor.getProblemReporter();
if (reporter != null) {
reporter.reportProblem(new JSProblem(e));
}
JavaScriptPlugin.error(e);
}
public IValueReference evaluate(ASTNode node) {
initializeVisitor();
return visitor.visit(node);
}
public IValueCollection getCollection() {
return visitor.getCollection();
}
public IValueCollection currentCollection() {
return visitor.peekContext();
}
private final Map<String, Type> types = new ConcurrentHashMap<String, Type>();
public Type getType(String typeName) {
if (typeName == null || typeName.length() == 0) {
return null;
}
final boolean queryProviders = canQueryTypeProviders();
return getType(typeName, null, queryProviders, true, !queryProviders,
true);
}
public SimpleType getTypeRef(String typeName) {
return TypeUtil.ref(getType(typeName));
}
public Type getKnownType(String typeName, TypeMode mode) {
if (typeName == null || typeName.length() == 0) {
return null;
}
final boolean queryProviders = canQueryTypeProviders();
return getType(typeName, mode, queryProviders, true, !queryProviders,
false);
}
public Type resolveType(Type type) {
if (type != null && type.isProxy()) {
return doResolveType(type);
} else {
return type;
}
}
protected Type doResolveType(Type type) {
final String typeName = URI.decode(((InternalEObject) type).eProxyURI()
.fragment());
final Type resolved = getType(typeName, null, true, true, false, true);
if (resolved != null) {
return resolved;
}
return type;
}
private String buildParameterizedTypeName(final GenericType genericType,
List<IRType> parameters) {
final StringBuilder parameterizedName = new StringBuilder();
parameterizedName.append(genericType.getName());
parameterizedName.append("<");
for (int i = 0; i < genericType.getTypeParameters().size(); ++i) {
if (i > 0) {
parameterizedName.append(",");
}
if (i < parameters.size()) {
parameterizedName.append(parameters.get(i).getName());
} else {
parameterizedName.append("*");
}
}
parameterizedName.append(">");
final String name = parameterizedName.toString();
return name;
}
public Type parameterize(Type target, List<IRType> parameters) {
target = resolveType(target);
if (target instanceof GenericType) {
final GenericType genericType = (GenericType) target;
final String name = buildParameterizedTypeName(genericType,
parameters);
Type type = types.get(name);
if (type != null) {
if (DEBUG) {
System.out.println("Returning " + name);
}
return type;
}
if (DEBUG) {
System.out.println("Creating " + name);
}
final Parameterizer parameterizer = new Parameterizer(genericType,
parameters);
type = parameterizer.copy();
parameterizer.copyReferences();
type.setName(name);
type.eAdapters().add(
new OriginReference(genericType,
parameterizer.actualParameters));
types.put(name, type);
typeRS.addToResource(type);
return type;
}
return target;
}
@SuppressWarnings("serial")
private static class Parameterizer extends EcoreUtil.Copier {
final GenericType genericType;
final Map<TypeVariable, IRType> parameters = new HashMap<TypeVariable, IRType>();
final IRType[] actualParameters;
public Parameterizer(GenericType genericType, List<IRType> parameters) {
super(false);
this.genericType = genericType;
final EList<TypeVariable> variables = genericType
.getTypeParameters();
this.actualParameters = new IRType[variables.size()];
for (int i = 0; i < variables.size(); ++i) {
final TypeVariable variable = variables.get(i);
IRType variableType = null;
if (i < parameters.size()) {
variableType = parameters.get(i);
}
if (variableType == null) {
variableType = JSTypeSet.any();
}
actualParameters[i] = variableType;
this.parameters.put(variable, variableType);
}
}
public Type copy() {
return (Type) copy(genericType);
}
@Override
public EObject copy(EObject eObject) {
if (eObject == null) {
return null;
} else {
final EObject copyEObject;
final EClass eClass;
if (eObject == genericType) {
final EClass genericClass = genericType.eClass();
final String parametererizedType = EcoreUtil.getAnnotation(
genericClass, TypeInfoModelPackage.eNS_URI,
"parameterizedType");
if (parametererizedType != null) {
final EClass parametererizedClass = (EClass) genericClass
.getEPackage().getEClassifier(
parametererizedType);
copyEObject = EcoreUtil.create(parametererizedClass);
} else {
copyEObject = TypeInfoModelFactory.eINSTANCE
.createType();
}
eClass = copyEObject.eClass();
} else if (eObject instanceof TypeVariableReference) {
final IRType source = parameters
.get(((TypeVariableReference) eObject)
.getVariable());
final RType result = TypeInfoModelFactory.eINSTANCE
.createRType();
result.setRuntimeType(source);
return result;
} else if (eObject instanceof TypeVariableClassType) {
final IRType source = parameters
.get(((TypeVariableClassType) eObject)
.getVariable());
final RType result = TypeInfoModelFactory.eINSTANCE
.createRType();
result.setRuntimeType(JSTypeSet
.classType(source instanceof IRSimpleType ? ((IRSimpleType) source)
.getTarget() : null));
return result;
} else {
copyEObject = createCopy(eObject);
eClass = eObject.eClass();
}
put(eObject, copyEObject);
for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i) {
EStructuralFeature eStructuralFeature = eClass
.getEStructuralFeature(i);
if (eStructuralFeature.isChangeable()
&& !eStructuralFeature.isDerived()) {
if (eStructuralFeature instanceof EAttribute) {
copyAttribute((EAttribute) eStructuralFeature,
eObject, copyEObject);
} else {
EReference eReference = (EReference) eStructuralFeature;
if (eReference.isContainment()) {
copyContainment(eReference, eObject,
copyEObject);
}
}
}
}
copyProxyURI(eObject, copyEObject);
return copyEObject;
}
}
@Override
protected void copyReference(EReference eReference, EObject eObject,
EObject copyEObject) {
if (eObject instanceof TypeVariableReference
|| eObject instanceof TypeVariableClassType)
return;
super.copyReference(eReference, eObject, copyEObject);
}
}
public Set<String> listTypes(TypeMode mode, String prefix) {
Set<String> result = new HashSet<String>();
final TypeInfoModelLoader loader = TypeInfoModelLoader.getInstance();
Set<String> typeNames = mode == TypeMode.CODE ? loader
.listTypeLiterals(prefix) : loader.listTypes(prefix);
if (typeNames != null) {
result.addAll(typeNames);
}
for (ITypeProvider provider : getTypeProviders()) {
typeNames = provider.listTypes(this, mode, prefix);
if (typeNames != null) {
result.addAll(typeNames);
}
}
return result;
}
/**
* @return the source
*/
public ReferenceSource getSource() {
return source;
}
public IValueCollection getTopValueCollection() {
if (resolve) {
for (IMemberEvaluator evaluator : TypeInfoManager
.getMemberEvaluators()) {
final IValueCollection collection = evaluator
.getTopValueCollection(this);
if (collection != null) {
return collection;
}
}
}
return null;
}
public IModelElement getModelElement() {
return source != null ? source.getModelElement() : null;
}
public String getContext() {
return null;
}
private enum TypeResolveMode {
SIMPLE, PROXY, UNKNOWN
}
private Type getType(String typeName, TypeMode mode,
boolean queryProviders, boolean queryPredefined,
boolean allowProxy, boolean allowUnknown) {
Type type = types.get(typeName);
if (type != null) {
if (!allowUnknown && type.getKind() == TypeKind.UNKNOWN) {
return null;
}
return type;
}
type = invariantRS.getCachedType(typeName);
if (type != null) {
types.put(typeName, type);
return type;
}
type = loadType(typeName, mode, queryProviders, queryPredefined);
if (type != null) {
validateTypeInfo(type);
types.put(typeName, type);
typeRS.addToResource(type);
return type;
}
if (allowProxy) {
type = TypeUtil.createProxy(typeName);
return type;
}
if (allowUnknown) {
type = createUnknown(typeName);
typeRS.addToResource(type);
types.put(typeName, type);
return type;
}
return null;
}
private void validateTypeInfo(Type type) {
final Resource resource = ((EObject) type).eResource();
if (resource != null) {
final ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet != null) {
if (!(resourceSet instanceof InvariantTypeResourceSet)) {
Assert.isLegal(!(resourceSet instanceof TypeResourceSet),
"Type " + type.getName()
+ " has invalid resource: " + resource
+ " (" + resourceSet.getClass() + ")");
}
}
}
// TODO check that member referenced types are contained or proxy
}
public void markInvariant(Type type) {
if (((EObject) type).eResource() != null) {
return;
}
invariantRS.add(type);
}
public void markInvariant(Type type, String context) {
if (((EObject) type).eResource() != null) {
return;
}
if (context == null) {
markInvariant(type);
} else {
Assert.isLegal(((EObject) type).eContainer() == null);
Assert.isLegal(((EObject) type).eResource() == null);
InvariantTypeResourceSet invariantTypeResourceSet = invariantContextRS
.get(context);
if (invariantTypeResourceSet == null) {
invariantTypeResourceSet = new InvariantTypeResourceSet(
context, invariantRS, invariantContextRS);
InvariantTypeResourceSet set = invariantContextRS.putIfAbsent(
context, invariantTypeResourceSet);
if (set != null) {
invariantTypeResourceSet = set;
}
}
invariantTypeResourceSet.add(type);
}
}
public Type getInvariantType(String typeName, String context) {
if (context == null) {
return invariantRS.getCachedType(typeName);
} else {
InvariantTypeResourceSet invariantTypeResourceSet = invariantContextRS
.get(context);
if (invariantTypeResourceSet != null) {
return invariantTypeResourceSet.getCachedType(typeName);
}
}
return null;
}
protected static Type createUnknown(String typeName) {
final Type type = TypeInfoModelFactory.eINSTANCE.createType();
type.setName(typeName);
type.setKind(TypeKind.UNKNOWN);
return type;
}
private final Map<String, Boolean> activeTypeRequests = new HashMap<String, Boolean>();
private boolean canQueryTypeProviders() {
return activeTypeRequests.isEmpty();
}
private Type loadType(String typeName, TypeMode mode,
boolean queryProviders, boolean queryPredefined) {
if (queryProviders
&& activeTypeRequests.put(typeName, Boolean.FALSE) == null) {
try {
Type type = invariantRS.getCachedType(typeName);
if (type != null) {
return type;
}
for (ITypeProvider provider : getTypeProviders()) {
type = provider.getType(this, mode, typeName);
if (type != null && !isProxy(type)) {
return type;
}
}
} finally {
activeTypeRequests.remove(typeName);
}
}
if (queryPredefined) {
final TypeInfoModelLoader loader = TypeInfoModelLoader
.getInstance();
final Type type;
if (mode == TypeMode.CODE) {
type = loader.getTypeLiteral(typeName);
} else {
type = loader.getType(typeName);
}
if (type != null) {
return type;
}
}
return null;
}
private ITypeProvider[] typeProviders = null;
public ITypeProvider[] getTypeProviders() {
if (typeProviders == null) {
typeProviders = createTypeProviders();
}
return typeProviders;
}
protected ITypeProvider[] createTypeProviders() {
return TypeInfoManager.createTypeProviders(this);
}
static abstract class TypeResourceSet extends ResourceSetImpl {
public TypeResourceSet() {
TypeInfoModelLoader.getInstance().initializeURIMap(this);
}
@Override
public EObject getEObject(URI uri, boolean loadOnDemand) {
if (TypeUtil.isTypeProxy(uri)) {
final String typeName = URI.decode(uri.fragment());
final Type type = resolveTypeProxy(typeName);
if (type == null) {
return createUnknown(typeName);
} else {
return type;
}
}
return super.getEObject(uri, loadOnDemand);
}
protected abstract Type resolveTypeProxy(String typeName);
public synchronized Resource getResource() {
if (typesResource == null) {
typesResource = new ResourceImpl(
TypeUtil.createProxyResourceURI());
getResources().add(typesResource);
}
return typesResource;
}
private Resource typesResource = null;
public void addToResource(final Type type) {
final EObject object = type;
if (object.eResource() == null) {
add(type);
}
}
protected synchronized void add(Type type) {
getResource().getContents().add(type);
}
}
private final TypeResourceSet typeRS = new TypeResourceSet() {
@Override
protected Type resolveTypeProxy(String typeName) {
return getType(typeName, null, true, false, false, false);
}
};
static class InvariantTypeResourceSet extends TypeResourceSet implements
ITypeInfoContext {
private final String context;
private final InvariantTypeResourceSet staticInvariants;
private final ConcurrentMap<String, InvariantTypeResourceSet> contextInvariants;
public InvariantTypeResourceSet(
ConcurrentMap<String, InvariantTypeResourceSet> contextInvariants) {
this(null, null, contextInvariants);
}
public InvariantTypeResourceSet(
String context,
InvariantTypeResourceSet staticInvariants,
ConcurrentMap<String, InvariantTypeResourceSet> contextInvariants) {
this.context = context;
this.staticInvariants = staticInvariants;
this.contextInvariants = contextInvariants;
}
private final Set<String> activeTypeRequests = new HashSet<String>();
private final Map<String, Type> types = new ConcurrentHashMap<String, Type>();
private boolean canQueryTypeProviders() {
synchronized (activeTypeRequests) {
return activeTypeRequests.isEmpty();
}
}
public String getContext() {
return context;
}
private Type getType(String typeName, TypeMode mode,
boolean queryProviders, boolean queryPredefined,
boolean allowProxy, boolean allowUnknown) {
Type type = types.get(typeName);
if (type != null) {
return type;
}
type = loadType(typeName, mode, queryProviders, queryPredefined);
if (type != null) {
// TODO validateTypeInfo(type);
addToResource(type);
return type;
}
if (allowProxy) {
type = TypeUtil.createProxy(typeName);
return type;
}
if (allowUnknown) {
type = createUnknown(typeName);
addToResource(type);
return type;
}
return null;
}
public SimpleType getTypeRef(String typeName) {
return TypeUtil.ref(getType(typeName));
}
private ITypeProvider[] typeProviders = null;
public ITypeProvider[] getTypeProviders() {
if (typeProviders == null) {
typeProviders = TypeInfoManager.createTypeProviders(this);
}
return typeProviders;
}
private Type loadType(String typeName, TypeMode mode,
boolean queryProviders, boolean queryPredefined) {
if (queryProviders) {
synchronized (activeTypeRequests) {
while (!activeTypeRequests.add(typeName)) {
try {
activeTypeRequests.wait();
} catch (InterruptedException e) {
}
}
}
try {
Type type = types.get(typeName);
if (type != null) {
return type;
}
for (ITypeProvider provider : getTypeProviders()) {
type = provider.getType(this, mode, typeName);
if (type != null && !isProxy(type)) {
return type;
}
}
} finally {
synchronized (activeTypeRequests) {
activeTypeRequests.remove(typeName);
activeTypeRequests.notifyAll();
}
}
}
if (queryPredefined) {
Type type = TypeInfoModelLoader.getInstance().getType(typeName);
if (type != null) {
return type;
}
}
return null;
}
@Override
protected Type resolveTypeProxy(String typeName) {
if (staticInvariants != null) {
Type cachedType = staticInvariants.getCachedType(typeName);
if (cachedType != null)
return cachedType;
}
return getType(typeName, null, true, false, false, false);
}
public Type getType(String typeName) {
if (typeName == null || typeName.length() == 0) {
return null;
}
final boolean queryProviders = canQueryTypeProviders();
return getType(typeName, null, queryProviders, true,
!queryProviders, true);
}
public Type getKnownType(String typeName, TypeMode mode) {
if (typeName == null || typeName.length() == 0) {
return null;
}
final boolean queryProviders = canQueryTypeProviders();
return getType(typeName, null, queryProviders, true,
!queryProviders, false);
}
public Type resolveType(Type type) {
if (type != null && type.isProxy()) {
final String typeName = URI.decode(((InternalEObject) type)
.eProxyURI().fragment());
final Type resolved = getType(typeName, null, true, true,
false, true);
if (resolved != null) {
return resolved;
}
}
return type;
}
public void markInvariant(Type type) {
if (((EObject) type).eResource() != null) {
return;
}
// context == null, this is a static one
if (staticInvariants == null)
add(type);
else
staticInvariants.add(type);
}
public void markInvariant(Type type, String context) {
if (((EObject) type).eResource() != null) {
return;
}
if (context.equals(this.context)) {
add(type);
} else {
InvariantTypeResourceSet invariantTypeResourceSet = this.contextInvariants
.get(context);
if (invariantTypeResourceSet == null) {
invariantTypeResourceSet = new InvariantTypeResourceSet(
context, invariantRS, invariantContextRS);
InvariantTypeResourceSet set = invariantContextRS
.putIfAbsent(context, invariantTypeResourceSet);
if (set != null) {
invariantTypeResourceSet = set;
}
}
invariantTypeResourceSet.add(type);
}
}
public Type getInvariantType(String typeName, String context) {
if (context == null) {
if (staticInvariants == null) {
return getCachedType(typeName);
} else {
return staticInvariants.getCachedType(typeName);
}
} else if (context.equals(this.context)) {
return getCachedType(typeName);
} else {
InvariantTypeResourceSet invariantTypeResourceSet = invariantContextRS
.get(context);
if (invariantTypeResourceSet != null) {
return invariantTypeResourceSet.getCachedType(typeName);
}
}
return null;
}
public IModelElement getModelElement() {
return null;
}
public ReferenceSource getSource() {
return ReferenceSource.UNKNOWN;
}
@Override
public void add(Type type) {
super.add(type);
types.put(type.getName(), type);
}
public Type getCachedType(String typeName) {
return types.get(typeName);
}
public void reset() {
types.clear();
synchronized (this) {
getResource().getContents().clear();
}
}
public IValue valueOf(Member member) {
// TODO (alex) review
return null;
}
public Type parameterize(Type target, List<IRType> parameters) {
// TODO (alex) review
return target;
}
public <T> T getAttribute(AttributeKey<T> key) {
// TODO (alex) review
return null;
}
public <T> void pushAttribute(AttributeKey<T> key, T value) {
// TODO (alex) review
}
public <T> T popAttribute(AttributeKey<T> key) {
// TODO (alex) review
return null;
}
}
static final ConcurrentHashMap<String, InvariantTypeResourceSet> invariantContextRS = new ConcurrentHashMap<String, InvariantTypeResourceSet>();
static final InvariantTypeResourceSet invariantRS = new InvariantTypeResourceSet(
invariantContextRS);
protected static boolean isProxy(Type type) {
return ((EObject) type).eIsProxy();
}
private IValueTypeFactory factory = new ValueTypeFactoryImpl(this);
public IValueTypeFactory getFactory() {
return factory;
}
private boolean resolve = true;
private Map<String, Member> elements = new HashMap<String, Member>();
public Member resolve(String name) {
if (name == null)
return null;
Member element = elements.get(name);
if (element != null) {
return element;
}
element = TypeInfoModelLoader.getInstance().getMember(name);
if (element != null) {
elements.put(name, element);
return element;
}
if (resolve) {
for (IElementResolver resolver : TypeInfoManager
.getElementResolvers()) {
element = resolver.resolveElement(this, name);
if (element != null) {
elements.put(name, element);
return element;
}
}
}
return null;
}
public IValue valueOf(Member member) {
for (IMemberEvaluator evaluator : TypeInfoManager.getMemberEvaluators()) {
final IValueCollection collection = evaluator.valueOf(this, member);
if (collection != null) {
if (collection instanceof IValueProvider) {
IValue value = ((IValueProvider) collection).getValue();
if (member.getType() != null) {
value.setDeclaredType(JSTypeSet.normalize(this,
member.getType()));
}
if (value.getKind() == ReferenceKind.UNKNOWN) {
if (member instanceof Property) {
value.setKind(ReferenceKind.PROPERTY);
} else {
value.setKind(ReferenceKind.METHOD);
}
}
if (value instanceof ImmutableValue) {
ElementValue elementValue = ElementValue.createFor(
member, this);
return new ValueWithElementValue(
(ImmutableValue) value, elementValue);
}
return value;
} else {
break;
}
}
}
return null;
}
public Set<String> listGlobals(String prefix) {
final Set<String> result = new HashSet<String>();
for (Member member : TypeInfoModelLoader.getInstance().listMembers(
prefix)) {
result.add(member.getName());
}
for (IElementResolver resolver : TypeInfoManager.getElementResolvers()) {
Set<String> globals = resolver.listGlobals(this, prefix);
if (globals != null) {
result.addAll(globals);
}
}
return result;
}
public void setDoResolve(boolean resolve) {
this.resolve = resolve;
}
private IModelBuilder[] modelBuilders = null;
public IModelBuilder[] getModelBuilders() {
if (modelBuilders == null) {
modelBuilders = TypeInfoManager.getModelBuilders(this);
}
return modelBuilders;
}
private static final ThreadLocal<TypeInferencer2> CURRENT = new ThreadLocal<TypeInferencer2>();
protected static final ITypeSystem DELEGATING_TYPE_SYSTEM = new DelagatingTypeSystem();
private static class DelagatingTypeSystem implements ITypeSystem {
private TypeInferencer2 current() {
return CURRENT.get();
}
public IValue valueOf(Member member) {
final TypeInferencer2 current = current();
if (current != null) {
return current.valueOf(member);
} else {
return null;
}
}
public Type resolveType(Type type) {
if (type != null && type.isProxy()) {
final TypeInferencer2 current = current();
if (current != null) {
return current.doResolveType(type);
} else {
final Type resolved = TypeInfoModelLoader.getInstance()
.getType(type.getName());
if (resolved != null) {
return resolved;
}
}
}
return type;
}
public Type parameterize(Type target, List<IRType> parameters) {
final TypeInferencer2 current = current();
if (current != null) {
return current.parameterize(target, parameters);
} else {
return target;
}
}
public <T> T getAttribute(AttributeKey<T> key) {
final TypeInferencer2 current = current();
return current != null ? current.getAttribute(key) : null;
}
}
private final Map<AttributeKey<?>, List<Object>> attributes = new HashMap<AttributeKey<?>, List<Object>>();
@SuppressWarnings("unchecked")
public <T> T getAttribute(AttributeKey<T> key) {
final List<Object> values = attributes.get(key);
return values != null && !values.isEmpty() ? (T) values.get(values
.size() - 1) : null;
}
public <T> void pushAttribute(AttributeKey<T> key, T value) {
List<Object> values = attributes.get(key);
if (values == null) {
values = new ArrayList<Object>(4);
attributes.put(key, values);
}
values.add(value);
}
@SuppressWarnings("unchecked")
public <T> T popAttribute(AttributeKey<T> key) {
final List<Object> values = attributes.get(key);
if (values != null && !values.isEmpty()) {
return (T) values.remove(values.size() - 1);
} else {
return null;
}
}
}