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);
        }
Beispiel #2
0
 public override void VisitChildren(XamlIlAstVisitorDelegate visitor)
 {
     Manipulation = (IXamlIlAstManipulationNode)Manipulation.Visit(visitor);
 }
Beispiel #3
0
 public override void VisitChildren(XamlIlAstVisitorDelegate visitor)
 {
     Value        = (IXamlIlAstValueNode)Value?.Visit(visitor);
     Manipulation = (IXamlIlAstManipulationNode)Manipulation?.Visit(visitor);
 }
Beispiel #4
0
 public override void VisitChildren(Visitor visitor)
 {
     base.VisitChildren(visitor);
     Manipulation = (IXamlIlAstManipulationNode)Manipulation?.Visit(visitor);
 }
Beispiel #5
0
 public override void VisitChildren(Visitor visitor)
 {
     Value        = (XamlIlAstCompilerLocalNode)Value.Visit(visitor);
     Manipulation = (IXamlIlAstManipulationNode)Manipulation.Visit(visitor);
 }
Beispiel #6
0
 public XamlIlAstImperativeValueManipulation(IXamlIlLineInfo lineInfo,
                                             IXamlIlAstValueNode value, IXamlIlAstManipulationNode manipulation) : base(lineInfo)
 {
     Value        = value;
     Manipulation = manipulation;
 }