2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
24 using Mono.Cecil.Rocks;
25 using Tizen.NUI.Binding;
26 using Tizen.NUI.Binding.Internals;
27 using Tizen.NUI.EXaml;
29 using Tizen.NUI.Xaml.Build.Tasks;
30 using Tizen.NUI.Xaml.Core.XamlC;
31 using static Mono.Cecil.Cil.Instruction;
32 using static Mono.Cecil.Cil.OpCodes;
34 namespace Tizen.NUI.EXaml.Build.Tasks
36 class EXamlSetPropertiesVisitor : IXamlNodeVisitor
39 static int typedBindingCount;
41 static readonly IList<XmlName> skips = new List<XmlName>
44 XmlName.xTypeArguments,
46 XmlName.xFactoryMethod,
51 public EXamlSetPropertiesVisitor(EXamlContext context, bool stopOnResourceDictionary = false)
54 Module = context.Module;
55 StopOnResourceDictionary = stopOnResourceDictionary;
58 public EXamlContext Context { get; }
59 public bool StopOnResourceDictionary { get; }
60 public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
61 public bool StopOnDataTemplate => true;
62 public bool VisitNodeOnDataTemplate => true;
63 public bool SkipChildren(INode node, INode parentNode) => false;
65 public bool IsResourceDictionary(ElementNode node)
67 var parentVar = Context.Values[node] as EXamlCreateObject;
69 if (null != parentVar && !parentVar.GetType().IsLocalType())
71 return parentVar.GetType().FullName == "Tizen.NUI.Binding.ResourceDictionary"
73 parentVar.GetType().Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
79 ModuleDefinition Module { get; }
81 public void Visit(ValueNode node, INode parentNode)
83 //TODO support Label text as element
85 if (!TryGetPropertyName(node, parentNode, out propertyName))
87 if (!IsCollectionItem(node, parentNode))
89 string contentProperty;
90 if (!Context.Variables.ContainsKey((IElementNode)parentNode))
92 var parentVar = Context.Variables[(IElementNode)parentNode];
93 if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
94 propertyName = new XmlName(((IElementNode)parentNode).NamespaceURI, contentProperty);
99 if (TrySetRuntimeName(propertyName, Context.Values[parentNode] as EXamlCreateObject, node))
101 if (skips.Contains(propertyName))
103 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
105 if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
108 SetPropertyValue(Context.Values[parentNode] as EXamlCreateObject, propertyName, node, Context, node);
111 public void Visit(MarkupNode node, INode parentNode)
115 public void Visit(ElementNode node, INode parentNode)
117 XmlName propertyName = XmlName.Empty;
119 //Simplify ListNodes with single elements
120 var pList = parentNode as ListNode;
123 (pList.CollectionItems.Count == 1
125 "XamlResources" == pList.XmlName.LocalName))
127 propertyName = pList.XmlName;
128 parentNode = parentNode.Parent;
131 if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName))
134 if (propertyName == XmlName._CreateContent
136 parentNode is ElementNode parentElementNode)
138 SetDataTemplate(parentElementNode, node, Context, node);
142 //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
143 var vardef = Context.Values[node];
145 var localName = propertyName.LocalName;
146 TypeReference declaringTypeReference = null;
148 PropertyDefinition propertyRef = null;
149 if (parentNode is IElementNode && propertyName != XmlName.Empty) {
150 propertyRef = Context.Variables [(IElementNode)parentNode].VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
153 if (vardef is EXamlCreateObject)
155 var realValue = ProvideValue(vardef as EXamlCreateObject, Context, Module, node, propertyRef: propertyRef, propertyDeclaringTypeRef: declaringTypeReference);
156 if (null != realValue && vardef != realValue)
158 (vardef as EXamlCreateObject).IsValid = false;
159 Context.Values[node] = realValue;
164 if (propertyName != XmlName.Empty) {
165 if (skips.Contains(propertyName))
167 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
170 SetPropertyValue(Context.Values[parentNode] as EXamlCreateObject, propertyName, node, Context, node);
172 else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
173 var parentVar = Context.Values[parentNode] as EXamlCreateObject;
174 string contentProperty;
176 bool isAdded = false;
178 if (CanAddToResourceDictionary(parentVar, parentVar.GetType(), node, node, Context))
180 var keyName = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
181 new EXamlAddToResourceDictionary(Context, parentVar, keyName, Context.Values[node]);
185 // Collection element, implicit content, or implicit collection element.
186 if (!isAdded && parentVar.GetType().GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).Any())
188 var elementType = parentVar.GetType();
189 var paramType = Context.Variables[node].VariableType;
191 foreach (var adderTuple in elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module))
193 var adderRef = Module.ImportReference(adderTuple.Item1);
194 adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
196 if (IsAddMethodOfCollection(Module, adderRef.Resolve()))
198 new EXamlAddToCollectionInstance(Context, parentVar, Context.Values[node]);
202 else if (paramType.InheritsFromOrImplements(adderTuple.Item1.Parameters[0].ParameterType.FullName))
204 new EXamlAddObject(Context, parentVar, Context.Values[node], adderRef.Resolve());
211 if (!isAdded && (contentProperty = GetContentProperty(parentVar.GetType())) != null)
213 var name = new XmlName(node.NamespaceURI, contentProperty);
214 if (skips.Contains(name))
216 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains(propertyName))
219 SetPropertyValue(Context.Values[parentNode] as EXamlCreateObject, name, node, Context, node);
225 throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
228 else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
230 var parentList = (ListNode)parentNode;
231 if (skips.Contains(parentList.XmlName))
233 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
236 var parent = Context.Variables[((IElementNode)parentNode.Parent)];
237 var elementType = parent.VariableType;
238 localName = parentList.XmlName.LocalName;
240 if (Context.Values[parentList.Parent] is EXamlCreateObject)
242 if (localName.Contains('.'))
244 int index = localName.LastIndexOf('.');
245 localName = localName.Substring(index + 1);
248 var getObjectByProperty = new EXamlGetObjectByProperty(Context, Context.Values[parentList.Parent] as EXamlCreateObject, localName);
249 new EXamlAddToCollectionProperty(Context, getObjectByProperty, Context.Values[node]);
254 public void Visit(RootNode node, INode parentNode)
258 public void Visit(ListNode node, INode parentNode)
262 private static MethodDefinition addDefOfCollection;
263 private static bool IsAddMethodOfCollection(ModuleDefinition module, MethodDefinition methodDef)
265 return module.ImportReference(typeof(List<string>)).InheritsFromOrImplements(methodDef.DeclaringType);
268 public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
270 name = default(XmlName);
271 var parentElement = parentNode as IElementNode;
272 if (parentElement == null)
274 foreach (var kvp in parentElement.Properties)
276 if (kvp.Value != node)
284 static bool IsCollectionItem(INode node, INode parentNode)
286 var parentList = parentNode as IListNode;
287 if (parentList == null)
289 return parentList.CollectionItems.Contains(node);
292 internal static string GetContentProperty(TypeReference typeRef)
294 if (typeRef.IsLocalType())
296 return typeRef.GetContentPropertyNameOfLocalType();
300 var typeDef = typeRef.ResolveCached();
301 var attributes = typeDef.CustomAttributes;
303 attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
305 return attr.ConstructorArguments[0].Value as string;
306 if (typeDef.BaseType == null)
308 return GetContentProperty(typeDef.BaseType);
312 public static object ProvideValue(EXamlCreateObject instance, EXamlContext context,
313 ModuleDefinition module, ElementNode node,
314 PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
316 GenericInstanceType markupExtension;
317 IList<TypeReference> genericArguments;
318 if (instance.GetType().FullName == "Tizen.NUI.Xaml.Build.Tasks.ArrayExtension")
320 var nodeValue = context.Values[node] as EXamlCreateObject;
322 if (nodeValue?.Instance is Xaml.Build.Tasks.ArrayExtension arrayExtension)
324 return arrayExtension.ProvideValue(node, module, context);
327 else if (instance.GetType().ImplementsGenericInterface("Tizen.NUI.Xaml.IMarkupExtension`1", out markupExtension, out genericArguments))
329 var nodeValue = context.Values[node] as EXamlCreateObject;
330 if (nodeValue?.Instance is BindingExtension bindingExtension)
332 bindingExtension.XmlType = new XmlType(node.XmlType.NamespaceUri, "Binding", node.XmlType.TypeArguments);
333 var newValue = bindingExtension.ProvideValue(context, module);
336 else if (nodeValue?.Instance is DynamicResourceExtension)
338 var dynamicResExtension = nodeValue.Instance as DynamicResourceExtension;
339 var newValue = dynamicResExtension.ProvideValue();
340 var newTypeRef = module.ImportReference(newValue.GetType());
341 return new EXamlCreateObject(context, newValue, newTypeRef, new object[] { dynamicResExtension.Key });
346 var nodeValue = context.Values[node] as EXamlCreateObject;
347 if (null != nodeValue)
349 if (nodeValue.GetType().ImplementsInterface(module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IMarkupExtension"))))
351 var acceptEmptyServiceProvider = instance.GetType().GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
352 if (nodeValue.Instance is ReferenceExtension)
354 var newValue = (nodeValue.Instance as ReferenceExtension).ProvideValue(context);
357 else if (nodeValue.Instance is StaticResourceExtension)
359 var newValue = (nodeValue.Instance as StaticResourceExtension).ProvideValue(context);
363 else if (nodeValue.GetType().ImplementsInterface(module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IValueProvider"))))
365 //var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
366 //var valueProviderType = context.Variables[node].VariableType;
367 ////If the IValueProvider has a ProvideCompiledAttribute that can be resolved, shortcut this
368 //var compiledValueProviderName = valueProviderType?.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?[0].Value as string;
369 //Type compiledValueProviderType;
370 //if (compiledValueProviderName != null && (compiledValueProviderType = Type.GetType(compiledValueProviderName)) != null)
372 // var compiledValueProvider = Activator.CreateInstance(compiledValueProviderType);
373 // var cProvideValue = typeof(ICompiledValueProvider).GetMethods().FirstOrDefault(md => md.Name == "ProvideValue");
374 // var instructions = (IEnumerable<Instruction>)cProvideValue.Invoke(compiledValueProvider, new object[] {
379 //foreach (var i in instructions)
386 //instance.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
387 //yield return Create(Ldloc, context.Variables[node]);
388 //if (acceptEmptyServiceProvider)
389 // yield return Create(Ldnull);
391 // foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
392 // yield return instruction;
393 //yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IValueProvider"),
394 // methodName: "ProvideValue",
395 // parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
396 //yield return Create(Stloc, instance.VariableDefinition);
402 static IList<Tuple<PropertyDefinition, string>> ParsePath(string path, TypeReference tSourceRef, IXmlLineInfo lineInfo, ModuleDefinition module)
404 if (string.IsNullOrWhiteSpace(path))
406 path = path.Trim(' ', '.'); //trim leading or trailing dots
407 var parts = path.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
408 var properties = new List<Tuple<PropertyDefinition, string>>();
410 var previousPartTypeRef = tSourceRef;
412 foreach (var part in parts) {
414 string indexArg = null;
415 var lbIndex = p.IndexOf('[');
417 var rbIndex = p.LastIndexOf(']');
419 throw new XamlParseException("Binding: Indexer did not contain closing bracket", lineInfo);
421 var argLength = rbIndex - lbIndex - 1;
423 throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
425 indexArg = p.Substring(lbIndex + 1, argLength).Trim();
426 if (indexArg.Length == 0)
427 throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
429 p = p.Substring(0, lbIndex);
434 var property = previousPartTypeRef.GetProperty(pd => pd.Name == p && pd.GetMethod != null && pd.GetMethod.IsPublic, out _)
435 ?? throw new XamlParseException($"Binding: Property '{p}' not found on '{previousPartTypeRef}'", lineInfo);
436 properties.Add(new Tuple<PropertyDefinition, string>(property,null));
437 previousPartTypeRef = property.PropertyType;
439 if (indexArg != null) {
440 var defaultMemberAttribute = previousPartTypeRef.GetCustomAttribute(module, ("mscorlib", "System.Reflection", "DefaultMemberAttribute"));
441 var indexerName = defaultMemberAttribute?.ConstructorArguments?.FirstOrDefault().Value as string ?? "Item";
442 var indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName && pd.GetMethod != null && pd.GetMethod.IsPublic, out _);
443 properties.Add(new Tuple<PropertyDefinition, string>(indexer, indexArg));
444 if (indexer.PropertyType != module.TypeSystem.String && indexer.PropertyType != module.TypeSystem.Int32)
445 throw new XamlParseException($"Binding: Unsupported indexer index type: {indexer.PropertyType.FullName}", lineInfo);
446 previousPartTypeRef = indexer.PropertyType;
452 private static bool SetPropertyValueToLocalType(EXamlCreateObject parent, XmlName propertyName, INode valueNode, EXamlContext context)
454 if (parent.Instance is Tizen.NUI.Xaml.Build.Tasks.ArrayExtension arrayExtension)
456 if ("Type" == propertyName.LocalName)
458 var value = context.Values[valueNode] as EXamlCreateObject;
461 arrayExtension.Type = value.Instance as TypeReference;
462 parent.IsValid = false;
465 else if ("Items" == propertyName.LocalName)
467 arrayExtension.Items = context.Values[valueNode];
468 parent.IsValid = false;
477 public static void SetPropertyValue(EXamlCreateObject parent, XmlName propertyName, INode valueNode, EXamlContext context, IXmlLineInfo iXmlLineInfo)
479 var module = context.Module;
480 var localName = propertyName.LocalName;
483 if (SetPropertyValueToLocalType(parent, propertyName, valueNode, context))
488 var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, iXmlLineInfo);
490 //If the target is an event, connect
491 if (CanConnectEvent(parent, localName, attached))
493 ConnectEvent(parent, localName, valueNode, iXmlLineInfo, context);
495 //If Value is DynamicResource, SetDynamicResource
496 else if (CanSetDynamicResource(bpRef, valueNode, context))
498 SetDynamicResource(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
500 //If Value is a BindingBase and target is a BP, SetBinding
501 else if (CanSetBinding(bpRef, valueNode, context))
503 SetBinding(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
505 //If it's a property, set it
506 else if (CanSet(parent, localName, valueNode, context))
508 Set(parent, localName, valueNode, iXmlLineInfo, context);
510 //If it's a BP, SetValue ()
511 else if (CanSetValue(bpRef, attached, valueNode, iXmlLineInfo, context))
513 SetValue(parent, bpRef, valueNode, iXmlLineInfo, context);
515 //If it's an already initialized property, add to it
516 else if (CanAdd(parent, propertyName, valueNode, iXmlLineInfo, context))
518 Add(parent, localName, valueNode, iXmlLineInfo, context);
522 throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
526 //public static IEnumerable<Instruction> GetPropertyValue(EXamlCreateObject parent, XmlName propertyName, ILContext context, IXmlLineInfo lineInfo, out TypeReference propertyType)
528 // var module = context.Module;
529 // var localName = propertyName.LocalName;
531 // var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
533 // //If it's a BP, GetValue ()
534 // if (CanGetValue(parent, bpRef, attached, lineInfo, context, out _))
535 // return GetValue(parent, bpRef, lineInfo, context, out propertyType);
537 // //If it's a property, set it
538 // if (CanGet(parent, localName, context, out _))
539 // return Get(parent, localName, lineInfo, context, out propertyType);
541 // throw new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
544 static MemberReference GetBindablePropertyReference(EXamlCreateObject parent, string namespaceURI, ref string localName, out bool attached, EXamlContext context, IXmlLineInfo iXmlLineInfo)
546 var module = context.Module;
547 TypeReference declaringTypeReference;
549 //If it's an attached BP, update elementType and propertyName
550 var bpOwnerType = parent.GetType();
551 attached = GetNameAndTypeRef(ref bpOwnerType, namespaceURI, ref localName, context, iXmlLineInfo);
552 var name = $"{localName}Property";
554 PropertyReference prRef = bpOwnerType.GetProperty(p => p.Name == name &&
555 p.GetMethod.IsStatic && p.GetMethod.IsPublic,
556 out declaringTypeReference);
560 //prRef = module.ImportReference(prRef.ResolveGenericParameters(declaringTypeReference));
561 prRef.PropertyType = module.ImportReference(prRef.PropertyType);
565 FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == name &&
567 (fd.IsPublic || fd.IsAssembly), out declaringTypeReference);
569 bpRef = module.ImportReference(bpRef.ResolveGenericParameters(declaringTypeReference));
570 bpRef.FieldType = module.ImportReference(bpRef.FieldType);
575 static bool CanConnectEvent(EXamlCreateObject parent, string localName, bool attached)
577 return !attached && parent.GetType().GetEvent(ed => ed.Name == localName, out _) != null;
580 static void ConnectEvent(EXamlCreateObject parent, string localName, INode valueNode, IXmlLineInfo iXmlLineInfo, EXamlContext context)
582 //Fang: Need to deal connect event
583 var elementType = parent.GetType();
584 var module = context.Module;
585 TypeReference eventDeclaringTypeRef;
587 var eventinfo = elementType.GetEvent(ed => ed.Name == localName, out eventDeclaringTypeRef);
592 // IL_0009: ldftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
593 //OR, if the handler is virtual
595 // IL_0009: ldvirtftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
597 // IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
598 // IL_0014: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Button::add_Clicked(class [mscorlib]System.EventHandler)
600 var value = ((ValueNode)valueNode).Value;
602 //if (context.Root is VariableDefinition)
603 // yield return Create(Ldloc, context.Root as VariableDefinition);
604 //else if (context.Root is FieldDefinition)
606 // yield return Create(Ldarg_0);
607 // yield return Create(Ldfld, context.Root as FieldDefinition);
610 // throw new InvalidProgramException();
611 var declaringType = context.Type;
612 while (declaringType.IsNested)
613 declaringType = declaringType.DeclaringType;
614 var handler = declaringType.AllMethods().FirstOrDefault(md => md.Name == value as string);
616 //check if the handler signature matches the Invoke signature;
617 var invoke = module.ImportReference(eventinfo.EventType.ResolveCached().GetMethods().First(md => md.Name == "Invoke"));
618 invoke = invoke.ResolveGenericParameters(eventinfo.EventType, module);
619 if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
621 TypeDefinition realType = eventinfo.EventType.ResolveCached();
623 GenericInstanceType genericInstanceType = eventinfo.EventType as GenericInstanceType;
625 if (null != genericInstanceType
626 && genericInstanceType.GenericArguments.Count == realType.GenericParameters.Count)
628 Dictionary<string, TypeReference> dict = new Dictionary<string, TypeReference>();
630 for (int i = 0; i < realType.GenericParameters.Count; i++)
632 string p = realType.GenericParameters[i].Name;
633 TypeReference type = genericInstanceType.GenericArguments[i];
638 if (dict.ContainsKey(invoke.ReturnType.Name))
640 invoke.ReturnType = dict[invoke.ReturnType.Name];
643 for (int i = 0; i < invoke.Parameters.Count; i++)
645 if (dict.ContainsKey(invoke.Parameters[i].ParameterType.Name))
647 invoke.Parameters[i].ParameterType = dict[invoke.Parameters[i].ParameterType.Name];
653 if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
654 throw new XamlParseException($"Signature (return type) of EventHandler \"{context.Type.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
655 if (invoke.Parameters.Count != handler.Parameters.Count)
656 throw new XamlParseException($"Signature (number of arguments) of EventHandler \"{context.Type.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
657 if (!invoke.ContainsGenericParameter)
658 for (var i = 0; i < invoke.Parameters.Count; i++)
659 if (!handler.Parameters[i].ParameterType.InheritsFromOrImplements(invoke.Parameters[i].ParameterType))
660 throw new XamlParseException($"Signature (parameter {i}) of EventHandler \"{context.Type.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
662 new EXamlAddEvent(context, parent, context.Values[context.RootNode] as EXamlCreateObject, localName, handler);
665 static bool CanSetDynamicResource(MemberReference bpRef, INode valueNode, EXamlContext context)
669 var elementNode = valueNode as IElementNode;
670 if (elementNode == null)
673 var valueInstance = context.Values[valueNode] as EXamlCreateObject;
674 if (null == valueInstance)
677 return valueInstance.GetType().FullName == typeof(DynamicResource).FullName;
680 static void SetDynamicResource(EXamlCreateObject parent, MemberReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, EXamlContext context)
682 var instance = context.Values[elementNode] as EXamlCreateObject;
683 if (null != instance)
685 var dynamicResource = instance.Instance as DynamicResource;
687 if (null != dynamicResource)
689 instance.IsValid = false;
690 new EXamlSetDynamicResource(context, parent, bpRef, dynamicResource.Key);
695 static bool CanSetBinding(MemberReference bpRef, INode valueNode, EXamlContext context)
697 var module = context.Module;
701 var elementNode = valueNode as IElementNode;
702 if (elementNode == null)
705 var valueInstance = context.Values[valueNode] as EXamlCreateObject;
706 if (null == valueInstance)
709 var implicitOperator = valueInstance.GetType().GetImplicitOperatorTo(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindingBase")), module);
710 if (implicitOperator != null)
713 return valueInstance.GetType().InheritsFromOrImplements(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")));
716 static void SetBinding(EXamlCreateObject parent, MemberReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, EXamlContext context)
718 new EXamlSetBinding(context, parent, bpRef, context.Values[elementNode]);
721 static bool CanSetValue(MemberReference bpRef, bool attached, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
723 var module = context.Module;
728 var valueNode = node as ValueNode;
729 if (valueNode != null && valueNode.CanConvertValue(context.Module, bpRef))
732 var elementNode = node as IElementNode;
733 if (elementNode == null)
736 return context.Values.ContainsKey(elementNode);
738 //VariableDefinition varValue;
739 //if (!context.Variables.TryGetValue(elementNode, out varValue))
742 // var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
743 //// If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here.
744 //// Worst case scenario ? InvalidCastException at runtime
745 //if (attached && varValue.VariableType.FullName == "System.Object")
747 //var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
748 //if (implicitOperator != null)
751 ////as we're in the SetValue Scenario, we can accept value types, they'll be boxed
752 //if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object")
755 //return varValue.VariableType.InheritsFromOrImplements(bpTypeRef);
758 static bool CanGetValue(EXamlCreateObject parent, MemberReference bpRef, bool attached, IXmlLineInfo iXmlLineInfo, EXamlContext context, out TypeReference propertyType)
760 var module = context.Module;
766 if (!parent.GetType().InheritsFromOrImplements(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))))
769 propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
773 static void SetValue(EXamlCreateObject parent, MemberReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
775 var valueNode = node as ValueNode;
777 if (valueNode != null)
779 var valueType = bpRef.GetBindablePropertyType(null, context.Module);
780 var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { valueType.Resolve() });
781 if (null != converterType)
783 var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
784 context.Values[node] = new EXamlCreateObject(context, converterValue, valueType);
788 context.Values[node] = valueNode.GetBaseValue(context, valueType);
792 new EXamlSetBindalbeProperty(context, parent, bpRef, context.Values[node]);
795 static void GetValue(EXamlCreateObject parent, FieldReference bpRef, IXmlLineInfo iXmlLineInfo, EXamlContext context, out TypeReference propertyType)
797 var module = context.Module;
798 propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
801 // Create(Ldloc, parent),
802 // Create(Ldsfld, bpRef),
803 // Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
804 // methodName: "GetValue",
805 // parameterTypes: new[] { (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty") })),
809 static bool CanSet(EXamlCreateObject parent, string localName, INode node, EXamlContext context)
811 var module = context.Module;
812 TypeReference declaringTypeReference;
813 var property = parent.GetType().GetProperty(pd => pd.Name == localName, out declaringTypeReference);
814 if (property == null)
816 var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
817 var propertySetter = property.SetMethod;
818 if (propertySetter == null || !propertySetter.IsPublic || propertySetter.IsStatic)
821 var valueNode = node as ValueNode;
822 if (valueNode != null && valueNode.CanConvertValue(context.Module, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached()}))
825 var elementNode = node as IElementNode;
826 if (elementNode == null)
829 var vardef = context.Variables[elementNode];
830 var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
832 var value = context.Values[elementNode] as EXamlCreateObject;
834 if (vardef.VariableType.InheritsFromOrImplements(propertyType))
836 if (null != value && value.GetType().InheritsFromOrImplements(propertyType))
838 if (implicitOperator != null)
840 if (propertyType.FullName == "System.Object")
843 //I'd like to get rid of this condition. This comment used to be //TODO replace latest check by a runtime type check
844 if (vardef.VariableType.FullName == "System.Object")
847 var realValue = context.Values[elementNode] as EXamlCreateObject;
848 if (null != realValue)
850 var valueTypeRef = realValue.GetType();
851 if (valueTypeRef.InheritsFromOrImplements(propertyType))
856 var realTypeFromMarkupExtension = valueTypeRef.GetRealTypeIfIsMarkupExtension();
858 if (true == realTypeFromMarkupExtension?.InheritsFromOrImplements(propertyType))
863 if ("System.Type" == valueTypeRef.FullName && "Mono.Cecil.TypeReference" == propertyType.FullName)
872 static bool CanGet(EXamlCreateObject parent, string localName, EXamlContext context, out TypeReference propertyType)
874 var module = context.Module;
876 TypeReference declaringTypeReference;
877 var property = parent.GetType().GetProperty(pd => pd.Name == localName, out declaringTypeReference);
878 if (property == null)
880 var propertyGetter = property.GetMethod;
881 if (propertyGetter == null || !propertyGetter.IsPublic || propertyGetter.IsStatic)
884 module.ImportReference(parent.GetType().ResolveCached());
885 var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
886 propertyGetterRef.ImportTypes(module);
887 propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
892 static void Set(EXamlCreateObject parent, string localName, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
894 var module = context.Module;
895 TypeReference declaringTypeReference;
896 var property = parent.Type.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
897 var propertySetter = property.SetMethod;
899 //// IL_0007: ldloc.0
900 //// IL_0008: ldstr "foo"
901 //// IL_000d: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Label::set_Text(string)
903 var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
904 propertySetterRef.ImportTypes(module);
905 var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
906 var valueNode = node as ValueNode;
907 var elementNode = node as IElementNode;
909 //if it's a value type, load the address so we can invoke methods on it
910 if (parent.Type.IsValueType)
912 // yield return Instruction.Create(OpCodes.Ldloca, parent);
916 // yield return Instruction.Create(OpCodes.Ldloc, parent);
919 if (valueNode != null)
921 if ("Tizen.NUI.Binding.BindableProperty" == propertyType.FullName)
923 var bindableProperty = BindablePropertyConverter.GetBindablePropertyFieldReference(valueNode.Value as string, module, node as BaseNode);
924 var fieldRef = bindableProperty.DeclaringType.ResolveCached().Fields.FirstOrDefault(a => a.FullName == bindableProperty.FullName);
925 context.Values[node] = new EXamlCreateObject(context, bindableProperty.DeclaringType, fieldRef, null);
927 else if ("Tizen.NUI.Binding.ResourceDictionary" == propertyType.FullName)
929 context.Values[node] = GetResourceDictionaryByXaml(parent, node, context, iXmlLineInfo);
933 var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { property, propertyType.ResolveCached() });
934 if (null != converterType)
936 var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
937 context.Values[node] = new EXamlCreateObject(context, converterValue, propertyType);
941 context.Values[node] = valueNode.GetBaseValue(context, property.PropertyType);
945 else if (elementNode != null)
947 var vardef = context.Variables[elementNode];
948 var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
949 //yield return Instruction.Create(OpCodes.Ldloc, vardef);
950 if (!vardef.VariableType.InheritsFromOrImplements(propertyType) && implicitOperator != null)
952 // IL_000f: call !0 class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<bool>::op_Implicit(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<!0>)
953 //yield return Instruction.Create(OpCodes.Call, module.ImportReference(implicitOperator));
955 else if (!vardef.VariableType.IsValueType && propertyType.IsValueType)
957 //yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(propertyType));
959 else if (vardef.VariableType.IsValueType && propertyType.FullName == "System.Object")
961 //yield return Instruction.Create(OpCodes.Box, vardef.VariableType);
963 if (parent.Type.IsValueType)
965 //yield return Instruction.Create(OpCodes.Call, propertySetterRef);
969 //yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
973 new EXamlSetProperty(context, parent, localName, context.Values[node]);
976 static void Get(EXamlCreateObject parent, string localName, IXmlLineInfo iXmlLineInfo, EXamlContext context, out TypeReference propertyType)
978 var module = context.Module;
979 var property = parent.GetType().GetProperty(pd => pd.Name == localName, out var declaringTypeReference);
980 var propertyGetter = property.GetMethod;
982 module.ImportReference(parent.GetType().ResolveCached());
983 var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
984 propertyGetterRef.ImportTypes(module);
985 propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
987 //if (parent.VariableType.IsValueType)
989 // Instruction.Create(OpCodes.Ldloca, parent),
990 // Instruction.Create(OpCodes.Call, propertyGetterRef),
994 // Instruction.Create(OpCodes.Ldloc, parent),
995 // Instruction.Create(OpCodes.Callvirt, propertyGetterRef),
999 static bool CanAdd(EXamlCreateObject parent, XmlName propertyName, INode node, IXmlLineInfo lineInfo, EXamlContext context)
1001 var module = context.Module;
1002 var localName = propertyName.LocalName;
1004 var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
1005 TypeReference propertyType;
1007 if ( !CanGetValue(parent, bpRef, attached, null, context, out propertyType)
1008 && !CanGet(parent, localName, context, out propertyType))
1011 //TODO check md.Parameters[0] type
1012 var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
1013 if (adderTuple == null)
1019 static Dictionary<EXamlCreateObject, IList<string>> resourceNamesInUse = new Dictionary<EXamlCreateObject, IList<string>>();
1020 static bool CanAddToResourceDictionary(EXamlCreateObject parent, TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, EXamlContext context)
1022 if (collectionType.IsLocalType())
1027 if ( collectionType.FullName != "Tizen.NUI.Binding.ResourceDictionary"
1028 && collectionType.ResolveCached().BaseType?.FullName != "Tizen.NUI.Binding.ResourceDictionary")
1032 if (node.Properties.ContainsKey(XmlName.xKey)) {
1033 var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
1034 if (!resourceNamesInUse.TryGetValue(parent, out var names))
1035 resourceNamesInUse[parent] = (names = new List<string>());
1036 if (names.Contains(key))
1037 throw new XamlParseException($"A resource with the key '{key}' is already present in the ResourceDictionary.", lineInfo);
1042 //is there a RD.Add() overrides that accepts this ?
1043 var nodeTypeRef = context.Variables[node].VariableType;
1044 var module = context.Module;
1045 if (module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
1047 parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }) != null)
1050 throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
1053 static void Add(EXamlCreateObject parent, string propertyName, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
1055 //Fang: Need to deal
1056 var module = context.Module;
1057 var elementNode = node as IElementNode;
1059 TypeReference declaringTypeReference;
1060 var property = parent.Type.GetProperty(pd => pd.Name == propertyName, out declaringTypeReference);
1061 TypeReference propertyType = property.PropertyType;
1063 if (null != elementNode && CanAddToResourceDictionary(parent, propertyType, elementNode, iXmlLineInfo, context))
1065 var keyName = (elementNode.Properties[XmlName.xKey] as ValueNode).Value as string;
1066 new EXamlAddToResourceDictionary(context, parent, keyName, context.Values[node]);
1070 var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
1071 var adderRef = module.ImportReference(adderTuple.Item1);
1072 adderRef = module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
1073 var childType = GetParameterType(adderRef.Parameters[0]);
1075 if (node is ValueNode valueNode)
1077 if (true == valueNode.CanConvertValue(module, childType, (TypeReference)null))
1079 var obj = new EXamlGetObjectByProperty(context, parent, propertyName);
1081 var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { property, childType.ResolveCached() });
1082 if (null != converterType)
1084 var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
1085 context.Values[node] = new EXamlCreateObject(context, converterValue, propertyType);
1089 context.Values[node] = valueNode.GetBaseValue(context, childType);
1091 new EXamlAddToCollectionProperty(context, obj, context.Values[node]);
1094 else if (node is ElementNode element)
1096 var obj = new EXamlGetObjectByProperty(context, parent, propertyName);
1097 new EXamlAddToCollectionProperty(context, obj, context.Values[node]);
1101 static IEnumerable<Instruction> AddToResourceDictionary(IElementNode node, IXmlLineInfo lineInfo, EXamlContext context)
1103 var module = context.Module;
1105 if (node.Properties.ContainsKey(XmlName.xKey)) {
1106 // IL_0014: ldstr "key"
1107 // IL_0019: ldstr "foo"
1108 // IL_001e: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.ResourceDictionary::Add(string, object)
1109 yield return Create(Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
1110 var varDef = context.Variables[node];
1111 yield return Create(Ldloc, varDef);
1112 if (varDef.VariableType.IsValueType)
1113 yield return Create(Box, module.ImportReference(varDef.VariableType));
1114 yield return Create(Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
1116 parameterTypes: new[] {
1117 ("mscorlib", "System", "String"),
1118 ("mscorlib", "System", "Object"),
1123 var nodeTypeRef = context.Variables[node].VariableType;
1124 yield return Create(Ldloc, context.Variables[node]);
1125 yield return Create(Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
1127 parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }));
1131 public static TypeReference GetParameterType(ParameterDefinition param)
1133 if (!param.ParameterType.IsGenericParameter)
1134 return param.ParameterType;
1135 var type = (param.Method as MethodReference).DeclaringType as GenericInstanceType;
1136 return type.GenericArguments [0];
1139 static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname,
1140 EXamlContext context, IXmlLineInfo lineInfo)
1142 var dotIdx = localname.IndexOf('.');
1145 var typename = localname.Substring(0, dotIdx);
1146 localname = localname.Substring(dotIdx + 1);
1147 elementType = new XmlType(namespaceURI, typename, null).GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, context.Module, lineInfo);
1153 static void SetDataTemplate(ElementNode parentNode, ElementNode rootnode, EXamlContext parentContext, IXmlLineInfo xmlLineInfo)
1155 var typeref = parentContext.Module.ImportReference(rootnode.XmlType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, parentContext.Module, rootnode));
1156 var visitorContext = new EXamlContext(typeref.ResolveCached(), typeref.Module, parentContext.EmbeddedResourceNameSpace);
1158 rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
1159 rootnode.Accept(new EXamlExpandMarkupsVisitor(visitorContext), null);
1160 rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
1161 rootnode.Accept(new EXamlCreateObjectVisitor(visitorContext), null);
1162 rootnode.Accept(new EXamlSetNamescopesAndRegisterNamesVisitor(visitorContext), null);
1163 rootnode.Accept(new EXamlSetFieldVisitor(visitorContext), null);
1164 rootnode.Accept(new EXamlSetResourcesVisitor(visitorContext), null);
1165 rootnode.Accept(new EXamlSetPropertiesVisitor(visitorContext, true), null);
1167 var eXamlString = visitorContext.GenerateEXamlString();
1169 var parentTyperef = parentContext.Module.ImportReference(parentNode.XmlType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, parentContext.Module, parentNode));
1171 if (parentContext.Values[parentNode] is EXamlCreateObject eXamlObject)
1173 eXamlObject.IsValid = false;
1174 parentContext.Values[parentNode] = new EXamlCreateDataTemplate(parentContext, parentTyperef, eXamlString);
1178 static EXamlCreateResourceDictionary GetResourceDictionaryByXaml(EXamlCreateObject parentObject, INode nodeOfXaml, EXamlContext parentContext, IXmlLineInfo xmlLineInfo)
1180 var module = parentContext.Module;
1182 string xamlName = "";
1184 if (nodeOfXaml is ValueNode valueNode)
1186 xamlName = valueNode.Value as string;
1189 EmbeddedResource matchedResource = null;
1191 foreach (var resource in module.Resources.OfType<EmbeddedResource>())
1193 if (resource.Name.StartsWith(parentContext.EmbeddedResourceNameSpace) && resource.Name.EndsWith(xamlName))
1195 matchedResource = resource;
1200 if (null == matchedResource)
1202 foreach (var resource in module.Resources.OfType<EmbeddedResource>())
1204 if (resource.Name.EndsWith(xamlName))
1206 matchedResource = resource;
1212 if (null != matchedResource)
1216 if (matchedResource.IsResourceDictionaryXaml(module, out classname))
1218 int lastIndex = classname.LastIndexOf('.');
1219 var realClassName = classname.Substring(lastIndex + 1);
1220 var typeref = XmlTypeExtensions.GetTypeReference(realClassName, module, nodeOfXaml as BaseNode, XmlTypeExtensions.ModeOfGetType.Both);
1222 var visitorContext = new EXamlContext(typeref.ResolveCached(), typeref.Module, parentContext.EmbeddedResourceNameSpace);
1223 var rootnode = XamlTask.ParseXaml(matchedResource.GetResourceStream(), typeref);
1225 var rootInstance = new EXamlCreateObject(visitorContext, null, typeref);
1226 visitorContext.Values[rootnode] = rootInstance;
1228 rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
1229 rootnode.Accept(new EXamlExpandMarkupsVisitor(visitorContext), null);
1230 rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
1231 rootnode.Accept(new EXamlCreateObjectVisitor(visitorContext), null);
1232 rootnode.Accept(new EXamlSetNamescopesAndRegisterNamesVisitor(visitorContext), null);
1233 rootnode.Accept(new EXamlSetFieldVisitor(visitorContext), null);
1234 rootnode.Accept(new EXamlSetResourcesVisitor(visitorContext), null);
1235 rootnode.Accept(new EXamlSetPropertiesVisitor(visitorContext, true), null);
1237 foreach (var pair in visitorContext.resourceDictionary)
1239 parentContext.resourceDictionary.Add(pair.Key, pair.Value);
1242 return new EXamlCreateResourceDictionary(parentContext, typeref, visitorContext.GenerateEXamlString());
1249 bool TrySetRuntimeName(XmlName propertyName, EXamlCreateObject variableDefinition, ValueNode node)
1251 if (null == variableDefinition)
1256 if (propertyName != XmlName.xName)
1259 var attributes = variableDefinition.GetType().ResolveCached()
1260 .CustomAttributes.Where(attribute => attribute.AttributeType.FullName == "Tizen.NUI.Xaml.RuntimeNamePropertyAttribute").ToList();
1262 if (!attributes.Any())
1265 var runTimeName = attributes[0].ConstructorArguments[0].Value as string;
1267 if (string.IsNullOrEmpty(runTimeName))
1270 SetPropertyValue(variableDefinition, new XmlName("", runTimeName), node, Context, node);