Beispiel #1
0
 public static bool IsDirectlyAssignableFrom(this IXamlIlType type, IXamlIlType other)
 {
     if (type.IsValueType || other.IsValueType)
     {
         return(type.Equals(other));
     }
     return(type.IsAssignableFrom(other));
 }
Beispiel #2
0
            public IXamlIlCustomAttribute GetCustomAttribute(IXamlIlType type, IXamlIlType attributeType)
            {
                if (attributeType.Equals(_typeConverterAttribute))
                {
                    var conv = LookupConverter(type);
                    if (conv != null)
                    {
                        return(new ConstructedAttribute(_typeConverterAttribute, new List <object>()
                        {
                            conv
                        }, null));
                    }
                }

                return(null);
            }
Beispiel #3
0
 public static void EmitConvert(XamlIlEmitContext context, IXamlIlLineInfo node, IXamlIlType what,
                                IXamlIlType to, Func <bool, IXamlIlEmitter> ld)
 {
     if (what.Equals(to))
     {
         ld(false);
     }
     else if (what == XamlIlPseudoType.Null)
     {
         if (to.IsValueType)
         {
             if (to.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.NullableT) == true)
             {
                 using (var loc = context.GetLocal(to))
                     ld(false)
                     .Pop()
                     .Ldloca(loc.Local)
                     .Emit(OpCodes.Initobj, to)
                     .Ldloc(loc.Local);
             }
             else
             {
                 throw new XamlIlLoadException("Unable to convert {x:Null} to " + to.GetFqn(), node);
             }
         }
         else
         {
             ld(false);
         }
     }
     else if (what.IsValueType && to.IsValueType)
     {
         if (to.IsNullableOf(what))
         {
             ld(false).Emit(OpCodes.Newobj,
                            to.Constructors.First(c =>
                                                  c.Parameters.Count == 1 && c.Parameters[0].Equals(what)));
         }
         else if (what.IsNullableOf(what))
         {
             ld(true)
             .EmitCall(what.FindMethod(m => m.Name == "get_Value"));
         }
         else
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert value type {what.GetFullName()} to value type {to.GetFullName()}",
                       node);
         }
     }
     else if (!to.IsValueType && what.IsValueType)
     {
         if (!to.IsAssignableFrom(what))
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert value type {what.GetFullName()} to reference type {to.GetFullName()}",
                       node);
         }
         ld(false).Box(what);
     }
     else if (to.IsValueType && !what.IsValueType)
     {
         if (!(what.Namespace == "System" && what.Name == "Object"))
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert reference type {what.GetFullName()} to value type {to.GetFullName()}",
                       node);
         }
         ld(false).Unbox_Any(to);
     }
     else
     {
         if (to.IsAssignableFrom(what))
         {
             // Downcast, always safe
             ld(false);
         }
         else if (what.IsInterface || what.IsAssignableFrom(to))
         {
             // Upcast or cast from interface, might throw InvalidCastException
             ld(false).Emit(OpCodes.Castclass, to);
         }
         else
         {
             // Types are completely unrelated, e. g. string to List<int> conversion attempt
             throw new XamlIlLoadException(
                       $"Don't know how to convert reference type {what.GetFullName()} to reference type {to.GetFullName()}",
                       node);
         }
     }
 }
        public static bool TryCallAdd(XamlIlAstTransformationContext context,
                                      IXamlIlProperty targetProperty, IXamlIlType targetPropertyType, IXamlIlAstValueNode value, out IXamlIlAstManipulationNode rv)
        {
            var so = context.Configuration.WellKnownTypes.Object;

            rv = null;
            IXamlIlWrappedMethod FindAdderImpl(IXamlIlType targetType, IXamlIlType valueType, IXamlIlType keyType = null)
            {
                var candidates = targetType.FindMethods(m =>
                                                        !m.IsStatic && m.IsPublic &&
                                                        (m.Name == "Add" || m.Name.EndsWith(".Add"))).ToList();

                bool CheckArg(IXamlIlType argType, bool allowObj)
                {
                    if (allowObj && argType.Equals(so))
                    {
                        return(true);
                    }
                    if (!allowObj && !argType.Equals(so) && argType.IsAssignableFrom(valueType))
                    {
                        return(true);
                    }
                    return(false);
                }

                foreach (var allowObj in new[] { false, true })
                {
                    foreach (var m in candidates)
                    {
                        if (keyType == null && m.Parameters.Count == 1 &&
                            CheckArg(m.Parameters[0], allowObj))
                        {
                            return(new XamlIlWrappedMethod(m));
                        }
                        if (keyType != null && m.Parameters.Count == 2 &&
                            m.Parameters[0].IsAssignableFrom(keyType) &&
                            CheckArg(m.Parameters[1], allowObj))
                        {
                            return(new XamlIlWrappedMethod(m));
                        }
                    }
                }

                return(null);
            }

            IXamlIlWrappedMethod FindAdderWithCast(IXamlIlType originalType, IXamlIlType newTargetType, IXamlIlType valueType)
            {
                var m = FindAdderImpl(newTargetType, valueType);

                if (m == null)
                {
                    return(null);
                }
                return(new XamlIlWrappedMethodWithCasts(m, new[] { originalType, m.ParametersWithThis[1] }));
            }

            IXamlIlWrappedMethod FindAdder(IXamlIlType valueType, IXamlIlType keyType = null)
            {
                if (keyType == null)
                {
                    if (targetPropertyType.Equals(context.Configuration.WellKnownTypes.IEnumerable))
                    {
                        return(FindAdderWithCast(targetPropertyType, context.Configuration.WellKnownTypes.IList,
                                                 valueType));
                    }
                    if (targetPropertyType.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes
                                                                         .IEnumerableT) == true)
                    {
                        return(FindAdderWithCast(
                                   targetPropertyType,
                                   context.Configuration.WellKnownTypes.IListOfT
                                   .MakeGenericType(targetPropertyType.GenericArguments[0]), valueType));
                    }
                }
                return(FindAdderImpl(targetPropertyType, valueType, keyType));
            }

            if (TryConvertMarkupExtension(context, value, targetProperty, out var ext))
            {
                var adder = FindAdder(ext.ProvideValue.ReturnType);
                if (adder != null)
                {
                    ext.Manipulation = adder;
                    rv = ext;
                    return(true);
                }
            }
            else
            {
                var vtype = value.Type.GetClrType();
                IXamlIlAstValueNode keyNode = null;

                bool IsKeyDirective(object node) => node is XamlIlAstXmlDirective d &&
                d.Namespace == XamlNamespaces.Xaml2006 &&
                d.Name == "Key";

                void ProcessDirective(object d)
                {
                    var directive = (XamlIlAstXmlDirective)d;

                    if (directive.Values.Count != 1)
                    {
                        throw new XamlIlParseException("Invalid number of arguments for x:Key directive",
                                                       directive);
                    }
                    keyNode = directive.Values[0];
                }

                void ProcessDirectiveCandidateList(IList nodes)
                {
                    var d = nodes.OfType <object>().FirstOrDefault(IsKeyDirective);

                    if (d != null)
                    {
                        ProcessDirective(d);
                        nodes.Remove(d);
                    }
                }

                IXamlIlAstManipulationNode VisitManipulationNode(IXamlIlAstManipulationNode man)
                {
                    if (IsKeyDirective(man))
                    {
                        ProcessDirective(man);
                        return(new XamlIlManipulationGroupNode(man));
                    }
                    if (man is XamlIlManipulationGroupNode grp)
                    {
                        ProcessDirectiveCandidateList(grp.Children);
                    }
                    if (man is XamlIlObjectInitializationNode init)
                    {
                        init.Manipulation = VisitManipulationNode(init.Manipulation);
                    }
                    return(man);
                }

                if (value is XamlIlAstObjectNode astObject)
                {
                    ProcessDirectiveCandidateList(astObject.Children);
                }
                else if (value is XamlIlValueWithManipulationNode vman)
                {
                    vman.Manipulation = VisitManipulationNode(vman.Manipulation);
                }


                var adder = FindAdder(vtype, keyNode?.Type.GetClrType());
                if (adder != null)
                {
                    var args = new List <IXamlIlAstValueNode>();
                    if (keyNode != null)
                    {
                        args.Add(keyNode);
                    }
                    args.Add(value);

                    rv = new XamlIlNoReturnMethodCallNode(value, adder, args);
                    if (targetProperty != null)
                    {
                        rv = new XamlIlPropertyValueManipulationNode(value, targetProperty, rv);
                    }
                    return(true);
                }
            }

            return(false);
        }