| /******************************************************************************* |
| * 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.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.dltk.annotations.Internal; |
| import org.eclipse.dltk.compiler.problem.IProblemIdentifier; |
| import org.eclipse.dltk.internal.javascript.validation.ValidationMessages; |
| import org.eclipse.dltk.javascript.core.JavaScriptProblems; |
| import org.eclipse.dltk.javascript.typeinference.IAssignProtection; |
| import org.eclipse.dltk.javascript.typeinference.ILocationProvider; |
| 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.typeinference.ReferenceLocation; |
| import org.eclipse.dltk.javascript.typeinfo.IMemberEvaluator; |
| import org.eclipse.dltk.javascript.typeinfo.IRArrayType; |
| import org.eclipse.dltk.javascript.typeinfo.IRClassType; |
| import org.eclipse.dltk.javascript.typeinfo.IRElement; |
| import org.eclipse.dltk.javascript.typeinfo.IRFunctionType; |
| import org.eclipse.dltk.javascript.typeinfo.IRLocalType; |
| import org.eclipse.dltk.javascript.typeinfo.IRMapType; |
| import org.eclipse.dltk.javascript.typeinfo.IRMember; |
| import org.eclipse.dltk.javascript.typeinfo.IRMethod; |
| import org.eclipse.dltk.javascript.typeinfo.IRProperty; |
| import org.eclipse.dltk.javascript.typeinfo.IRRecordMember; |
| import org.eclipse.dltk.javascript.typeinfo.IRRecordType; |
| import org.eclipse.dltk.javascript.typeinfo.IRSimpleType; |
| import org.eclipse.dltk.javascript.typeinfo.IRType; |
| import org.eclipse.dltk.javascript.typeinfo.IRTypeDeclaration; |
| import org.eclipse.dltk.javascript.typeinfo.IRUnionType; |
| import org.eclipse.dltk.javascript.typeinfo.ITypeInfoContext; |
| import org.eclipse.dltk.javascript.typeinfo.ITypeSystem; |
| import org.eclipse.dltk.javascript.typeinfo.JSTypeSet; |
| import org.eclipse.dltk.javascript.typeinfo.MemberPredicate; |
| import org.eclipse.dltk.javascript.typeinfo.MemberPredicates; |
| import org.eclipse.dltk.javascript.typeinfo.RSimpleType; |
| import org.eclipse.dltk.javascript.typeinfo.RTypeMemberQuery; |
| import org.eclipse.dltk.javascript.typeinfo.RTypes; |
| import org.eclipse.dltk.javascript.typeinfo.TypeInfoManager; |
| import org.eclipse.dltk.javascript.typeinfo.TypeUtil; |
| import org.eclipse.dltk.javascript.typeinfo.model.Element; |
| import org.eclipse.dltk.javascript.typeinfo.model.Type; |
| import org.eclipse.dltk.javascript.typeinfo.model.TypeKind; |
| |
| public abstract class ElementValue implements IValue { |
| |
| public static IValue findMember(IRType type, String name) { |
| return findMember(type, name, MemberPredicates.ALWAYS_TRUE); |
| } |
| |
| private static class PrototypeType extends RSimpleType { |
| public PrototypeType(IRTypeDeclaration declaration) { |
| super(declaration); |
| } |
| |
| @Override |
| public String getName() { |
| return "prototype<" + getTarget().getName() + ">"; |
| } |
| |
| @Override |
| public boolean isExtensible() { |
| return true; |
| } |
| } |
| |
| static IValue findMemberA(IRType type, String name, boolean resolve) { |
| final MemberPredicate predicate; |
| if (type instanceof IRClassType) { |
| final Type target = ((IRClassType) type).getTarget(); |
| predicate = target != null ? target.memberPredicateFor(type, |
| MemberPredicates.STATIC) : MemberPredicates.STATIC; |
| } else if (type instanceof IRSimpleType) { |
| final Type target = ((IRSimpleType) type).getTarget(); |
| predicate = target != null ? target.memberPredicateFor(type, |
| MemberPredicates.NON_STATIC) : MemberPredicates.NON_STATIC; |
| } else if (type instanceof IRUnionType) { |
| // TODO (alex) use different predicate for each option |
| predicate = MemberPredicates.ALWAYS_TRUE; |
| } else { |
| predicate = MemberPredicates.NON_STATIC; |
| } |
| return findMember(type, name, predicate, resolve); |
| } |
| |
| public static IValue findMember(IRType type, String name, |
| MemberPredicate predicate) { |
| return findMember(type, name, predicate, true); |
| } |
| |
| public static IValue findMember(IRType type, String name, |
| MemberPredicate predicate, boolean resolve) { |
| if (IValueReference.ARRAY_OP.equals(name)) { |
| IRType arrayType = TypeUtil.extractArrayItemType(type); |
| // only give back this a a TypeValue if it is a known and not a |
| // NoneType |
| if (arrayType != null |
| && TypeUtil.kind(arrayType) != TypeKind.UNKNOWN |
| && arrayType != RTypes.none() |
| && arrayType != RTypes.arrayOf().getItemType()) { |
| return new TypeValue(arrayType); |
| } |
| } |
| if (type instanceof IRClassType) { |
| final IRTypeDeclaration t = ((IRClassType) type).getDeclaration(); |
| if (t != null) { |
| final List<IRMember> selection = findMembers(t, name, predicate); |
| if (!selection.isEmpty()) { |
| if (selection.size() == 1) { |
| return createElement(t.getTypeSystem(), t, |
| selection.get(0)); |
| } |
| return new MemberValue( |
| selection.toArray(new IRMember[selection.size()])); |
| } |
| } |
| if ((t == null || t.getSource().hasPrototype()) |
| && predicate.isCompatibleWith(MemberPredicates.STATIC)) { |
| final List<IRMember> selection = findMembers( |
| t != null ? t.getTypeSystem().convert( |
| t.getSource().getPrototypeType()) |
| : RTypes.FUNCTION.getDeclaration(), name, |
| MemberPredicates.NON_STATIC); |
| if (!selection.isEmpty()) { |
| if (selection.size() == 1) { |
| final IRMember selected = selection.get(0); |
| if (IRLocalType.PROTOTYPE_PROPERTY.equals(selected |
| .getName()) |
| && selected instanceof IRProperty) { |
| if (t != null) { |
| return new PrototypePropertyValue( |
| (IRProperty) selected, |
| new PrototypeType(t)); |
| } else { |
| return new PrototypePropertyValue( |
| (IRProperty) selected, |
| new PrototypeType( |
| RTypes.OBJECT.getDeclaration())); |
| } |
| } |
| return createElement(selected); |
| } |
| return new MemberValue( |
| selection.toArray(new IRMember[selection.size()])); |
| } |
| } |
| } else if (type instanceof IRUnionType) { |
| for (IRType unionTarget : ((IRUnionType) type).getTargets()) { |
| IValue member = findMember(unionTarget, name, predicate, |
| resolve); |
| if (member != null) |
| return member; |
| } |
| } else if (type instanceof IRRecordType) { |
| final IRRecordMember member = ((IRRecordType) type).getMember(name); |
| if (member != null) { |
| return new RTypeValue(member.getType(), member); |
| } |
| return findMember(RTypes.OBJECT, name); |
| } else if (type instanceof IRFunctionType) { |
| final IRFunctionType functionType = (IRFunctionType) type; |
| if (FunctionMethod.apply.test(name)) { |
| return getFunctionMethod(functionType.getTypeSystem(), |
| functionType, FunctionMethod.apply); |
| } else if (FunctionMethod.call.test(name)) { |
| return getFunctionMethod(functionType.getTypeSystem(), |
| functionType, FunctionMethod.call); |
| } else { |
| final List<IRMember> selection = findMembers( |
| RTypes.FUNCTION.getDeclaration(), name, predicate); |
| if (!selection.isEmpty()) { |
| if (selection.size() == 1) { |
| return createElement(selection.get(0)); |
| } |
| return new MemberValue( |
| selection.toArray(new IRMember[selection.size()])); |
| } |
| } |
| } else if (type instanceof IRLocalType) { |
| final IValueReference child = ((IRLocalType) type) |
| .getDirectChild(name); |
| if (child != null) { |
| final IValue value = ((IValueProvider) child).getValue(); |
| if (value != null) |
| return value; |
| } |
| return findMember(RTypes.OBJECT, name); |
| } else if (type instanceof IRSimpleType) { |
| final IRTypeDeclaration t = ((IRSimpleType) type).getDeclaration(); |
| if (t != null) { |
| final List<IRMember> selection = findMembers(t, name, predicate); |
| if (!selection.isEmpty()) { |
| if (selection.size() == 1) { |
| return createElement(t.getTypeSystem(), t, |
| selection.get(0)); |
| } |
| return new MemberValue( |
| selection.toArray(new IRMember[selection.size()])); |
| } else if (resolve |
| && t.getTypeSystem() instanceof ITypeInfoContext) { |
| Type target = ((IRSimpleType) type).getTarget(); |
| for (IMemberEvaluator evaluator : TypeInfoManager |
| .getMemberEvaluators()) { |
| final IValueCollection collection = evaluator.valueOf( |
| (ITypeInfoContext) t.getTypeSystem(), target); |
| if (collection != null) { |
| if (collection instanceof IValueProvider) { |
| IValueReference child = collection |
| .getChild(name); |
| if (child instanceof IValueProvider) { |
| return ((IValueProvider) child).getValue(); |
| } |
| } |
| } |
| } |
| } |
| } |
| } else if (type instanceof IRMapType) { |
| final List<IRMember> selection = findMembers( |
| RTypes.OBJECT.getDeclaration(), name, predicate); |
| if (!selection.isEmpty()) { |
| if (selection.size() == 1) { |
| return createElement(selection.get(0)); |
| } |
| return new MemberValue(selection.toArray(new IRMember[selection |
| .size()])); |
| } |
| if (!IValueReference.ARRAY_OP.equals(name) |
| && !IValueReference.FUNCTION_OP.equals(name)) { |
| return new RTypeValue(((IRMapType) type).getValueType(), null); |
| } |
| } else if (type == RTypes.any()) { |
| if (!IValueReference.ARRAY_OP.equals(name) |
| && !IValueReference.FUNCTION_OP.equals(name)) { |
| return PhantomValue.VALUE; |
| } |
| } |
| return null; |
| } |
| |
| private static ElementValue getFunctionMethod(ITypeSystem context, |
| IRFunctionType type, FunctionMethod method) { |
| if (context != null) { |
| final FunctionMethodKey key = new FunctionMethodKey(type, method); |
| ElementValue value = (ElementValue) context.getValue(key); |
| if (value == null) { |
| value = new FunctionTypeMethodValue(type, method); |
| context.setValue(key, value); |
| } |
| return value; |
| } else { |
| return new FunctionTypeMethodValue(type, method); |
| } |
| } |
| |
| private static class FunctionMethodKey { |
| private final IRFunctionType type; |
| private final FunctionMethod method; |
| |
| public FunctionMethodKey(IRFunctionType type, FunctionMethod method) { |
| this.type = type; |
| this.method = method; |
| } |
| |
| @Override |
| public int hashCode() { |
| return type.hashCode() ^ method.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof FunctionMethodKey) { |
| final FunctionMethodKey other = (FunctionMethodKey) obj; |
| return type.equals(other.type) && method == other.method; |
| } |
| return false; |
| } |
| } |
| |
| private static ElementValue createElement(final IRMember member) { |
| if (member instanceof IRProperty) { |
| return new PropertyValue((IRProperty) member); |
| } else if (member instanceof IRMethod) { |
| return new MethodValue((IRMethod) member); |
| } else { |
| throw new IllegalArgumentException("Unsupported IRMember of type " |
| + member.getClass()); |
| } |
| } |
| |
| private static ElementValue createElement(ITypeSystem context, |
| final IRTypeDeclaration type, final IRMember member) { |
| if (member instanceof IRProperty) { |
| if (TypeSystemImpl.isContextualizable(member.getType())) { |
| return new PropertyValue(context.contextualize( |
| (IRProperty) member, type)); |
| } else { |
| return new PropertyValue((IRProperty) member); |
| } |
| } else if (member instanceof IRMethod) { |
| if (TypeSystemImpl.isContextualizable(member.getType())) { |
| return new MethodValue(context.contextualize((IRMethod) member, |
| type)); |
| } else { |
| return new MethodValue((IRMethod) member); |
| } |
| } else { |
| return null; |
| } |
| } |
| |
| public static List<IRMember> findMembers(IRTypeDeclaration type, |
| String name, MemberPredicate predicate) { |
| final List<IRMember> selection = new ArrayList<IRMember>(4); |
| for (IRMember member : new RTypeMemberQuery(type, predicate) |
| .ignoreDuplicates()) { |
| if (name.equals(member.getName())) { |
| selection.add(member); |
| } |
| } |
| return selection; |
| } |
| |
| public static ElementValue createFor(IRElement element) { |
| if (element instanceof IRMethod) { |
| return new MethodValue((IRMethod) element); |
| } else if (element instanceof IRProperty) { |
| return new PropertyValue((IRProperty) element); |
| } else { |
| final IRTypeDeclaration type = (IRTypeDeclaration) element; |
| return new TypeValue(RTypes.simple(type)); |
| } |
| } |
| |
| public static ElementValue createClass(ITypeSystem context, Type type) { |
| return new ClassValue(JSTypeSet.singleton(RTypes.classType(context, |
| type))); |
| } |
| |
| static class TypeValue extends ElementValue implements IValue { |
| |
| private final Map<String, IValue> children = new HashMap<String, IValue>( |
| 4, 0.9f); |
| |
| private final JSTypeSet types; |
| |
| public TypeValue(IRType type) { |
| this.types = JSTypeSet.singleton(type); |
| } |
| |
| public TypeValue(JSTypeSet types) { |
| this.types = types; |
| } |
| |
| @Override |
| public final Set<String> getDirectChildren(int flags) { |
| if ((flags & NO_LOCAL_TYPES) == 0) { |
| final Set<String> set = new HashSet<String>(); |
| for (IRType irType : getTypes()) { |
| if (irType instanceof IRLocalType) { |
| set.addAll(((IRLocalType) irType).getDirectChildren()); |
| } |
| } |
| return set; |
| } else { |
| return Collections.emptySet(); |
| } |
| } |
| |
| @Override |
| protected Type[] getElements() { |
| return types.toArray(); |
| } |
| |
| public IValue getChild(String name, boolean resolve) { |
| IValue value = children.get(name); |
| if (value == null) { |
| for (IRType type : types) { |
| value = findMemberA(type, name, resolve); |
| if (value != null) { |
| if (value instanceof ElementValue) { |
| value = ((ElementValue) value).resolveValue(); |
| } |
| break; |
| } |
| } |
| if (value == null && name.equals(IValueReference.ARRAY_OP)) { |
| value = new Value(); |
| } |
| if (value != null) { |
| children.put(name, value); |
| } |
| } |
| return value; |
| } |
| |
| public IRType getDeclaredType() { |
| return types.toRType(); |
| } |
| |
| public JSTypeSet getDeclaredTypes() { |
| return types; |
| } |
| |
| @Override |
| public final JSTypeSet getTypes() { |
| return types; |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + types; |
| } |
| } |
| |
| private static class ClassValue extends ElementValue implements IValue { |
| |
| private final JSTypeSet types; |
| |
| public ClassValue(JSTypeSet types) { |
| this.types = types; |
| } |
| |
| @Override |
| protected Type[] getElements() { |
| return types.toArray(); |
| } |
| |
| public IValue getChild(String name, boolean resolve) { |
| // just guess that if the child is the function operator it is a new |
| // expression of this type. return then the none static type. |
| if (name.equals(IValueReference.FUNCTION_OP)) { |
| if (types.size() == 1) { |
| final IRType type = types.toRType(); |
| if (type instanceof IRClassType) { |
| return new TypeValue(((IRClassType) type).newItemType()); |
| } |
| } |
| final JSTypeSet returnTypes = JSTypeSet.create(); |
| for (IRType type : types) { |
| if (type instanceof IRClassType) { |
| returnTypes.add(((IRClassType) type).newItemType()); |
| } else { |
| returnTypes.add(type); |
| } |
| } |
| return new TypeValue(returnTypes); |
| } |
| for (IRType type : types) { |
| IValue child = findMember(type, name, MemberPredicates.STATIC); |
| if (child != null) |
| return child; |
| } |
| return null; |
| } |
| |
| public IRType getDeclaredType() { |
| return types.toRType(); |
| } |
| |
| public JSTypeSet getDeclaredTypes() { |
| return types; |
| } |
| |
| @Override |
| public ReferenceKind getKind() { |
| return ReferenceKind.TYPE; |
| } |
| |
| @Override |
| public Object getAttribute(String key, boolean includeReferences) { |
| if (IAssignProtection.ATTRIBUTE.equals(key)) { |
| return UNASSIGNABLE_CLASS; |
| } |
| return super.getAttribute(key, includeReferences); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + types; |
| } |
| } |
| |
| private static class MethodValue extends ElementValue implements IValue { |
| |
| private TypeValue functionOperator; |
| private final IRMethod method; |
| |
| public MethodValue(IRMethod method) { |
| this.method = method; |
| } |
| |
| @Override |
| protected IRMethod getElements() { |
| return method; |
| } |
| |
| @Override |
| public IValue resolveValue() { |
| final IValue value = resolveValue(method); |
| if (value != null) { |
| return value; |
| } |
| return this; |
| } |
| |
| @Override |
| public ReferenceKind getKind() { |
| return ReferenceKind.METHOD; |
| } |
| |
| public IValue getChild(String name, boolean resolve) { |
| if (IValueReference.FUNCTION_OP.equals(name)) { |
| if (method.getType() != null) { |
| if (functionOperator == null) { |
| functionOperator = new TypeValue( |
| JSTypeSet.singleton(method.getType())); |
| } |
| return functionOperator; |
| } |
| } |
| final IValue child = ElementValue.findMemberA(getDeclaredType(), |
| name, resolve); |
| if (child != null) { |
| return child; |
| } |
| return null; |
| } |
| |
| public IRType getDeclaredType() { |
| return RTypes.FUNCTION; |
| } |
| |
| public JSTypeSet getDeclaredTypes() { |
| return JSTypeSet.singleton(getDeclaredType()); |
| } |
| |
| @Override |
| public Object getAttribute(String key, boolean includeReferences) { |
| if (IAssignProtection.ATTRIBUTE.equals(key) |
| && method.getDeclaringType() == null) { |
| return UNASSIGNABLE_METHOD; |
| } |
| return super.getAttribute(key, includeReferences); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + '<' + method + '>'; |
| } |
| } |
| |
| public static final IAssignProtection READONLY_PROPERTY = new IAssignProtection() { |
| public IProblemIdentifier problemId() { |
| return JavaScriptProblems.PROPERTY_READONLY; |
| } |
| |
| public String problemMessage() { |
| return ValidationMessages.AssignmentToReadonlyProperty; |
| } |
| }; |
| |
| static final IAssignProtection UNASSIGNABLE_METHOD = new IAssignProtection() { |
| public IProblemIdentifier problemId() { |
| return JavaScriptProblems.UNASSIGNABLE_ELEMENT; |
| } |
| |
| public String problemMessage() { |
| return ValidationMessages.UnassignableMethod; |
| } |
| }; |
| |
| static final IAssignProtection UNASSIGNABLE_CLASS = new IAssignProtection() { |
| public IProblemIdentifier problemId() { |
| return JavaScriptProblems.UNASSIGNABLE_ELEMENT; |
| } |
| |
| public String problemMessage() { |
| return ValidationMessages.UnassignableClass; |
| } |
| }; |
| |
| private static class PropertyValue extends ElementValue implements IValue { |
| |
| private final IRProperty property; |
| private final Map<String, IValue> children = new HashMap<String, IValue>( |
| 4, 0.9f); |
| |
| public PropertyValue(IRProperty property) { |
| this.property = property; |
| } |
| |
| @Override |
| protected IRProperty getElements() { |
| return property; |
| } |
| |
| @Override |
| public IValue resolveValue() { |
| final IValue value = resolveValue(property); |
| if (value != null) { |
| return value; |
| } |
| return this; |
| } |
| |
| @Override |
| public ReferenceKind getKind() { |
| return ReferenceKind.PROPERTY; |
| } |
| |
| @Override |
| public Set<String> getDirectChildren(int flags) { |
| IValue value = resolveValue(); |
| if (value != null && value != this) { |
| return value.getDirectChildren(flags); |
| } |
| return super.getDirectChildren(flags); |
| } |
| |
| public IValue getChild(String name, boolean resolve) { |
| IValue child = children.get(name); |
| if (child == null) { |
| if (IValueReference.ARRAY_OP.equals(name) |
| && property.getType() != null) { |
| IRType arrayType = null; |
| if (property.getType() instanceof IRArrayType) { |
| arrayType = ((IRArrayType) property.getType()) |
| .getItemType(); |
| } else if (property.getType() instanceof IRMapType) { |
| arrayType = ((IRMapType) property.getType()) |
| .getValueType(); |
| } |
| if (arrayType != null) { |
| child = new TypeValue(arrayType); |
| children.put(name, child); |
| return child; |
| } |
| } |
| final IRType propType = getDeclaredType(); |
| child = ElementValue.findMemberA(propType, name, |
| resolve); |
| if (child instanceof ElementValue) { |
| child = ((ElementValue) child).resolveValue(); |
| } |
| if (child != null) |
| children.put(name, child); |
| } |
| return child; |
| } |
| |
| public IRType getDeclaredType() { |
| return property.getType(); |
| } |
| |
| private JSTypeSet declaredTypes = null; |
| |
| public JSTypeSet getDeclaredTypes() { |
| if (declaredTypes == null) { |
| final IRType type = getDeclaredType(); |
| if (type != null) { |
| declaredTypes = JSTypeSet.singleton(type); |
| } else { |
| declaredTypes = JSTypeSet.emptySet(); |
| } |
| } |
| return declaredTypes; |
| } |
| |
| @Override |
| public Object getAttribute(String key, boolean includeReferences) { |
| if (IAssignProtection.ATTRIBUTE.equals(key)) { |
| final IRTypeDeclaration declaringType = property |
| .getDeclaringType(); |
| if (declaringType != null) { |
| return declaringType.getReadOnlyStatus(property); |
| } else { |
| return property.isReadOnly() ? READONLY_PROPERTY : null; |
| } |
| } |
| return super.getAttribute(key, includeReferences); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + '<' + property + '>'; |
| } |
| } |
| |
| private static class PrototypePropertyValue extends PropertyValue { |
| private final IRType valueType; |
| |
| public PrototypePropertyValue(IRProperty property, IRType valueType) { |
| super(property); |
| this.valueType = valueType; |
| } |
| |
| @Override |
| public IRType getDeclaredType() { |
| return valueType; |
| } |
| } |
| |
| private static class RTypeValue extends ElementValue implements IValue { |
| |
| private final IRType type; |
| private final Map<String, IValue> children = new HashMap<String, IValue>(); |
| private final IRMember element; |
| |
| public RTypeValue(IRType type, IRMember element) { |
| this.type = type; |
| this.element = element; |
| } |
| |
| @Override |
| protected IRMember getElements() { |
| return element; |
| } |
| |
| @Override |
| public ReferenceKind getKind() { |
| return ReferenceKind.PROPERTY; |
| } |
| |
| public IValue getChild(String name, boolean resolve) { |
| IValue child = children.get(name); |
| if (child == null) { |
| if (IValueReference.ARRAY_OP.equals(name)) { |
| IRType arrayType = null; |
| if (type instanceof IRArrayType) { |
| arrayType = ((IRArrayType) type).getItemType(); |
| } else if (type instanceof IRMapType) { |
| arrayType = ((IRMapType) type).getValueType(); |
| } |
| if (arrayType != null) { |
| ElementValue arrayOpChild = new TypeValue(arrayType); |
| children.put(name, arrayOpChild); |
| return arrayOpChild; |
| } |
| } else if (IValueReference.FUNCTION_OP.equals(name)) { |
| if (type instanceof IRFunctionType) { |
| child = new Value(); |
| child.addType(((IRFunctionType) type).getReturnType()); |
| children.put(name, child); |
| return child; |
| } |
| } |
| child= ElementValue.findMemberA(type, name, resolve); |
| if (child instanceof ElementValue) { |
| child = ((ElementValue) child).resolveValue(); |
| children.put(name, child); |
| } |
| } |
| return child; |
| } |
| |
| @Override |
| public final Set<String> getDirectChildren(int flags) { |
| if ((flags & NO_LOCAL_TYPES) == 0) { |
| final Set<String> set = new HashSet<String>(); |
| IRType irType = getDeclaredType(); |
| if (irType instanceof IRLocalType) { |
| set.addAll(((IRLocalType) irType).getDirectChildren()); |
| } |
| return set; |
| } else { |
| return Collections.emptySet(); |
| } |
| } |
| |
| public IRType getDeclaredType() { |
| return type; |
| } |
| |
| public JSTypeSet getDeclaredTypes() { |
| if (type != null) { |
| return JSTypeSet.singleton(type); |
| } else { |
| return JSTypeSet.emptySet(); |
| } |
| } |
| |
| @Override |
| public ReferenceLocation getLocation() { |
| if (element != null |
| && element.getSource() instanceof ILocationProvider) { |
| return ((ILocationProvider) element.getSource()).getLocation(); |
| } |
| return super.getLocation(); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + '<' + type + '>'; |
| } |
| } |
| |
| private static class MemberValue extends ElementValue implements IValue { |
| |
| private TypeValue functionOperator; |
| private final IRMember[] members; |
| |
| public MemberValue(IRMember[] members) { |
| assert members.length > 1; |
| this.members = members; |
| } |
| |
| @Override |
| protected IRMember[] getElements() { |
| return members; |
| } |
| |
| // @Override |
| // public IValue resolveValue() { |
| // if (members.length == 1) { |
| // final IValue value = resolveValue(members[0]); |
| // if (value != null) { |
| // // copy over the properties of this value. |
| // value.setDeclaredType(getDeclaredType()); |
| // value.setAttribute(IReferenceAttributes.ELEMENT, |
| // getAttribute(IReferenceAttributes.ELEMENT)); |
| // return value; |
| // } |
| // } |
| // return this; |
| // } |
| |
| @Override |
| public ReferenceKind getKind() { |
| for (IRMember member : members) { |
| if (member instanceof IRMethod) |
| return ReferenceKind.METHOD; |
| } |
| return ReferenceKind.PROPERTY; |
| } |
| |
| public IValue getChild(String name, boolean resolve) { |
| if (IValueReference.FUNCTION_OP.equals(name)) { |
| JSTypeSet types = null; |
| for (IRMember member : members) { |
| if (member instanceof IRMethod) { |
| final IRMethod method = (IRMethod) member; |
| if (method.getType() != null) { |
| if (types == null) { |
| types = JSTypeSet.create(); |
| } |
| types.add(method.getType()); |
| } |
| } |
| } |
| if (types != null) { |
| if (functionOperator == null) { |
| functionOperator = new TypeValue(types); |
| } |
| return functionOperator; |
| } |
| } |
| |
| IRType type = getDeclaredType(); |
| if (type != null) { |
| final IValue child = ElementValue.findMemberA(type, name, |
| resolve); |
| if (child != null) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| public IRType getDeclaredType() { |
| for (IRMember member : members) { |
| if (member instanceof IRProperty) { |
| final IRProperty property = (IRProperty) member; |
| if (property.getType() != null) { |
| return property.getType(); |
| } |
| } else if (member instanceof IRMethod) { |
| return RTypes.FUNCTION; |
| } |
| } |
| return null; |
| } |
| |
| public JSTypeSet getDeclaredTypes() { |
| JSTypeSet types = null; |
| for (IRMember member : members) { |
| if (member instanceof IRProperty) { |
| final IRProperty property = (IRProperty) member; |
| if (property.getType() != null) { |
| if (types == null) { |
| types = JSTypeSet.create(); |
| } |
| types.add(property.getType()); |
| } |
| } else if (member instanceof IRMethod) { |
| if (types == null) { |
| types = JSTypeSet.create(); |
| } |
| types.add(RTypes.FUNCTION); |
| } |
| } |
| if (types != null) { |
| return types; |
| } else { |
| return JSTypeSet.emptySet(); |
| } |
| } |
| |
| @Override |
| public Object getAttribute(String key, boolean includeReferences) { |
| if (IAssignProtection.ATTRIBUTE.equals(key)) { |
| for (IRMember member : members) { |
| if (member instanceof IRProperty) { |
| if (((IRProperty) member).isReadOnly()) { |
| return READONLY_PROPERTY; |
| } |
| } else if (member instanceof IRMethod |
| && member.getDeclaringType() == null) { |
| return UNASSIGNABLE_METHOD; |
| } |
| } |
| return null; |
| } |
| return super.getAttribute(key, includeReferences); |
| } |
| |
| } |
| |
| public ElementValue() { |
| } |
| |
| protected abstract Object getElements(); |
| |
| public IValue resolveValue() { |
| return this; |
| } |
| |
| @Internal |
| IValue resolveValue(IRMember member) { |
| final IRTypeDeclaration type = member.getDeclaringType(); |
| final ITypeSystem typeSystem = type != null ? type.getTypeSystem() |
| : ITypeSystem.CURRENT.get(); |
| return typeSystem != null ? typeSystem.valueOf(member) : null; |
| } |
| |
| public final void clear() { |
| } |
| |
| public final void addValue(IValue src) { |
| } |
| |
| public final void addReference(IValue src) { |
| } |
| |
| public void removeReference(IValue value) { |
| } |
| |
| public final Object getAttribute(String key) { |
| return getAttribute(key, false); |
| } |
| |
| public Object getAttribute(String key, boolean includeReferences) { |
| if (IReferenceAttributes.ELEMENT.equals(key)) { |
| return getElements(); |
| } |
| if (IReferenceAttributes.HIDE_ALLOWED.equals(key)) { |
| final Object elements = getElements(); |
| if (elements instanceof IRElement) { |
| final Object source = ((IRElement) elements).getSource(); |
| if (source instanceof Element) { |
| if (((Element) source).isHideAllowed()) { |
| return Boolean.TRUE; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| public final void setAttribute(String key, Object value) { |
| } |
| |
| public final Set<String> getDirectChildren() { |
| return getDirectChildren(IValue.DEFAULT); |
| } |
| |
| public Set<String> getDirectChildren(int flags) { |
| return Collections.emptySet(); |
| } |
| |
| public Set<String> getDeletedChildren() { |
| return Collections.emptySet(); |
| } |
| |
| public void deleteChild(String name, boolean force) { |
| } |
| |
| public final boolean hasChild(String name) { |
| return false; |
| } |
| |
| public final IValue createChild(String name, int flags) { |
| return getChild(name, true); |
| // throw new UnsupportedOperationException(); |
| } |
| |
| public void putChild(String name, IValue value) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public ReferenceKind getKind() { |
| return ReferenceKind.UNKNOWN; |
| } |
| |
| public ReferenceLocation getLocation() { |
| return ReferenceLocation.UNKNOWN; |
| } |
| |
| public JSTypeSet getTypes() { |
| return JSTypeSet.emptySet(); |
| } |
| |
| public final void setDeclaredType(IRType declaredType) { |
| } |
| |
| public void addType(IRType type) { |
| } |
| |
| public final void setKind(ReferenceKind kind) { |
| } |
| |
| public final void setLocation(ReferenceLocation location) { |
| } |
| } |