| package org.eclipse.dltk.internal.javascript.ti; |
| |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.dltk.internal.javascript.validation.JavaScriptValidations; |
| 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.IRClassType; |
| import org.eclipse.dltk.javascript.typeinfo.IRType; |
| import org.eclipse.dltk.javascript.typeinfo.RTypes; |
| import org.eclipse.dltk.javascript.typeinfo.model.Type; |
| |
| public class LazyTypeReference extends AbstractReference { |
| |
| final class LazyTypeValue extends Value implements ILazyValue { |
| boolean resolved = false; |
| private boolean finalResolve; |
| private boolean doResolve = true; |
| private boolean resolving; |
| |
| public void resolve() { |
| if (!resolved && doResolve && !resolving) { |
| resolving = true; |
| doResolve(); |
| resolving = false; |
| } |
| } |
| |
| private void doResolve() { |
| IValueReference createChild = collection.getChild(className); |
| if (createChild.exists() |
| && createChild.getAttribute(IReferenceAttributes.RESOLVING) == null) { |
| final IRType childType = JavaScriptValidations |
| .typeOf(createChild); |
| if (childType != null && childType instanceof IRClassType) { |
| final Type target = ((IRClassType) childType).getTarget(); |
| if (target != null) { |
| setDeclaredType(RTypes.simple(context, target)); |
| resolved = true; |
| return; |
| } |
| } |
| IValueCollection collection = (IValueCollection) createChild |
| .getAttribute(IReferenceAttributes.FUNCTION_SCOPE); |
| if (collection != null && collection.getThis() != null) { |
| addValue(((IValueProvider) collection.getThis()).getValue()); |
| } else { |
| IValue src = ((IValueProvider) createChild).getValue(); |
| if (src != null) { |
| addValue(src); |
| } |
| } |
| setKind(ReferenceKind.TYPE); |
| setDeclaredType(RTypes.localType(className, createChild)); |
| resolved = true; |
| } else if (className.indexOf('.') != -1) { |
| StringTokenizer st = new StringTokenizer(className, "."); |
| IValueReference child = null; |
| while (st.hasMoreTokens()) { |
| String token = st.nextToken(); |
| if (child == null) { |
| child = collection.getChild(token); |
| } else { |
| child = child.getChild(token); |
| } |
| if (!child.exists()) { |
| child = null; |
| break; |
| } |
| } |
| if (child != null) { |
| IValue src = ((IValueProvider) child).getValue(); |
| if (src != null) { |
| // this is a type so try to get the this of the |
| // function if this resolves to a function object. |
| IValueCollection collection = (IValueCollection) src |
| .getAttribute( |
| IReferenceAttributes.FUNCTION_SCOPE, |
| true); |
| if (collection != null) |
| addValue(((IValueProvider) collection.getThis()) |
| .getValue()); |
| else |
| addValue(src); |
| setDeclaredType(RTypes.localType(className, child)); |
| } |
| setKind(ReferenceKind.TYPE); |
| resolved = true; |
| } |
| } else { |
| doResolve = !finalResolve; |
| } |
| } |
| |
| public String getLazyName() { |
| return className; |
| } |
| |
| public boolean isResolved() { |
| return resolved; |
| } |
| |
| public void setFinalResolve() { |
| finalResolve = true; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof LazyTypeValue) |
| return ((LazyTypeValue) obj).getLazyName().equals(className); |
| return super.equals(obj); |
| } |
| |
| @Override |
| public int hashCode() { |
| return className.hashCode(); |
| } |
| } |
| |
| private final LazyTypeValue value = new LazyTypeValue(); |
| final ITypeInferenceContext context; |
| final String className; |
| final IValueCollection collection; |
| |
| public LazyTypeReference(ITypeInferenceContext context, String className, |
| IValueCollection collection) { |
| this.context = context; |
| this.className = className; |
| this.collection = collection; |
| |
| } |
| |
| @Override |
| public IValueReference getChild(String name) { |
| if (name.equals(IValueReference.FUNCTION_OP)) |
| return this; |
| return super.getChild(name); |
| } |
| |
| public IValueReference getParent() { |
| return null; |
| } |
| |
| public String getName() { |
| return className; |
| } |
| |
| public void delete(boolean force) { |
| } |
| |
| public boolean isReference() { |
| return true; |
| } |
| |
| @Override |
| public IValue getValue() { |
| value.resolve(); |
| return value; |
| } |
| |
| @Override |
| public boolean exists() { |
| value.resolve(); |
| return value.isResolved(); |
| } |
| |
| @Override |
| public IValue createValue() { |
| return getValue(); |
| } |
| |
| } |