public static bool TryConvertMarkupExtension(XamlIlAstTransformationContext context,
                                                     IXamlIlAstValueNode node, IXamlIlProperty prop, out XamlIlMarkupExtensionNode o)
        {
            o = null;
            var nodeType   = node.Type.GetClrType();
            var candidates = nodeType.Methods.Where(m => m.Name == "ProvideValue" && m.IsPublic && !m.IsStatic)
                             .ToList();
            var so = context.Configuration.WellKnownTypes.Object;
            var sp = context.Configuration.TypeMappings.ServiceProvider;

            // Try non-object variant first and variants without IServiceProvider argument first

            var provideValue = candidates.FirstOrDefault(m => m.Parameters.Count == 0 && !m.ReturnType.Equals(so))
                               ?? candidates.FirstOrDefault(m => m.Parameters.Count == 0)
                               ?? candidates.FirstOrDefault(m =>
                                                            m.Parameters.Count == 1 && m.Parameters[0].Equals(sp) && !m.ReturnType.Equals(so))
                               ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1 && m.Parameters[0].Equals(sp));

            if (provideValue == null)
            {
                return(false);
            }
            o = new XamlIlMarkupExtensionNode(node, prop, provideValue, node, null);
            return(true);
        }
        public static bool TryConvertMarkupExtension(XamlIlAstTransformationContext context,
                                                     IXamlIlAstValueNode node, out XamlIlMarkupExtensionNode o)
        {
            o = null;
            var nodeType   = node.Type.GetClrType();
            var candidates = GetMarkupExtensionProvideValueAlternatives(context, nodeType).ToList();
            var so         = context.Configuration.WellKnownTypes.Object;
            var sp         = context.Configuration.TypeMappings.ServiceProvider;

            // Try non-object variant first and variants without IServiceProvider argument first

            var provideValue = candidates.FirstOrDefault(m => m.Parameters.Count == 0 && !m.ReturnType.Equals(so))
                               ?? candidates.FirstOrDefault(m => m.Parameters.Count == 0)
                               ?? candidates.FirstOrDefault(m =>
                                                            m.Parameters.Count == 1 && m.Parameters[0].Equals(sp) && !m.ReturnType.Equals(so))
                               ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1 && m.Parameters[0].Equals(sp));

            if (provideValue == null)
            {
                if (node.Type.IsMarkupExtension)
                {
                    throw new XamlIlParseException(
                              $"{node.Type.GetClrType().GetFqn()} was resolved as markup extension, but doesn't have a matching ProvideValue/ProvideTypedValue method",
                              node.Type);
                }

                return(false);
            }
            o = new XamlIlMarkupExtensionNode(node, provideValue, node);
            return(true);
        }
        public static List <IXamlIlAstManipulationNode> GeneratePropertyAssignments(XamlIlAstTransformationContext context,
                                                                                    IXamlIlProperty property, List <IXamlIlAstValueNode> nodes)
        {
            var tmp = nodes.Cast <IXamlIlAstNode>().ToList();

            GeneratePropertyAssignments(context, property, tmp.Count,
                                        i => (IXamlIlAstValueNode)tmp[i],
                                        (i, v) => tmp[i] = v);
            return(tmp.Cast <IXamlIlAstManipulationNode>().ToList());
        }
示例#4
0
        public static bool TryGetCorrectlyTypedValue(XamlIlAstTransformationContext context,
                                                     IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode rv)
        {
            if (type.IsAssignableFrom(node.Type.GetClrType()))
            {
                rv = node;
                return(true);
            }

            return(TryConvertValue(context, node, type, null, out rv));
        }
示例#5
0
        public static IEnumerable <IXamlIlMethod> GetMarkupExtensionProvideValueAlternatives(
            XamlIlAstTransformationContext context,
            IXamlIlType type)
        {
            var sp = context.Configuration.TypeMappings.ServiceProvider;

            return(type.FindMethods(m =>
                                    (m.Name == "ProvideValue" || m.Name == "ProvideTypedValue") && m.IsPublic && !m.IsStatic &&
                                    (m.Parameters.Count == 0 || (m.Parameters.Count == 1 && m.Parameters[0].Equals(sp)))
                                    ));
        }
        public static void GeneratePropertyAssignments(XamlIlAstTransformationContext context,
                                                       IXamlIlProperty contentProperty,
                                                       int count, Func <int, IXamlIlAstValueNode> getNode, Action <int, IXamlIlAstNode> setNode)
        {
            var type = contentProperty.PropertyType;

            // Markup extension ?
            if (contentProperty.Setter?.IsPublic == true &&
                count == 1 &&
                TryConvertMarkupExtension(context, getNode(0),
                                          contentProperty, out var me))
            {
                setNode(0, me);
            }
            // Direct property assignment?
            else if (contentProperty.Setter?.IsPublic == true &&
                     count == 1 &&
                     context.Configuration.TryGetCorrectlyTypedValue(getNode(0),
                                                                     contentProperty.PropertyType,
                                                                     out var value))
            {
                setNode(0,
                        new XamlIlPropertyAssignmentNode(getNode(0), contentProperty, value));
            }
            // Collection property?
            else if (contentProperty.Getter?.IsPublic == true)
            {
                for (var ind = 0; ind < count; ind++)
                {
                    if (TryCallAdd(context, contentProperty, contentProperty.PropertyType, getNode(ind), out var addCall))
                    {
                        setNode(ind, addCall);
                    }
                    else
                    {
                        var propFqn  = contentProperty.PropertyType.GetFqn();
                        var valueFqn = getNode(ind).Type.GetClrType().GetFqn();
                        throw new XamlIlLoadException(
                                  $"Unable to directly convert {valueFqn} to {propFqn} find a suitable Add({valueFqn}) on type {propFqn}",
                                  getNode(ind));
                    }
                }
            }
            else
            {
                throw new XamlIlLoadException(
                          $"Unable to handle {getNode(0).Type.GetClrType().GetFqn()} assignment to {contentProperty.Name} " +
                          $"as either direct assignment or collection initialization, check if value type matches property type or that property type has proper Add method",
                          getNode(0));
            }
        }
        public void Transform(XamlIlDocument doc,
                              Dictionary <string, string> namespaceAliases, bool strict = true)
        {
            var ctx = new XamlIlAstTransformationContext(_configuration, namespaceAliases, strict);

            var root = doc.Root;

            foreach (var transformer in Transformers)
            {
                root = root.Visit(n => transformer.Transform(ctx, n));
            }

            doc.Root = root;
        }
        public static bool TryCallAdd(XamlIlAstTransformationContext context,
                                      IXamlIlProperty targetProperty, IXamlIlType targetPropertyType, IXamlIlAstValueNode value, out IXamlIlAstManipulationNode rv)
        {
            if (TryConvertMarkupExtension(context, value, targetProperty, out var ext))
            {
                var adder = new[] { ext.ProvideValue.ReturnType, context.Configuration.WellKnownTypes.Object }
                .Select(argType => targetPropertyType.FindMethod(m =>
                                                                 !m.IsStatic && m.IsPublic &&
                                                                 (m.Name == "Add" || m.Name.EndsWith(".Add")) &&
                                                                 m.Parameters.Count == 1 &&
                                                                 m.Parameters[0].Equals(argType)))
                .FirstOrDefault(m => m != null);
                if (adder != null)
                {
                    ext.Manipulation = adder;
                    rv = ext;
                    return(true);
                }
            }

            if (context.Configuration.TryCallAdd(targetPropertyType, value, out var nret))
            {
                if (targetProperty != null)
                {
                    rv = new XamlIlPropertyValueManipulationNode(value, targetProperty, nret);
                }
                else
                {
                    rv = nret;
                }
                return(true);
            }

            rv = null;
            return(false);
        }
 public Visitor(XamlIlAstTransformationContext context, IXamlIlAstTransformer transformer)
 {
     _context     = context;
     _transformer = transformer;
 }
示例#10
0
        public static IReadOnlyList <IXamlIlMethod> FindPossibleAdders(XamlIlAstTransformationContext context,
                                                                       IXamlIlType type)
        {
            IReadOnlyList <IXamlIlMethod> FindPossibleAddersImpl()
            {
                var known = context.Configuration.WellKnownTypes;

                // Attempt to cast IEnumerable and IEnumerable<T> to IList<T>
                var actualType = type;

                if (actualType.Equals(known.IEnumerable))
                {
                    actualType = known.IList;
                }
                if (actualType.GenericTypeDefinition?.Equals(known.IEnumerableT) == true)
                {
                    actualType = known.IListOfT.MakeGenericType(actualType.GenericArguments[0]);
                }

                var inspectTypes = new List <IXamlIlType>();

                inspectTypes.Add(actualType);
                inspectTypes.AddRange(actualType.GetAllInterfaces());

                // If type supports IList<T> don't fall back to IList
                if (inspectTypes.Any(t => t.GenericTypeDefinition?.Equals(known.IListOfT) == true))
                {
                    inspectTypes = inspectTypes.Where(t => !t.Equals(known.IList)).ToList();
                }

                var rv = new List <IXamlIlMethod>();

                foreach (var t in inspectTypes)
                {
                    foreach (var m in t.FindMethods(m => m.Name == "Add" && m.IsPublic && !m.IsStatic &&
                                                    (m.Parameters.Count == 1 || m.Parameters.Count == 2)))
                    {
                        if (rv.Any(em => em.Equals(m)))
                        {
                            continue;
                        }
                        rv.Add(m);
                    }
                }

                // First use methods from the type itself, then from base types, then from interfaces
                rv = rv
                     .OrderByDescending(x => x.ThisOrFirstParameter().Equals(actualType))
                     .ThenBy(x => x.ThisOrFirstParameter().IsInterface)
                     .ToList();

                // Add casts
                for (var c = 0; c < rv.Count; c++)
                {
                    if (!rv[c].ThisOrFirstParameter().Equals(type))
                    {
                        rv[c] = new XamlIlMethodWithCasts(rv[c], new[] { type }.Concat(rv[c].Parameters));
                    }
                }

                return(rv);
            }

            var cache = context.GetOrCreateItem <AdderCache>();

            if (cache.TryGetValue(type, out var rvr))
            {
                return(rvr);
            }
            else
            {
                return(cache[type] = FindPossibleAddersImpl());
            }
        }
示例#11
0
        public static bool TryConvertValue(XamlIlAstTransformationContext context,
                                           IXamlIlAstValueNode node, IXamlIlType type, XamlIlAstClrProperty propertyContext,
                                           out IXamlIlAstValueNode rv)
        {
            rv = null;
            var cfg = context.Configuration;

            // Since we are doing a conversion anyway, it makes sense to check for the underlying nullable type
            if (type.GenericTypeDefinition?.Equals(cfg.WellKnownTypes.NullableT) == true)
            {
                type = type.GenericArguments[0];
            }


            if (cfg.CustomValueConverter?.Invoke(context, node, type, out rv) == true)
            {
                return(true);
            }

            var nodeType = node.Type.GetClrType();

            // Implicit type converters
            if (!nodeType.Equals(cfg.WellKnownTypes.String))
            {
                return(false);
            }

            if (node is XamlIlAstTextNode tn)
            {
                if (type.IsEnum)
                {
                    if (TypeSystemHelpers.TryGetEnumValueNode(type, tn.Text, tn, out var enumConstantNode))
                    {
                        rv = enumConstantNode;
                        return(true);
                    }
                }

                // Well known types
                if (TypeSystemHelpers.ParseConstantIfTypeAllows(tn.Text, type, tn, out var constantNode))
                {
                    rv = constantNode;
                    return(true);
                }

                if (type.FullName == "System.Type")
                {
                    var resolvedType = XamlIlTypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true);
                    rv = new XamlIlTypeExtensionNode(tn, resolvedType, type);
                    return(true);
                }

                if (cfg.WellKnownTypes.Delegate.IsAssignableFrom(type))
                {
                    var invoke   = type.FindMethod(m => m.Name == "Invoke");
                    var rootType = context.RootObject.Type.GetClrType();
                    var handler  =
                        rootType.FindMethod(tn.Text, invoke.ReturnType, false, invoke.Parameters.ToArray());
                    if (handler != null)
                    {
                        rv = new XamlIlLoadMethodDelegateNode(tn, context.RootObject, type, handler);
                        return(true);
                    }
                }
            }

            IXamlIlAstValueNode CreateInvariantCulture() =>
            new XamlIlStaticOrTargetedReturnMethodCallNode(node,
                                                           cfg.WellKnownTypes.CultureInfo.Methods.First(x =>
                                                                                                        x.IsPublic && x.IsStatic && x.Name == "get_InvariantCulture"), null);

            var candidates = type.Methods.Where(m => m.Name == "Parse" &&
                                                m.ReturnType.Equals(type) &&
                                                m.Parameters.Count > 0 &&
                                                m.Parameters[0].Equals(cfg.WellKnownTypes.String)).ToList();

            // Types with parse method
            var parser = candidates.FirstOrDefault(m =>
                                                   m.Parameters.Count == 2 &&
                                                   (
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.CultureInfo) ||
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.IFormatProvider)
                                                   )
                                                   )
                         ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1);

            if (parser != null)
            {
                var args = new List <IXamlIlAstValueNode> {
                    node
                };
                if (parser.Parameters.Count == 2)
                {
                    args.Add(CreateInvariantCulture());
                }

                rv = new XamlIlStaticOrTargetedReturnMethodCallNode(node, parser, args);
                return(true);
            }

            if (cfg.TypeMappings.TypeDescriptorContext != null)
            {
                IXamlIlType converterType = null;
                if (propertyContext?.TypeConverters.TryGetValue(type, out converterType) != true)
                {
                    var typeConverterAttribute =
                        cfg.GetCustomAttribute(type, cfg.TypeMappings.TypeConverterAttributes).FirstOrDefault();
                    if (typeConverterAttribute != null)
                    {
                        converterType = TryGetTypeConverterFromCustomAttribute(cfg, typeConverterAttribute);
                    }
                }

                if (converterType != null)
                {
                    var converterMethod = converterType.FindMethod("ConvertFrom", cfg.WellKnownTypes.Object, false,
                                                                   cfg.TypeMappings.TypeDescriptorContext, cfg.WellKnownTypes.CultureInfo,
                                                                   cfg.WellKnownTypes.Object);
                    rv = new XamlIlAstNeedsParentStackValueNode(node,
                                                                new XamlIlAstRuntimeCastNode(node,
                                                                                             new XamlIlStaticOrTargetedReturnMethodCallNode(node, converterMethod,
                                                                                                                                            new[]
                    {
                        new XamlIlAstNewClrObjectNode(node,
                                                      new XamlIlAstClrTypeReference(node, converterType, false), null,
                                                      new List <IXamlIlAstValueNode>()),
                        new XamlIlAstContextLocalNode(node, cfg.TypeMappings.TypeDescriptorContext),
                        CreateInvariantCulture(), node
                    }), new XamlIlAstClrTypeReference(node, type, false)));
                    return(true);
                }
            }

            return(false);
        }
示例#12
0
        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);
        }