private SitecoreService BuildSitecoreService(Type controllerType) { var controller = new TypeViewer(controllerType); var service = new SitecoreService { Name = RemoveControllerSuffix(controllerType.FullName), Url = GetRouteFromType(controllerType), Definition = controller.ToJson(), CsrfProtection = controller.CheckForMitigations(ControllerType.WebAPI), Authorise = controller.CheckForAuthorise(ControllerType.WebAPI) }; var entityService = controllerType.GetGenericInterface(typeof(IEntityService <>)); if (entityService != null) { var pocoObject = entityService.GetGenericArguments()[0]; service.IsEntityService = true; service.Metadata = GetMetadata(pocoObject); } return(service); }
public void check_for_authorise_finds_derived_authorization_attributes() { var controllerViewer = new TypeViewer(typeof(AnalyticsDataController)); controllerViewer.CheckForAuthorise(ControllerType.WebAPI) .ShouldBeTrue(); }
private static Controller BuildController(ControllerWrapper wrapper) { System.Diagnostics.Debug.Assert(wrapper.ControllerType.HasValue); var typeViewer = new TypeViewer(wrapper.Type); return(new Controller( wrapper.Type.FullName, wrapper.ControllerType.Value, typeViewer.ToJson(), typeViewer.CheckForMitigations(wrapper.ControllerType.Value), typeViewer.CheckForAuthorise(wrapper.ControllerType.Value))); }
public static bool CheckForAuthorise(this TypeViewer typeViewer, ControllerType controllerType) { var webApiAuthorizeAttributeName = typeof(System.Web.Http.AuthorizeAttribute).Name; var mvcAuthorizeAttributeName = typeof(System.Web.Mvc.AuthorizeAttribute).Name; var attributeToDetect = (controllerType == ControllerType.MVC) ? mvcAuthorizeAttributeName : webApiAuthorizeAttributeName; var classValidation = typeViewer.HasClassAttribute(attributeToDetect); var methodValidation = typeViewer.HasMethodAttribute(attributeToDetect); return(classValidation || methodValidation); }
public static Csrf CheckForMitigations(this TypeViewer typeViewer, ControllerType controllerType) { const string webApiAntiForgeryAttributeName = "ValidateHttpAntiForgeryTokenAttribute"; var mvcAntiForgeryAttributeName = typeof(System.Web.Mvc.ValidateAntiForgeryTokenAttribute).Name; var attributeToDetect = (controllerType == ControllerType.MVC) ? mvcAntiForgeryAttributeName : webApiAntiForgeryAttributeName; var classValidation = typeViewer.HasClassAttribute(attributeToDetect); var methodValidation = typeViewer.HasMethodAttribute(attributeToDetect); return(classValidation ? Csrf.Class : methodValidation?Csrf.Method : Csrf.None); }
private void ShowViewer(TypeViewer viewer, ResourceData data) { #if !DEBUG try { viewer.RenderResource(data); } catch (AnolisException ex) { String exTemplate = "\r\nMessage:\r\n{0}\r\n\r\nStack Trace:\r\n{1}"; String message = "An unhandled exception was thrown whilst trying to load the resource.\r\n"; Exception e = ex; while (e != null) { message += String.Format(exTemplate, ex.Message, ex.StackTrace); e = e.InnerException; } DialogResult result = MessageBox.Show(this, message, "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2); if (result == DialogResult.Cancel) { return; } else { ShowViewer(viewer, data); } } #else viewer.RenderResource(data); #endif // don't load it if it's already the currently displayed viewer if (_currentViewer != viewer) { viewer.Dock = DockStyle.Fill; __viewer.Controls.Clear(); __viewer.Controls.Add(viewer); _currentViewer = viewer; } }
private void __viewers_SelectionChangeCommitted(object sender, EventArgs e) { TypeViewer viewer = (__viewers.SelectedItem as TypeViewerWrapper).Viewer; ShowViewer(viewer, _data); }
public virtual TypeNode GetStreamElementType(Expression x, TypeViewer typeViewer){ x = this.GetInnerExpression(x); if (x == null) return null; if (x.NodeType == NodeType.Composition) x = ((Composition)x).Expression; if (x == null) return null; TypeNode xt = TypeNode.StripModifiers(x.Type); TypeNode t = this.GetCollectionElementType(xt, typeViewer); if (t != null && (t != SystemTypes.Object || xt == SystemTypes.IEnumerable)) return t; t = this.GetStreamElementType(xt, typeViewer); if (t != xt && t != SystemTypes.Object) return t; switch (x.NodeType){ case NodeType.MethodCall: case NodeType.Call: case NodeType.Calli: case NodeType.Callvirt: { MethodCall mc = (MethodCall) x; MemberBinding mb = mc.Callee as MemberBinding; if (mb != null) { TypeNode mt = this.GetMemberElementType(mb.BoundMember, typeViewer); if (mt != null && mt != SystemTypes.Object) return mt; } break; } case NodeType.MemberBinding: { TypeNode mt = this.GetMemberElementType(((MemberBinding)x).BoundMember, typeViewer); if (mt != null && mt != SystemTypes.Object) return mt; break; } } return t; }
public virtual Cardinality GetCardinality(Expression collection, TypeViewer typeViewer) { if (collection == null) return Cardinality.None; if (collection is Literal && collection.Type == SystemTypes.Type) { return Cardinality.One; } TypeNode type = collection.Type; TypeAlias ta = type as TypeAlias; if (ta != null) type = ta.AliasedType; Cardinality card = this.GetCardinality(type, typeViewer); if ((card == Cardinality.None || card == Cardinality.One) && !(this.IsStructural(type) || type == SystemTypes.GenericNonNull)) { TypeNode elementType = this.GetStreamElementType(collection, typeViewer); if (elementType != type) { return Cardinality.ZeroOrMore; } } return card; }
/// <summary> /// Computes an upper bound in the type hierarchy for the set of argument types. /// This upper bound is a type that all types in the list are assignable to. /// If the types are all classes, then *the* least-upper-bound in the class /// hierarchy is returned. /// If the types contain at least one interface, then *a* deepest upper-bound /// is found from the intersection of the upward closure of each type. /// Note that if one of the types is System.Object, then that is immediately /// returned as the unified type without further examination of the list. /// </summary> /// <param name="ts">A list containing the set of types from which to compute the unified type.</param> /// <returns>The type corresponding to the least-upper-bound.</returns> public virtual TypeNode UnifiedType(TypeNodeList ts, TypeViewer typeViewer){ if (ts == null || ts.Count == 0) return null; TypeNode unifiedType = SystemTypes.Object; // default unified type bool atLeastOneInterface = false; #region If at least one of the types is System.Object, then that is the unified type for (int i = 0, n = ts.Count; i < n; i++){ TypeNode t = this.Unwrap(ts[i]); if (t == SystemTypes.Object){ return SystemTypes.Object; } } #endregion If at least one of the types is System.Object, then that is the unified type // assert forall{TypeNode t in ts; t != SystemTypes.Object}; #region See if any of the types are interfaces for (int i = 0, n = ts.Count; i < n; i++){ TypeNode t = this.Unwrap(ts[i]); if (t.NodeType == NodeType.Interface){ atLeastOneInterface = true; break; } } #endregion See if any of the types are interfaces #region Find the LUB in the class hierarchy (if there are no interfaces) if (!atLeastOneInterface){ TrivialHashtable h = new TrivialHashtable(ts.Count); // Create the list [s, .., t] for each element t of ts where for each item // in the list, t_i, t_i = t_{i+1}.BaseType. (s.BaseType == SystemTypes.Object) // Store the list in a hashtable keyed by t. // Do this only for classes. Handle interfaces in a different way because of // multiple inheritance. for (int i = 0, n = ts.Count; i < n; i++){ TypeNodeList tl = new TypeNodeList(); TypeNode t = this.Unwrap(ts[i]); tl.Add(t); TypeNode t2 = t.BaseType; while (t2 != null && t2 != SystemTypes.Object){ // avoid including System.Object in the list for classes tl.Insert(t2,0); t2 = this.Unwrap(t2.BaseType); } h[ts[i].UniqueKey] = tl; } bool stop = false; int depth = 0; while (!stop){ TypeNode putativeUnifiedType = null; int i = 0; int n = ts.Count; putativeUnifiedType = ((TypeNodeList) h[ts[0].UniqueKey])[depth]; while (i < n){ TypeNode t = ts[i]; TypeNodeList subTypes = (TypeNodeList) h[t.UniqueKey]; if (subTypes.Count <= depth || subTypes[depth] != putativeUnifiedType){ // either reached the top of the hierarchy for t_i or it is on a different branch // than the current one. stop = true; break; } i++; } if (i == n){ // made it all the way through: all types are subtypes of the current one unifiedType = putativeUnifiedType; } depth++; } } #endregion Find the LUB in the class hierarchy (if there are no interfaces) #region Find *a* LUB in the interface hierarchy (if there is at least one interface or current LUB is object) if (unifiedType == SystemTypes.Object || atLeastOneInterface){ TrivialHashtable interfaces = new TrivialHashtable(); for (int i = 0, n = ts.Count; i < n; i++){ InterfaceList il = new InterfaceList(); interfaces[ts[i].UniqueKey] = il; this.SupportedInterfaces(ts[i],il,typeViewer); // side-effect: il gets added to } // interfaces[ts[i]] is the upward closure of all of the interfaces supported by ts[i] // compute the intersection of all of the upward closures // might as well start with the first type in the list ts InterfaceList intersection = new InterfaceList(); InterfaceList firstIfaceList = (InterfaceList)interfaces[ts[0].UniqueKey]; for (int i = 0, n = firstIfaceList.Count; i < n; i++){ Interface iface = firstIfaceList[i]; bool found = false; int j = 1; // start at second type in the list ts while (j < ts.Count){ InterfaceList cur = (InterfaceList)interfaces[ts[j].UniqueKey]; found = false; for (int k = 0, p = cur.Count; k < p; k++){ if (cur[k] == iface){ found = true; break; } } if (!found){ // then the j-th type doesn't support iface, don't bother looking in the rest break; } j++; } if (found){ intersection.Add(iface); } } // TODO: take the "deepest" interface in the intersection. // "deepest" means that if any other type in the intersection is a subtype // of it, then *don't* consider it. if (intersection.Count > 0){ InterfaceList finalIntersection = new InterfaceList(intersection.Count); Interface iface = intersection[0]; for (int i = 0, n = intersection.Count; i < n; i++){ Interface curFace = intersection [i]; int j = 0; int m = intersection.Count; while (j < m){ if (j != i){ Interface jFace = intersection[j]; if (TypeViewer.GetTypeView(typeViewer, jFace).IsAssignableTo(curFace)) break; } j++; } if (j == m){ // made it all the way through, no other iface is a subtype of curFace finalIntersection.Add(curFace); } } if (finalIntersection.Count > 0){ unifiedType = finalIntersection[0]; // heuristic: just take the first one } } } #endregion Find *a* LUB in the interface hierarchy (if there is at least one interface or current LUB is object) return unifiedType; }
public virtual TypeNode GetStreamElementType(TypeNode t, TypeViewer typeViewer){ TypeNode originalT = t; TypeAlias ta = t as TypeAlias; while (ta != null) { t = ta.AliasedType; ta = t as TypeAlias; } if (t == null) return null; ArrayType aType = t as ArrayType; //REVIEW: should [] and {} participate in this? if (aType != null) return aType.ElementType; TypeNode template = t.Template; if (template == SystemTypes.GenericIEnumerable || template == SystemTypes.GenericIEnumerator || template == SystemTypes.GenericIList || template == SystemTypes.GenericList || template == SystemTypes.GenericNonEmptyIEnumerable || template == SystemTypes.GenericBoxed || template == SystemTypes.GenericNonNull || template == SystemTypes.GenericInvariant){ if (t.TemplateArguments != null && t.TemplateArguments.Count > 0) return t.TemplateArguments[0]; } if (TypeViewer.GetTypeView(typeViewer, t).IsAssignableTo(SystemTypes.Range)) return SystemTypes.Int32; if (TypeViewer.GetTypeView(typeViewer, t).IsAssignableTo(SystemTypes.IList)) return SystemTypes.Object; if (TypeViewer.GetTypeView(typeViewer, t).IsAssignableTo(SystemTypes.IDictionary)) return SystemTypes.Object; if (t is Interface) return originalT; InterfaceList ifaces = TypeViewer.GetTypeView(typeViewer, t).Interfaces; for (int i = 0, n = ifaces == null ? 0 : ifaces.Count; i < n; i++){ Interface iface = ifaces[i]; if (iface == null) continue; TypeNode eType = this.GetStreamElementType(iface, typeViewer); if (eType != iface) return eType; } return originalT; }
public virtual Literal ImplicitLiteralCoercion(Literal lit, TypeNode sourceType, TypeNode targetType, TypeViewer typeViewer) { try{ object val = System.Convert.ChangeType(lit.Value, targetType.TypeCode); return new Literal(val, targetType); }catch(InvalidCastException){ }catch(OverflowException){ }catch(FormatException){} this.HandleError(lit, Error.NoImplicitCoercionFromConstant, lit.SourceContext.SourceText, this.GetTypeName(targetType)); return null; }
/// <summary> /// Returns true if conversion from t3 to t1 exists and is better (closer) than the conversion from t3 to t2 /// Call this only if both conversions exist. /// </summary> public virtual bool IsBetterMatch(TypeNode t1, TypeNode t2, TypeNode t3, TypeViewer typeViewer){ if (t1 == null) return false; if (t2 == null || t2 == TypeSystem.DoesNotMatchAnyType) return true; //this type always loses if (t1 == t2) return false; if (t1 == t3) return true; //t2 is different from t3 while t1 == t3, so t1 must be a better match if (t2 == t3) return false; //t1 is different from t3, while t2 == t3, so t1 cannot be a better match //t3 can go to t1 and t2 only via conversions. Try to establish which conversion is better (closer). bool t1tot2 = this.ImplicitCoercionFromTo(t1, t2, typeViewer); bool t2tot1 = this.ImplicitCoercionFromTo(t2, t1, typeViewer); if (t1tot2 && !t2tot1) return this.ImplicitCoercionFromTo(t3, t1, typeViewer); //Can get from t3 to t2 via t1, but can't get from t3 to t1 via t2, so t3 is closer to t1 if (t2tot1 && !t1tot2) return !this.ImplicitCoercionFromTo(t3, t2, typeViewer); //Get get from t3 to t1 via t2, but can't get from t3 to t2 via t1, so t2 is closer to t1 //Special rule for integer types: //Prefer conversions to signed integers over conversions to unsigned integers. //But always prefer smaller int over larger int. switch (t1.TypeCode){ case TypeCode.SByte: switch (t2.TypeCode){ case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return true; } break; case TypeCode.Byte: switch (t2.TypeCode){ case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return true; case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return false; } break; case TypeCode.Int16: switch (t2.TypeCode){ case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int32: case TypeCode.Int64: return true; case TypeCode.SByte: return false; } break; case TypeCode.UInt16: switch (t2.TypeCode){ case TypeCode.UInt32: case TypeCode.UInt64: return true; case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return false; } break; case TypeCode.Int32: switch (t2.TypeCode){ case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Int64: return true; case TypeCode.SByte: case TypeCode.Int16: return false; } break; case TypeCode.UInt32: switch (t2.TypeCode){ case TypeCode.UInt64: return true; case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return false; } break; case TypeCode.Int64: switch (t2.TypeCode){ case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return true; case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: return false; } break; case TypeCode.UInt64: switch (t2.TypeCode){ case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return false; } break; } if (!t1.IsValueType && t2.IsValueType && t3 == SystemTypes.Object) return true; if (t1 is Pointer && !(t2 is Pointer) && t3 is Pointer && ((Pointer)t3).ElementType == SystemTypes.Void) return true; return false; }
protected virtual Expression StandardImplicitCoercion(Expression source, bool sourceIsNonNullType, TypeNode sourceType, bool targetIsNonNullType, TypeNode targetType, TypeNode originalTargetType, TypeViewer typeViewer){ if (Literal.IsNullLiteral(source)) { if (this.IsNullableType(targetType)) { Local temp = new Local(targetType); StatementList statements = new StatementList(); BlockExpression result = new BlockExpression(new Block(statements)); statements.Add(new AssignmentStatement(new AddressDereference(new UnaryExpression(temp, NodeType.AddressOf), targetType), new Literal(null, CoreSystemTypes.Object))); statements.Add(new ExpressionStatement(temp)); return result; } if (targetType.IsTemplateParameter && !targetType.IsReferenceType) { // Check for reference constraint this.HandleError(source, Error.TypeVarCantBeNull, targetType.Name.Name); return new Local(targetType); } } //Identity coercion if (sourceType == targetType && (!targetIsNonNullType || (targetIsNonNullType == sourceIsNonNullType))) return source; ITypeParameter stp = sourceType as ITypeParameter; ITypeParameter ttp = targetType as ITypeParameter; if (stp != null && ttp != null && stp.ParameterListIndex == ttp.ParameterListIndex && stp.DeclaringMember == ttp.DeclaringMember && (!targetIsNonNullType || (targetIsNonNullType == sourceIsNonNullType))) return source; if (source is This && targetType != null && sourceType == targetType.Template && targetType.IsNotFullySpecialized) //TODO: add check for sourceType.TemplateParameters == targetType.TemplateArguments return source; //Dereference source Reference sr = sourceType as Reference; if (sr != null){ sourceType = sr.ElementType; Pointer pType = targetType as Pointer; if (pType != null && this.StandardImplicitCoercionFromTo(null, sourceType, pType.ElementType, typeViewer)) return source; else if (pType != null && pType.ElementType == SystemTypes.Void) return source; bool sourceIsThis = source is This; source = new AddressDereference(source, sourceType, source.SourceContext); source.Type = sourceType; sourceIsNonNullType = this.IsNonNullType(sourceType); sourceType = TypeNode.StripModifier(sourceType, SystemTypes.NonNullType); //Special case for coercion of this in template class if (sourceIsThis && targetType != null && sourceType == targetType.Template && targetType.IsNotFullySpecialized) //TODO: add check for sourceType.TemplateParameters == targetType.TemplateArguments return source; } //Identity coercion after dereference if (sourceType == targetType && (!targetIsNonNullType || (targetIsNonNullType == sourceIsNonNullType))) return source; //Special case for null literal if (Literal.IsNullLiteral(source)){ if (targetIsNonNullType) return ImplicitNonNullCoercion(this.ErrorHandler, source, originalTargetType); if (targetType is ITypeParameter && this.useGenerics) return new BinaryExpression(source, new Literal(targetType, SystemTypes.Type), NodeType.UnboxAny); if (!targetType.IsValueType || targetType.Template == SystemTypes.GenericBoxed) return new Literal(null, targetType, source.SourceContext); if (this.IsNullableType(targetType)) return new Local(StandardIds.NewObj, targetType, source.SourceContext); TypeAlias tAlias = targetType as TypeAlias; if (tAlias != null){ if (tAlias.RequireExplicitCoercionFromUnderlyingType) return null; source = this.ImplicitCoercion(source, tAlias.AliasedType, typeViewer); if (source == null) return null; Method coercion = this.UserDefinedImplicitCoercionMethod(source, tAlias.AliasedType, targetType, false, typeViewer); if (coercion != null){ ExpressionList args = new ExpressionList(this.ImplicitCoercion(source, coercion.Parameters[0].Type, typeViewer)); return new MethodCall(new MemberBinding(null, coercion), args, NodeType.Call, coercion.ReturnType); } }else{ Method coercion = this.UserDefinedImplicitCoercionMethod(source, source.Type, targetType, true, typeViewer); if (coercion != null){ ExpressionList args = new ExpressionList(this.ImplicitCoercion(source, coercion.Parameters[0].Type, typeViewer)); return new MethodCall(new MemberBinding(null, coercion), args, NodeType.Call, coercion.ReturnType); } } this.HandleError(source, Error.CannotCoerceNullToValueType, this.GetTypeName(targetType)); return new Local(targetType); } //Special case for string literal if (source.NodeType == NodeType.Literal && sourceType == SystemTypes.String && (targetType.Template == SystemTypes.GenericNonNull || targetType.Template == SystemTypes.GenericInvariant) && this.GetStreamElementType(targetType, typeViewer) == SystemTypes.String) return this.ExplicitCoercion(source, targetType, typeViewer); //Implicit numeric coercions + implicit enumeration coercions + implicit constant expression coercions if (sourceType.IsPrimitive && sourceType != SystemTypes.String && (targetType.IsPrimitive || targetType == SystemTypes.Decimal || targetType is EnumNode)){ Expression primitiveCoercion = this.ImplicitPrimitiveCoercion(source, sourceType, targetType, typeViewer); if (primitiveCoercion != null) return primitiveCoercion; } //Implicit coercion from string literal to numbers or eums if (this.allowStringLiteralToOtherPrimitiveCoercion && sourceType == SystemTypes.String && (targetType.IsPrimitive || targetType == SystemTypes.Decimal || targetType is EnumNode)){ Expression primitiveCoercion = this.ImplicitPrimitiveCoercion(source, sourceType, targetType, typeViewer); if (primitiveCoercion != null) return primitiveCoercion; } //Implicit reference coercions if (TypeViewer.GetTypeView(typeViewer, sourceType).IsAssignableTo(targetType)){ if (targetIsNonNullType && !(sourceIsNonNullType) && !sourceType.IsValueType) { //Handling for non null types return ImplicitNonNullCoercion(this.ErrorHandler, source, originalTargetType); }else if (sourceType.IsValueType && !targetType.IsValueType){ if (sourceType.NodeType == NodeType.TypeUnion){ Debug.Assert(targetType == SystemTypes.Object); return this.CoerceTypeUnionToObject(source, typeViewer); } if (sourceType is TupleType){ if (targetType == SystemTypes.Object) return this.TupleCoercion(source, sourceType, targetType, false, typeViewer); }else if (targetType.Template != SystemTypes.GenericIEnumerable && this.GetStreamElementType(sourceType, typeViewer) != sourceType) return this.ExplicitCoercion(this.CoerceStreamToObject(source, sourceType, typeViewer), targetType, typeViewer); Expression e = new BinaryExpression(source, new MemberBinding(null, sourceType), NodeType.Box, targetType, source.SourceContext); e.Type = targetType; return e; }else if (this.useGenerics && (sourceType is TypeParameter || sourceType is ClassParameter)){ source = new BinaryExpression(source, new MemberBinding(null, sourceType), NodeType.Box, sourceType); if (targetType == SystemTypes.Object) return source; return new BinaryExpression(source, new MemberBinding(null, targetType), NodeType.UnboxAny, targetType); } else if (this.useGenerics && sourceType is ArrayType) { ArrayType sat = (ArrayType)sourceType; while (sat.ElementType is ArrayType) sat = (ArrayType)sat.ElementType; if (sat.ElementType is ITypeParameter) return new BinaryExpression(source, new MemberBinding(null, targetType), NodeType.Castclass, targetType, source.SourceContext); return source; }else return source; } //Special case for delegates if (targetType is DelegateNode) return this.CoerceToDelegate(source, sourceType, (DelegateNode)targetType, false, typeViewer); //Special case for type union to common base type if (sourceType.NodeType == NodeType.TypeUnion) return this.CoerceFromTypeUnion(source, (TypeUnion)sourceType, targetType, false, originalTargetType, typeViewer); //Special case for Type intersection target type if (targetType.NodeType == NodeType.TypeIntersection) return this.CoerceToTypeIntersection(source, sourceType, (TypeIntersection)targetType, false, typeViewer); //Special cases for typed streams Expression streamCoercion = this.StreamCoercion(source, sourceType, targetType, false, originalTargetType, typeViewer); if (streamCoercion != null) return streamCoercion; //Implicit tuple coercions return this.TupleCoercion(source, sourceType, targetType, false, typeViewer); }
public virtual Expression TupleCoercion(Expression source, TypeNode sourceType, TypeNode targetType, bool explicitCoercion, TypeViewer typeViewer){ TupleType sTuple = sourceType as TupleType; TupleType tTuple = targetType as TupleType; if (sTuple == null){ if (!explicitCoercion) return null; if (tTuple == null) return null; MemberList tMems = tTuple.Members; if (tMems == null || tMems.Count != 3) return null; ConstructTuple consTuple = new ConstructTuple(); consTuple.Type = tTuple; Field f = (Field)tMems[0].Clone(); consTuple.Fields = new FieldList(f); if (f.Type is TypeAlias) f.Initializer = this.ExplicitCoercion(source, f.Type, typeViewer); else f.Initializer = this.StandardExplicitCoercion(source, this.IsNonNullType(sourceType), sourceType, this.IsNonNullType(f.Type), f.Type, f.Type, typeViewer); if (f.Initializer == null) return null; return consTuple; } MemberList sMembers = sTuple.Members; if (sMembers == null) return null; int n = sMembers.Count; if (tTuple == null){ if (n == 3){ TypeUnion tUnion = targetType as TypeUnion; if (tUnion != null){ Method coercion = this.UserDefinedImplicitCoercionMethod(source, sourceType, targetType, true, typeViewer); if (coercion != null) return new MethodCall(new MemberBinding(null, coercion), new ExpressionList(this.ImplicitCoercion(source, coercion.Parameters[0].Type, typeViewer)), NodeType.Call, coercion.ReturnType, source.SourceContext); } Field sField = sMembers[0] as Field; if (sField == null || (!explicitCoercion && !this.ImplicitCoercionFromTo(sField.Type, targetType, typeViewer))) return null; if (!sField.IsAnonymous && targetType == SystemTypes.Object) return new BinaryExpression(source, new MemberBinding(null, sTuple), NodeType.Box, SystemTypes.Object); ConstructTuple cTuple = source as ConstructTuple; if (cTuple != null){ //TODO: give a warning source = cTuple.Fields[0].Initializer; }else{ MemberBinding mb = new MemberBinding(new UnaryExpression(source, NodeType.AddressOf), sField); mb.Type = sField.Type; source = mb; } if (explicitCoercion) return this.ExplicitCoercion(source, targetType, typeViewer); else return this.ImplicitCoercion(source, targetType, typeViewer); } if (targetType == SystemTypes.Object) return new BinaryExpression(source, new MemberBinding(null, sTuple), NodeType.Box, SystemTypes.Object); return null; } MemberList tMembers = tTuple.Members; if (sMembers == tMembers) return source; if (tMembers == null) return null; if (n != tMembers.Count) return null; n-=2; ConstructTuple consTup = source as ConstructTuple; if (consTup != null){ FieldList consFields = consTup.Fields; for (int i = 0; i < n; i++){ Field cField = consFields[i]; if (cField == null) continue; Field tField = tMembers[i] as Field; if (tField == null) return null; if (explicitCoercion) cField.Initializer = this.ExplicitCoercion(cField.Initializer, tField.Type, typeViewer); else{ if (!tField.IsAnonymous && tField.Name != null && (cField.IsAnonymous || cField.Name == null || cField.Name.UniqueIdKey != tField.Name.UniqueIdKey)) return null; cField.Initializer = this.ImplicitCoercion(cField.Initializer, tField.Type, typeViewer); } if (cField.Initializer == null) return null; cField.Type = tField.Type; } consTup.Type = tTuple; return consTup; } Local loc = new Local(sTuple); CoerceTuple cTup = new CoerceTuple(); cTup.OriginalTuple = source; cTup.Temp = loc; cTup.Type = tTuple; FieldList cFields = cTup.Fields = new FieldList(n); for (int i = 0; i < n; i++){ Field sField = sMembers[i] as Field; if (sField == null) return null; Field tField = tMembers[i] as Field; if (tField == null) return null; Field cField = new Field(); cField.Type = tField.Type; MemberBinding mb = new MemberBinding(loc, sField); if (explicitCoercion) cField.Initializer = this.ExplicitCoercion(mb, tField.Type, typeViewer); else{ if (!tField.IsAnonymous && tField.Name != null && (sField.IsAnonymous || sField.Name == null || sField.Name.UniqueIdKey != tField.Name.UniqueIdKey)) return null; cField.Initializer = this.ImplicitCoercion(mb, tField.Type, typeViewer); } if (cField.Initializer == null) return null; cFields.Add(cField); } return cTup; }
public virtual Expression ImplicitCoercion(Expression source, TypeNode targetType, TypeViewer typeViewer){ TypeNode originalTargetType = targetType; if (targetType == null || targetType.Name == Looker.NotFound) return source; if (source == null) return null; //HS D if (source is Hole) { source.Type = targetType; return source; } //HS D if (source is LambdaHole) { if (targetType == SystemTypes.Boolean) source = new LambdaHole(source, new Literal(0), NodeType.Ge, source.SourceContext); source.Type = targetType; return source; } Literal sourceLit = source as Literal; if (sourceLit != null && sourceLit.Value is TypeNode){ this.HandleError(source, Error.TypeInVariableContext, this.GetTypeName((TypeNode)sourceLit.Value), "class", "variable"); return null; } //Ignore parentheses if (source.NodeType == NodeType.Parentheses){ UnaryExpression uex = (UnaryExpression)source; uex.Operand = this.ImplicitCoercion(uex.Operand, targetType, typeViewer); if (uex.Operand == null) return null; uex.Type = uex.Operand.Type; return uex; } bool targetIsNonNullType = this.IsNonNullType(targetType); targetType = TypeNode.StripModifier(targetType, SystemTypes.NonNullType); targetType = TypeNode.StripModifier(targetType, SystemTypes.NullableType); //TODO: handle SkipCheck and EnforceCheck //Special case for closure expressions if (source.NodeType == NodeType.AnonymousNestedFunction) return this.CoerceAnonymousNestedFunction((AnonymousNestedFunction)source, targetType, false, typeViewer); TypeNode sourceType = source.Type; if (sourceType == null) sourceType = SystemTypes.Object; bool sourceIsNonNullType = this.IsNonNullType(source.Type); sourceType = TypeNode.StripModifier(sourceType, SystemTypes.NonNullType); sourceType = TypeNode.StripModifier(sourceType, SystemTypes.NullableType); if (sourceType == SystemTypes.String && !sourceIsNonNullType && source is Literal) sourceIsNonNullType = ((Literal)source).Value != null; if (this.currentParameter != null && targetType is Reference){ UnaryExpression uex = source as UnaryExpression; if (uex != null){ if (sourceIsNonNullType && !targetIsNonNullType){ string ttypeName = this.GetTypeName(targetType); string stypeName = this.GetTypeName(source.Type); this.HandleError(source, Error.NoImplicitCoercion, stypeName, ttypeName); return null; } if (!sourceIsNonNullType && targetIsNonNullType){ string ttypeName = this.GetTypeName(targetType); string stypeName = this.GetTypeName(source.Type); this.HandleError(source, Error.NoImplicitCoercion, stypeName, ttypeName); return null; } if (uex.NodeType == NodeType.OutAddress){ if ((this.currentParameter.Flags & ParameterFlags.Out) == 0){ this.currentParameter.Flags |= ParameterFlags.Out; string stypeName = this.GetTypeName(sourceType); this.currentParameter.Flags &= ~ParameterFlags.Out; this.HandleError(source, Error.NoImplicitCoercion, stypeName, this.GetTypeName(targetType)); return null; } }else if (uex.NodeType == NodeType.RefAddress){ if ((this.currentParameter.Flags & ParameterFlags.Out) != 0){ this.currentParameter.Flags &= ~ParameterFlags.Out; string stypeName = this.GetTypeName(sourceType); this.currentParameter.Flags |= ParameterFlags.Out; this.HandleError(source, Error.NoImplicitCoercion, stypeName, this.GetTypeName(targetType)); return null; } } } } Expression result = this.StandardImplicitCoercion(source, sourceIsNonNullType, sourceType, targetIsNonNullType, targetType, originalTargetType, typeViewer); if (result != null) return result; Method coercion = this.UserDefinedImplicitCoercionMethod(source, sourceType, targetType, true, typeViewer); if (coercion != null){ if (this.IsNullableType(targetType) && this.IsNullableType(sourceType) && !this.IsNullableType(coercion.Parameters[0].Type)) return this.CoerceWithLiftedCoercion(source, sourceType, targetType, coercion, false, typeViewer); ExpressionList args = new ExpressionList(1); args.Add(this.ImplicitCoercion(source, coercion.Parameters[0].Type, typeViewer)); return this.ImplicitCoercion(new MethodCall(new MemberBinding(null, coercion), args, NodeType.Call, coercion.ReturnType, source.SourceContext), targetType, typeViewer); } if (sourceType == SystemTypes.Type && source is Literal) this.HandleError(source, Error.TypeInVariableContext, this.GetTypeName((TypeNode)((Literal)source).Value), "class", "variable"); else if (this.IsNullableType(sourceType) && this.IsNullableType(targetType) && this.ImplicitCoercionFromTo(this.RemoveNullableWrapper(sourceType), this.RemoveNullableWrapper(targetType))) { TypeNode usType = this.RemoveNullableWrapper(sourceType); TypeNode utType = this.RemoveNullableWrapper(targetType); Local tempSrc = new Local(sourceType); Local tempTar = new Local(targetType); StatementList statements = new StatementList(); BlockExpression result1 = new BlockExpression(new Block(statements)); statements.Add(new AssignmentStatement(tempSrc, source)); Method hasValue = sourceType.GetMethod(StandardIds.getHasValue); Method getValueOrDefault = sourceType.GetMethod(StandardIds.GetValueOrDefault); Method ctor = targetType.GetMethod(StandardIds.Ctor, utType); Block pushValue = new Block(); Block done = new Block(); Expression tempHasValue = new MethodCall(new MemberBinding(new UnaryExpression(tempSrc, NodeType.AddressOf), hasValue), null); tempHasValue.Type = SystemTypes.Boolean; statements.Add(new Branch(tempHasValue, pushValue)); statements.Add(new AssignmentStatement(new AddressDereference(new UnaryExpression(tempTar, NodeType.AddressOf), targetType), new Literal(null, CoreSystemTypes.Object))); statements.Add(new Branch(null, done)); statements.Add(pushValue); Expression value = new MethodCall(new MemberBinding(new UnaryExpression(tempSrc, NodeType.AddressOf), getValueOrDefault), null); value.Type = usType; value = this.ImplicitCoercion(value, utType); Construct cons = new Construct(new MemberBinding(null, ctor), new ExpressionList(value)); result1.Type = ctor.DeclaringType; statements.Add(new AssignmentStatement(tempTar, cons)); statements.Add(done); statements.Add(new ExpressionStatement(tempTar)); return result1; }else this.HandleError(source, Error.NoImplicitCoercion, this.GetTypeName(sourceType), this.GetTypeName(originalTargetType)); return null; }
public virtual Expression CoerceWithLiftedCoercion(Expression source, TypeNode sourceType, TypeNode targetType, Method coercion, bool explicitCoercion, TypeViewer typeViewer){ if (source == null || sourceType == null || targetType == null || coercion == null){Debug.Assert(false); return null;} Block nullCase = new Block(new StatementList(1)); Block nonNullCase = new Block(new StatementList(1)); Block done = new Block(); Block coercionBlock = new Block(new StatementList(7)); Local copyOfSource = new Local(source.Type); Local result = new Local(targetType); //null case StatementList statements = nullCase.Statements; statements.Add(new AssignmentStatement(result, new Local(StandardIds.NewObj, targetType))); //nonNull case statements = nonNullCase.Statements; Method getValue = TypeViewer.GetTypeView(typeViewer, sourceType).GetMethod(Identifier.For("get_Value")); Expression getVal = new MethodCall( new MemberBinding(new UnaryExpression(copyOfSource, NodeType.AddressOf, TypeViewer.GetTypeView(typeViewer, sourceType).GetReferenceType()), getValue), null, NodeType.Call, getValue.ReturnType); if (explicitCoercion) getVal = this.ExplicitCoercion(getVal, coercion.Parameters[0].Type, typeViewer); else getVal = this.ImplicitCoercion(getVal, coercion.Parameters[0].Type, typeViewer); if (getVal == null) return null; Expression nonNullVal = new MethodCall(new MemberBinding(null, coercion), new ExpressionList(getVal), NodeType.Call, coercion.ReturnType); statements.Add(new AssignmentStatement(result, this.ImplicitCoercion(nonNullVal, targetType, typeViewer))); //coercion block statements = coercionBlock.Statements; statements.Add(new AssignmentStatement(copyOfSource, source)); Method hasValue = TypeViewer.GetTypeView(typeViewer, sourceType).GetMethod(StandardIds.getHasValue); if (hasValue == null){Debug.Assert(false); return null;} Expression ifNonNull = new MethodCall( new MemberBinding(new UnaryExpression(copyOfSource, NodeType.AddressOf, TypeViewer.GetTypeView(typeViewer, sourceType).GetReferenceType()), hasValue), null, NodeType.Call); statements.Add(new Branch(ifNonNull, nonNullCase)); statements.Add(nullCase); statements.Add(new Branch(null, done)); statements.Add(nonNullCase); statements.Add(done); statements.Add(new ExpressionStatement(result)); return new BlockExpression(coercionBlock, targetType); }
public virtual Expression TryImplicitCoercion(Expression source, TypeNode targetType, TypeViewer typeViewer) { ErrorHandler oldEH = this.ErrorHandler; this.ErrorHandler = null; Expression e = null; try { e = this.ImplicitCoercion(source, targetType, typeViewer); } finally { this.ErrorHandler = oldEH; }; return e; }
protected virtual Method UserDefinedExplicitCoercionMethod(Expression source, TypeNode sourceType, TypeNode targetType, bool tryStandardCoercions, TypeNode originalTargetType, TypeViewer typeViewer){ Reference rtype = sourceType as Reference; if (rtype != null) sourceType = rtype.ElementType; if (sourceType == targetType) return null; //First do efficient searches for a method that coerces directly between source and target type //If the source type knows how to convert to the target type, give it preference Method coercion = TypeViewer.GetTypeView(typeViewer, sourceType).GetExplicitCoercionToMethod(targetType); if (coercion != null) return coercion; coercion = TypeViewer.GetTypeView(typeViewer, sourceType).GetImplicitCoercionToMethod(targetType); if (coercion != null) return coercion; //If the target type knows how to convert from the source type, that is dandy too coercion = TypeViewer.GetTypeView(typeViewer, targetType).GetExplicitCoercionFromMethod(sourceType); if (coercion != null) return coercion; coercion = TypeViewer.GetTypeView(typeViewer, targetType).GetImplicitCoercionFromMethod(sourceType); if (coercion != null) return coercion; //Perhaps the base type can convert to the target type, or the target type can convert from the base type if (sourceType.BaseType != null){ coercion = this.UserDefinedExplicitCoercionMethod(source, sourceType.BaseType, targetType, false, originalTargetType, typeViewer); if (coercion != null) return coercion; } if (!tryStandardCoercions) return null; //Now resort to desperate measures //See if the target type has a conversion that can convert the source after a standard coercion has been applied MemberList coercions = TypeViewer.GetTypeView(typeViewer, targetType).ExplicitCoercionMethods; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ coercion = coercions[i] as Method; if (coercion == null) continue; if (coercion.ReturnType != targetType) continue; ParameterList pars = coercion.Parameters; if (pars == null || pars.Count != 1) continue; Parameter par = pars[0]; if (par == null) continue; if (sourceType == par.Type) return coercion; if (this.StandardExplicitCoercion(source, this.IsNonNullType(sourceType), sourceType, this.IsNonNullType(par.Type), par.Type, par.Type, typeViewer) != null) return coercion; //REVIEW: choose the best of the bunch? } coercions = TypeViewer.GetTypeView(typeViewer, targetType).ImplicitCoercionMethods; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ coercion = coercions[i] as Method; if (coercion == null) continue; if (coercion.ReturnType != targetType) continue; ParameterList pars = coercion.Parameters; if (pars == null || pars.Count != 1) continue; Parameter par = pars[0]; if (par == null) continue; if (sourceType == par.Type) return coercion; if (this.StandardExplicitCoercion(source, this.IsNonNullType(sourceType), sourceType, this.IsNonNullType(par.Type), par.Type, par.Type, typeViewer) != null) return coercion; //REVIEW: choose the best of the bunch? } //See if the source type has a conversion that results in a type that can be converted to the target type via a standard coercion TypeNode tgtType = targetType; if (targetType is EnumNode) tgtType = ((EnumNode)targetType).UnderlyingType; coercions = TypeViewer.GetTypeView(typeViewer, sourceType).ExplicitCoercionMethods; TypeNode bestSoFar = null; coercion = null; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ Method m = coercions[i] as Method; if (m == null) continue; TypeNode rType = m.ReturnType; if (rType == sourceType) continue; if (this.StandardImplicitCoercionFromTo(null, rType, targetType, typeViewer)) return m; if (this.StandardExplicitCoercion(source, this.IsNonNullType(rType), rType, this.IsNonNullType(targetType), targetType, originalTargetType, typeViewer) != null){ //Possible information loss, try to choose the least bad coercion if (bestSoFar == null || this.IsBetterMatch(tgtType, bestSoFar, rType, typeViewer)){ coercion = m; bestSoFar = rType; } } } coercions = TypeViewer.GetTypeView(typeViewer, sourceType).ImplicitCoercionMethods; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ Method m = coercions[i] as Method; if (m == null) continue; TypeNode rType = m.ReturnType; if (rType == sourceType) continue; if (this.StandardImplicitCoercionFromTo(null, rType, targetType, typeViewer)) return m; if (this.StandardExplicitCoercion(source, this.IsNonNullType(rType), rType, this.IsNonNullType(targetType), targetType, originalTargetType, typeViewer) != null){ if (bestSoFar == null || this.IsBetterMatch(tgtType, bestSoFar, rType, typeViewer)){ coercion = m; bestSoFar = rType; } } } if (coercion != null) return coercion; //TODO: pass this into the recursive call //Perhaps the base type can convert to the target type, or the target type can convert from the base type, via standard coercions if (sourceType.BaseType != null){ coercion = this.UserDefinedExplicitCoercionMethod(source, sourceType.BaseType, targetType, true, originalTargetType, typeViewer); if (coercion != null) return coercion; } //Since this is an explicit coercion, try converting to the base type of the target type if (targetType.BaseType != null){ coercion = this.UserDefinedExplicitCoercionMethod(source, sourceType, targetType.BaseType, true, originalTargetType, typeViewer); if (coercion != null) return coercion; } return null; }
public override Literal ImplicitLiteralCoercion(Literal lit, TypeNode sourceType, TypeNode targetType, TypeViewer typeViewer) { return(this.LiteralCoercion(lit, sourceType, targetType, false, targetType, typeViewer, false)); }
private Literal LiteralCoercion(Literal /*!*/ lit, TypeNode sourceType, TypeNode targetType, bool explicitCoercion, TypeNode originalTargetType, TypeViewer typeViewer, bool forLabel) { if (sourceType == targetType) { if (sourceType == lit.Type) { return(lit); } return(new Literal(Convert.ChangeType(lit.Value, sourceType.TypeCode), sourceType, lit.SourceContext)); } object val = lit.Value; EnumNode eN = targetType as EnumNode; if (eN != null) { if (sourceType.IsPrimitiveInteger && val is IConvertible && ((IConvertible)val).ToDouble(null) == 0.0) { if (eN.UnderlyingType == SystemTypes.Int64 || eN.UnderlyingType == SystemTypes.UInt64) { val = 0L; } else { val = 0; } return(new Literal(val, eN, lit.SourceContext)); } goto error; } if (targetType.TypeCode == TypeCode.Boolean) { this.HandleError(lit, Error.ConstOutOfRange, lit.SourceContext.SourceText, "bool"); lit.SourceContext.Document = null; return(null); } if (targetType.TypeCode == TypeCode.String) { if (val != null || lit.Type != SystemTypes.Object) { this.HandleError(lit, Error.NoImplicitConversion, this.GetTypeName(sourceType), this.GetTypeName(targetType)); lit.SourceContext.Document = null; return(null); } return(lit); } if (targetType.TypeCode == TypeCode.Object) { if (val == null && sourceType == SystemTypes.Object && (explicitCoercion || !this.IsNonNullType(targetType))) { return(lit); } if (val is string && this.IsNonNullType(targetType) && TypeNode.StripModifiers(targetType) == SystemTypes.String) { return(lit); } Method coercion = null; if (explicitCoercion) { coercion = this.UserDefinedExplicitCoercionMethod(lit, sourceType, targetType, true, originalTargetType, typeViewer); } else { coercion = this.UserDefinedImplicitCoercionMethod(lit, sourceType, targetType, true, typeViewer); } if (coercion != null) { return(null); } this.HandleError(lit, Error.NoImplicitConversion, this.GetTypeName(sourceType), this.GetTypeName(targetType)); lit.SourceContext.Document = null; return(null); } if ((targetType.TypeCode == TypeCode.Char || sourceType.TypeCode == TypeCode.Boolean || sourceType.TypeCode == TypeCode.Decimal) && !forLabel) { goto error; } switch (sourceType.TypeCode) { case TypeCode.Double: switch (targetType.TypeCode) { case TypeCode.Single: this.HandleError(lit, Error.LiteralDoubleCast, "float", "F"); return(lit); case TypeCode.Decimal: this.HandleError(lit, Error.LiteralDoubleCast, "decimal", "M"); return(lit); default: this.HandleError(lit, Error.NoImplicitConversion, this.GetTypeName(sourceType), this.GetTypeName(targetType)); lit.SourceContext.Document = null; return(null); } case TypeCode.Single: switch (targetType.TypeCode) { case TypeCode.Double: break; default: this.HandleError(lit, Error.NoImplicitConversion, this.GetTypeName(sourceType), this.GetTypeName(targetType)); lit.SourceContext.Document = null; return(null); } break; case TypeCode.Int64: case TypeCode.UInt64: switch (targetType.TypeCode) { case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Decimal: case TypeCode.Single: case TypeCode.Double: break; default: if (explicitCoercion || !lit.TypeWasExplicitlySpecifiedInSource) { break; } this.HandleError(lit, Error.NoImplicitConversion, this.GetTypeName(sourceType), this.GetTypeName(targetType)); lit.SourceContext.Document = null; return(null); } break; } try{ if (val == null) { if (targetType.IsValueType) { goto error; } } else { val = System.Convert.ChangeType(val, targetType.TypeCode); } return(new Literal(val, targetType, lit.SourceContext)); }catch (InvalidCastException) { }catch (OverflowException) { }catch (FormatException) {} error: if (sourceType.IsPrimitiveNumeric && lit.SourceContext.Document != null) { Error e = Error.ConstOutOfRange; if (explicitCoercion) { e = Error.ConstOutOfRangeChecked; } this.HandleError(lit, e, lit.SourceContext.SourceText, this.GetTypeName(targetType)); } else { this.HandleError(lit, Error.NoImplicitConversion, this.GetTypeName(sourceType), this.GetTypeName(targetType)); } if (this.ErrorHandler != null) { lit.SourceContext.Document = null; } return(null); }
public virtual bool ImplicitCoercionToIntersection(TypeNode sourceType, TypeIntersection intersect, TypeViewer typeViewer){ if (intersect == null) return false; TypeNodeList types = intersect.Types; for (int i = 0, n = types == null ? 0 : types.Count; i < n; i++){ TypeNode t = types[i]; if (t == null) continue; if (!this.ImplicitCoercionFromTo(sourceType, t, typeViewer)) return false; } return true; }
public virtual Expression ImplicitPrimitiveCoercion(Expression source, TypeNode sourceType, TypeNode targetType, TypeViewer typeViewer){ if (this.insideUnsafeCode && (targetType == SystemTypes.IntPtr || targetType == SystemTypes.UIntPtr)) return this.ImplicitPrimitiveCoercionHelper(source, sourceType, targetType); Literal lit = source as Literal; if (lit != null) return this.ImplicitLiteralCoercion(lit, sourceType, targetType, typeViewer); Expression result = this.ImplicitPrimitiveCoercionHelper(source, sourceType, targetType); if (result != null) result.Type = targetType; return result; }
public virtual Expression CoerceToTypeIntersection(Expression source, TypeNode sourceType, TypeIntersection targetType, bool explicitCoercion, TypeViewer typeViewer){ if (source == null || sourceType == null || targetType == null) return null; if (!explicitCoercion){ TypeNodeList types = targetType.Types; for (int i = 0, n = types == null ? 0 : types.Count; i < n; i++){ TypeNode t = types[i]; if (t == null) continue; if (!TypeViewer.GetTypeView(typeViewer, sourceType).IsAssignableTo(t)) return null; } } Method fromObject = TypeViewer.GetTypeView(typeViewer, targetType).GetMethod(StandardIds.FromObject, SystemTypes.Object); Method getType = Runtime.GetType; MethodCall fromObjectCall = new MethodCall(new MemberBinding(null, fromObject), new ExpressionList(source), NodeType.Call); fromObjectCall.Type = targetType; return fromObjectCall; }
public virtual Method UserDefinedImplicitCoercionMethod(Expression source, TypeNode sourceType, TypeNode targetType, bool tryStandardCoercions, TypeViewer typeViewer){ Reference rtype = sourceType as Reference; if (rtype != null) sourceType = rtype.ElementType; if (tryStandardCoercions && this.IsNullableType(sourceType) && this.IsNullableType(targetType)) { sourceType = sourceType.TemplateArguments[0]; targetType = targetType.TemplateArguments[0]; } //First do efficient searches for a method that implicitly coerces directly between source and target type //If the source type knows how to convert to the target type, give it preference Method coercion = TypeViewer.GetTypeView(typeViewer, sourceType).GetImplicitCoercionToMethod(targetType); if (coercion != null) return coercion; //If the target type knows how to convert from the source type, that is dandy too coercion = TypeViewer.GetTypeView(typeViewer, targetType).GetImplicitCoercionFromMethod(sourceType); if (coercion != null) return coercion; //Perhaps the base type can convert to the target type, or the target type can convert from the base type if (sourceType.BaseType != null && sourceType != SystemTypes.Object){ coercion = this.UserDefinedImplicitCoercionMethod(source, sourceType.BaseType, targetType, tryStandardCoercions, typeViewer); if (coercion != null) return coercion; } if (!tryStandardCoercions) return null; //Now resort to desperate measures //See if the source type has a conversion that results in a type that can be converted to the target type via a standard coercion MemberList coercions = TypeViewer.GetTypeView(typeViewer, sourceType).ImplicitCoercionMethods; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ coercion = coercions[i] as Method; if (coercion == null) continue; if (coercion.ReturnType == sourceType) continue; if (this.StandardImplicitCoercionFromTo(source, coercion.ReturnType, targetType, typeViewer)) return coercion; } //See if the target type has a conversion that can convert the source after a standard coercion has been applied coercions = TypeViewer.GetTypeView(typeViewer, targetType).ImplicitCoercionMethods; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ coercion = coercions[i] as Method; if (coercion == null) continue; if (coercion.ReturnType != targetType) continue; ParameterList pars = coercion.Parameters; if (pars == null || pars.Count != 1) continue; Parameter par = pars[0]; if (par.Type == null) continue; if (this.StandardImplicitCoercionFromTo(source, sourceType, par.Type, typeViewer)) return coercion; } return null; }
public virtual Expression CoerceObjectToTypeUnion(Expression source, TypeUnion targetType, TypeViewer typeViewer){ Method fromObject = TypeViewer.GetTypeView(typeViewer, targetType).GetMethod(StandardIds.FromObject, SystemTypes.Object, SystemTypes.Type); Method getType = Runtime.GetType; ExpressionList arguments = new ExpressionList(2); arguments.Add(source); arguments.Add(new MethodCall(new MemberBinding(new Expression(NodeType.Dup), getType), null, NodeType.Call)); MethodCall fromObjectCall = new MethodCall(new MemberBinding(null, fromObject), arguments, NodeType.Call); fromObjectCall.Type = targetType; return fromObjectCall; }
public virtual TypeNode UnifiedType(Literal lit, TypeNode t, TypeViewer typeViewer){ if (lit == null || lit.Type == null || t == null){Debug.Assert(false); return SystemTypes.Object;} t = this.Unwrap(t); MemberList coercions = TypeViewer.GetTypeView(typeViewer, t).ImplicitCoercionMethods; for (int i = 0, n = coercions == null ? 0 : coercions.Count; i < n; i++){ Method coercion = coercions[i] as Method; if (coercion == null) continue; TypeNode t2 = coercion.ReturnType; if (t2 == t || t2 == null || !t2.IsPrimitive) continue; if (this.ImplicitLiteralCoercionFromTo(lit, lit.Type, t2)) return t2; } return this.UnifiedType(lit.Type, t); }
public virtual Expression CoerceToTypeUnion(Expression source, TypeNode sourceType, TypeUnion targetType, TypeViewer typeViewer){ if (source == null || sourceType == null || targetType == null) return null; if (this.UserDefinedImplicitCoercionMethod(source, sourceType, targetType, true, typeViewer) != null) return null; TypeUnion tType = targetType.UnlabeledUnion; if (tType == null) return null; Method coercion = this.UserDefinedImplicitCoercionMethod(source, sourceType, tType, true, typeViewer); if (coercion == null) return null; //No coercion possible TypeNode chosenType = coercion.Parameters[0].Type; TypeNodeList types1 = tType.Types; TypeNodeList types2 = targetType.Types; for (int i = 0, n = types1.Count; i < n; i++){ TypeNode t = types1[i]; if (t == chosenType){ source = this.ExplicitCoercion(source, types2[i], typeViewer); if (source == null) return null; return this.ExplicitCoercion(source, targetType, typeViewer); } } Debug.Assert(false); return null; }
public virtual void SupportedInterfaces(TypeNode t, InterfaceList ifaceList, TypeViewer typeViewer){ if (ifaceList == null) return; TypeNode unwrappedT = this.Unwrap(t); Interface iface = unwrappedT as Interface; if (iface != null){ // possibly not needed, but seems better to keep ifaceList as a set int i = 0; while (i < ifaceList.Count){ if (ifaceList[i] == iface) break; i++; } if (i == ifaceList.Count) // not found ifaceList.Add(iface); }else{ // nop } InterfaceList ifaces = TypeViewer.GetTypeView(typeViewer, unwrappedT).Interfaces; for (int i = 0, n = ifaces == null ? 0 : ifaces.Count; i < n; i++){ this.SupportedInterfaces(ifaces[i],ifaceList,typeViewer); } return; }
public static bool NotAccessible(Member member, ref TypeNode qualifierType, Module currentModule, TypeNode currentType, TypeViewer typeViewer) { if (member == null) return false; switch (member.NodeType) { case NodeType.Field: return Checker.NotAccessible(member, ref qualifierType, (int)(((Field)member).Flags & FieldFlags.FieldAccessMask), currentModule, currentType, typeViewer); case NodeType.InstanceInitializer: case NodeType.Method: return Checker.NotAccessible(member, ref qualifierType, (int)(((Method)member).Flags & MethodFlags.MethodAccessMask), currentModule, currentType, typeViewer); case NodeType.Property: Property p = (Property)member; return Checker.NotAccessible(member, ref qualifierType, (int)(Method.GetVisibilityUnion(p.Getter, p.Setter) & MethodFlags.MethodAccessMask), currentModule, currentType, typeViewer); case NodeType.Event: Event e = (Event)member; return Checker.NotAccessible(member, ref qualifierType, (int)(Method.GetVisibilityUnion(e.HandlerAdder, e.HandlerRemover) & MethodFlags.MethodAccessMask), currentModule, currentType, typeViewer); } return false; }
public virtual TypeNode GetCollectionElementType(TypeNode t, TypeViewer typeViewer){ bool foundObject = false; TypeAlias ta = t as TypeAlias; while (ta != null){t = ta.AliasedType; ta = t as TypeAlias;} if (t == null || t == SystemTypes.String || t is TupleType) return null; // look for get_Item indexer MemberList list = TypeViewer.GetTypeView(typeViewer, t).GetMembersNamed(StandardIds.getItem); if (list != null) { for( int i = 0, n = list.Count; i < n; i++ ) { Method m = list[i] as Method; if (m == null) continue; if (m.ReturnType != SystemTypes.Object) return m.ReturnType; foundObject = true; } } // look for enumerable pattern Method mge = TypeViewer.GetTypeView(typeViewer, t).GetMethod(StandardIds.GetEnumerator); if (mge != null) { Method mgc = TypeViewer.GetTypeView(typeViewer, mge.ReturnType).GetMethod(StandardIds.getCurrent); if (mgc != null) { if (mgc.ReturnType != SystemTypes.Object) return mgc.ReturnType; foundObject = true; } } InterfaceList ilist = TypeViewer.GetTypeView(typeViewer, t).Interfaces; if (ilist != null) { for( int i = 0, n = ilist.Count; i < n; i++ ) { Interface iface = ilist[i]; if (iface == null) continue; TypeNode tn = this.GetCollectionElementType(iface, typeViewer); if (tn == null) continue; if (tn != SystemTypes.Object) return tn; foundObject = true; } } if (foundObject) return SystemTypes.Object; if (t.BaseType != null && t.BaseType != SystemTypes.Object) { return this.GetCollectionElementType(t.BaseType, typeViewer); } return null; }
public static bool NotAccessible(Member member, TypeNode type, ref TypeNode qualifierType, int visibility, Module currentModule, TypeNode currentType, TypeViewer typeViewer) { if (type == null) return false; TypeNode effectiveType = type.EffectiveTypeNode; if ((object)effectiveType != (object)type) { // the member being accessed is declared in a type extension; also see whether the member // would be accessible if it were considered declared in the extendee type if (!NotAccessible(member, effectiveType, ref qualifierType, visibility, currentModule, currentType, typeViewer)) { return false; } } TypeNode effectiveCurrentType = currentType == null ? null : currentType.EffectiveTypeNode; if ((object)effectiveCurrentType != (object)currentType) { // the member is being accessed from a type extension; see whether the member // would be accessible if it were being accessed from the extendee type // [v-craigc-TODO: consider inaccessible any members not visible according to the // accessibility claimed by the extension; the current code implicitly grants private // access to extensions] if (!NotAccessible(member, type, ref qualifierType, visibility, currentModule, effectiveCurrentType, typeViewer)) { return false; } } TypeNode template = type; while (template.Template != null) { if (template.Template == template) { Debug.Assert(false); template.Template = null; break; } template = template.Template; } TypeNode t = currentType; while (t != null && t.Template != null) { if (t.Template == t) { Debug.Assert(false); t.Template = null; break; } t = t.Template; } while (t != null) { if (t == template) { switch ((FieldFlags)visibility) { case FieldFlags.FamANDAssem: case FieldFlags.Family: while (qualifierType != null && qualifierType.Template != null) qualifierType = qualifierType.Template; if (qualifierType != null && !TypeViewer.GetTypeView(typeViewer, qualifierType).IsAssignableTo(t) && !TypeViewer.GetTypeView(typeViewer, qualifierType).IsAssignableToInstanceOf(t)) { qualifierType = null; return true; } break; } return false; } t = t.DeclaringType; } switch ((FieldFlags)visibility) { case FieldFlags.Assembly: return !Checker.InternalsAreVisible(currentModule, type.DeclaringModule); case FieldFlags.FamANDAssem: if (!Checker.InternalsAreVisible(currentModule, type.DeclaringModule)) return true; goto case FieldFlags.Family; case FieldFlags.Family: if (currentType == null || !TypeViewer.GetTypeView(typeViewer, currentType).IsAssignableTo(type)) { if (currentType != null && currentType.DeclaringType != null) return Checker.NotAccessible(member, ref qualifierType, currentModule, currentType.DeclaringType, typeViewer); return true; } while (qualifierType != null && qualifierType.Template != null) qualifierType = qualifierType.Template; if (qualifierType != null && !TypeViewer.GetTypeView(typeViewer, qualifierType).IsAssignableTo(currentType) && !TypeViewer.GetTypeView(typeViewer, qualifierType).IsAssignableToInstanceOf(currentType)) { qualifierType = null; return true; } return false; case FieldFlags.FamORAssem: if (Checker.InternalsAreVisible(currentModule, type.DeclaringModule)) return false; goto case FieldFlags.Family; case FieldFlags.Private: return true; case FieldFlags.Public: return false; } return false; }
public virtual TypeNode GetMemberElementType(Member member, TypeViewer typeViewer) { if (member == null) return null; AttributeNode attr = MetadataHelper.GetCustomAttribute(member, SystemTypes.ElementTypeAttribute); if (attr != null){ Literal litType = MetadataHelper.GetNamedAttributeValue(attr, StandardIds.ElementType); if (litType != null) return litType.Value as TypeNode; } return this.GetStreamElementType(this.GetMemberType(member), typeViewer); }
public override Expression ExplicitLiteralCoercion(Literal lit, TypeNode sourceType, TypeNode targetType, TypeViewer typeViewer) { if (sourceType == targetType && (sourceType == SystemTypes.Double || sourceType == SystemTypes.Single)) { return(lit); } TypeNode originalTargetType = targetType; EnumNode sourceEnum = sourceType as EnumNode; if (sourceEnum != null) { sourceType = sourceEnum.UnderlyingType; } bool needsRuntimeCoercion = this.suppressOverflowCheck; if (!sourceType.IsPrimitiveInteger || sourceType == SystemTypes.IntPtr || sourceType == SystemTypes.UIntPtr) { needsRuntimeCoercion = true; } else if (!targetType.IsPrimitiveInteger || targetType == SystemTypes.IntPtr || targetType == SystemTypes.UIntPtr) { needsRuntimeCoercion = true; } if (needsRuntimeCoercion) { if (lit != null && lit.Value != null) { targetType = TypeNode.StripModifier(targetType, SystemTypes.NonNullType); } return(this.ExplicitCoercion(lit, targetType, typeViewer)); } else { return(this.LiteralCoercion(lit, sourceType, targetType, true, originalTargetType, null, false)); } }
public virtual Cardinality GetCardinality(TypeNode collectionType, TypeViewer typeViewer) { if (collectionType == null) return Cardinality.None; TypeAlias ta = collectionType as TypeAlias; if (ta != null) collectionType = ta.AliasedType; if (collectionType is TupleType) { return Cardinality.One; } else if (collectionType.Template == SystemTypes.GenericBoxed) { return Cardinality.ZeroOrOne; } else if (collectionType.Template == SystemTypes.GenericNonNull) { return Cardinality.One; } else if (collectionType.Template == SystemTypes.GenericNonEmptyIEnumerable) { return Cardinality.OneOrMore; } else if (TypeViewer.GetTypeView(typeViewer, collectionType).IsAssignableTo(SystemTypes.INullable)) { return Cardinality.ZeroOrOne; } else { TypeUnion tu = collectionType as TypeUnion; if (tu != null && tu.Types.Count > 0) { Cardinality c = this.GetCardinality(tu.Types[0], typeViewer); for( int i = 1, n = tu.Types.Count; i < n; i++ ) { TypeNode tn = tu.Types[i]; if (tn == null) continue; c = this.GetCardinalityOr(c, this.GetCardinality(tn, typeViewer)); } return c; } TypeNode elementType = this.GetStreamElementType(collectionType, typeViewer); if (elementType != collectionType) { return Cardinality.ZeroOrMore; } else if (collectionType.IsValueType) { return Cardinality.One; } else { return Cardinality.None; } } }
public virtual Expression CoerceTypeUnionToObject(Expression source, TypeViewer typeViewer){ TypeUnion sourceType = (TypeUnion)source.Type; Method getValue = TypeViewer.GetTypeView(typeViewer, sourceType).GetMethod(StandardIds.GetValue); Local temp = new Local(Identifier.Empty, sourceType); Expression tempAddr = new UnaryExpression(temp, NodeType.AddressOf); StatementList statements = new StatementList(2); statements.Add(new AssignmentStatement(temp, source)); statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(tempAddr, getValue), null))); BlockExpression result = new BlockExpression(new Block(statements)); result.Type = SystemTypes.Object; return result; }
protected virtual Expression CoerceFromTypeUnion(Expression source, TypeUnion sourceType, TypeNode targetType, bool explicitCoercion, TypeNode originalTargetType, TypeViewer typeViewer){ if (source == null || sourceType == null || targetType == null) return null; if (targetType == SystemTypes.Object) return this.CoerceTypeUnionToObject(source, typeViewer); int cErrors = (this.Errors != null) ? this.Errors.Count : 0; if (explicitCoercion){ Method coercion = this.UserDefinedExplicitCoercionMethod(source, sourceType, targetType, false, originalTargetType, typeViewer); if (coercion != null && coercion.ReturnType == targetType && coercion.Parameters != null && coercion.Parameters[0] != null && this.ImplicitCoercionFromTo(sourceType, coercion.Parameters[0].Type, typeViewer)) return this.ImplicitCoercion(new MethodCall(new MemberBinding(null, coercion), new ExpressionList(source), NodeType.Call, coercion.ReturnType), targetType, typeViewer); } Method getTag = TypeViewer.GetTypeView(typeViewer, sourceType).GetMethod(StandardIds.GetTag); if (getTag == null) return null; Method getValue = TypeViewer.GetTypeView(typeViewer, sourceType).GetMethod(StandardIds.GetValue); if (getValue == null) return null; Local src = new Local(sourceType); Local srcOb = new Local(SystemTypes.Object, source.SourceContext); Local tgt = new Local(targetType); Expression callGetTag = new MethodCall(new MemberBinding(new UnaryExpression(src, NodeType.AddressOf), getTag), null); Expression callGetValue = new MethodCall(new MemberBinding(new UnaryExpression(src, NodeType.AddressOf), getValue), null); TypeNodeList types = sourceType.Types; int n = types == null ? 0 : types.Count; Block endOfSwitch = new Block(); StatementList statements = new StatementList(5+n); statements.Add(new AssignmentStatement(src, source)); statements.Add(new AssignmentStatement(srcOb, callGetValue)); BlockList cases = new BlockList(n); statements.Add(new SwitchInstruction(callGetTag, cases)); bool hadCoercion = false; Block eb = new Block(new StatementList(1)); Construct c = new Construct(new MemberBinding(null, SystemTypes.InvalidCastException.GetConstructor()), null, SystemTypes.InvalidCastException); eb.Statements.Add(new Throw(c)); for (int i = 0; i < n; i++){ TypeNode t = types[i]; if (t == null) continue; if (!explicitCoercion && !this.ImplicitCoercionFromTo(t, targetType, typeViewer)) return null; Expression expr = this.ExplicitCoercion(srcOb, t, typeViewer); if (expr == null) return null; expr = this.ExplicitCoercion(expr, targetType, typeViewer); if (expr == null) { cases.Add(eb); statements.Add(eb); } else { Block b = new Block(new StatementList(2)); hadCoercion = true; expr.SourceContext = srcOb.SourceContext; b.Statements.Add(new AssignmentStatement(tgt, expr)); b.Statements.Add(new Branch(null, endOfSwitch)); cases.Add(b); statements.Add(b); } } if (this.Errors != null) { for (int ie = cErrors, ne = this.Errors.Count; ie < ne; ie++) { this.Errors[ie] = null; } } if (!hadCoercion) return null; statements.Add(endOfSwitch); statements.Add(new ExpressionStatement(tgt)); return new BlockExpression(new Block(statements)); //TODO: wrap this in a CoerceTypeUnion node so that source code can be reconstructed easily }
public TypeViewerBehaviour() { _sut = new TypeViewer(typeof(MyServicesApiController)); }
public static bool NotAccessible(Member member, ref TypeNode qualifierType, int visibility, Module currentModule, TypeNode currentType, TypeViewer typeViewer) { TypeNode type = member.DeclaringType; return NotAccessible(member, type, ref qualifierType, visibility, currentModule, currentType, typeViewer); }
public virtual bool ImplicitCoercionToUnion(TypeNode sourceType, TypeUnion union, TypeViewer typeViewer){ if (union == null) return false; TypeNodeList types = union.Types; for (int i = 0, n = types == null ? 0 : types.Count; i < n; i++){ TypeNode t = types[i]; if (t == null) continue; if (this.ImplicitCoercionFromTo(sourceType, t, typeViewer)) return true; } return true; }
public virtual Expression CoerceTypeIntersectionToObject(Expression source, TypeViewer typeViewer){ TypeIntersection sourceType = (TypeIntersection)source.Type; Method coercion = TypeViewer.GetTypeView(typeViewer, sourceType).GetImplicitCoercionToMethod(SystemTypes.Object); ExpressionList args = new ExpressionList(1); args.Add(source); MethodCall result = new MethodCall(new MemberBinding(null, coercion), args); result.Type = SystemTypes.Object; return result; }
public override Expression CoerceAnonymousNestedFunction(AnonymousNestedFunction func, TypeNode targetType, bool explicitCoercion, TypeViewer typeViewer) { if (func is AnonymousNestedDelegate && !(targetType is DelegateNode)) { this.HandleError(func, Error.AnonMethToNonDel, this.GetTypeName(targetType)); return(null); } return(base.CoerceAnonymousNestedFunction(func, targetType, explicitCoercion, typeViewer)); }