2 using System.Collections.Generic;
8 using Mono.Cecil.Rocks;
10 using Xamarin.Forms.Internals;
11 using Xamarin.Forms.Xaml;
13 using static Mono.Cecil.Cil.Instruction;
14 using static Mono.Cecil.Cil.OpCodes;
16 namespace Xamarin.Forms.Build.Tasks
18 class SetPropertiesVisitor : IXamlNodeVisitor
21 static int typedBindingCount;
23 static readonly IList<XmlName> skips = new List<XmlName>
26 XmlName.xTypeArguments,
28 XmlName.xFactoryMethod,
33 public SetPropertiesVisitor(ILContext context, bool stopOnResourceDictionary = false)
36 Module = context.Body.Method.Module;
37 StopOnResourceDictionary = stopOnResourceDictionary;
40 public ILContext Context { get; }
41 public bool StopOnResourceDictionary { get; }
42 public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
43 public bool StopOnDataTemplate => true;
44 public bool VisitNodeOnDataTemplate => true;
45 public bool SkipChildren(INode node, INode parentNode) => false;
47 public bool IsResourceDictionary(ElementNode node)
49 var parentVar = Context.Variables[(IElementNode)node];
50 return parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary"
51 || parentVar.VariableType.Resolve().BaseType?.FullName == "Xamarin.Forms.ResourceDictionary";
54 ModuleDefinition Module { get; }
56 public void Visit(ValueNode node, INode parentNode)
58 //TODO support Label text as element
60 if (!TryGetPropertyName(node, parentNode, out propertyName))
62 if (!IsCollectionItem(node, parentNode))
64 string contentProperty;
65 if (!Context.Variables.ContainsKey((IElementNode)parentNode))
67 var parentVar = Context.Variables[(IElementNode)parentNode];
68 if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
69 propertyName = new XmlName(((IElementNode)parentNode).NamespaceURI, contentProperty);
74 if (TrySetRuntimeName(propertyName, Context.Variables[(IElementNode)parentNode], node))
76 if (skips.Contains(propertyName))
78 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
80 if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
82 Context.IL.Append(SetPropertyValue(Context.Variables [(IElementNode)parentNode], propertyName, node, Context, node));
85 public void Visit(MarkupNode node, INode parentNode)
89 public void Visit(ElementNode node, INode parentNode)
91 XmlName propertyName = XmlName.Empty;
93 //Simplify ListNodes with single elements
94 var pList = parentNode as ListNode;
95 if (pList != null && pList.CollectionItems.Count == 1) {
96 propertyName = pList.XmlName;
97 parentNode = parentNode.Parent;
100 if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName))
103 if (propertyName == XmlName._CreateContent) {
104 SetDataTemplate((IElementNode)parentNode, node, Context, node);
108 //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
109 var vardef = Context.Variables[node];
110 var vardefref = new VariableDefinitionReference(vardef);
111 var localName = propertyName.LocalName;
112 TypeReference declaringTypeReference = null;
113 FieldReference bpRef = null;
115 PropertyDefinition propertyRef = null;
116 if (parentNode is IElementNode && propertyName != XmlName.Empty) {
117 bpRef = GetBindablePropertyReference(Context.Variables [(IElementNode)parentNode], propertyName.NamespaceURI, ref localName, out _, Context, node);
118 propertyRef = Context.Variables [(IElementNode)parentNode].VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
120 Context.IL.Append(ProvideValue(vardefref, Context, Module, node, bpRef:bpRef, propertyRef:propertyRef, propertyDeclaringTypeRef: declaringTypeReference));
121 if (vardef != vardefref.VariableDefinition)
123 vardef = vardefref.VariableDefinition;
124 Context.Body.Variables.Add(vardef);
125 Context.Variables[node] = vardef;
128 if (propertyName != XmlName.Empty) {
129 if (skips.Contains(propertyName))
131 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
134 Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
136 else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
137 var parentVar = Context.Variables[(IElementNode)parentNode];
138 string contentProperty;
140 if (CanAddToResourceDictionary(parentVar, parentVar.VariableType, node, node, Context)) {
141 Context.IL.Append(parentVar.LoadAs(Module.GetTypeDefinition(("XSF", "Xamarin.Forms", "ResourceDictionary")), Module));
142 Context.IL.Append(AddToResourceDictionary(node, node, Context));
144 // Collection element, implicit content, or implicit collection element.
145 else if ( parentVar.VariableType.ImplementsInterface(Module.ImportReference(("mscorlib", "System.Collections", "IEnumerable")))
146 && parentVar.VariableType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).Any()) {
147 var elementType = parentVar.VariableType;
148 var adderTuple = elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
149 var adderRef = Module.ImportReference(adderTuple.Item1);
150 adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
152 Context.IL.Emit(Ldloc, parentVar);
153 Context.IL.Append(vardef.LoadAs(adderRef.Parameters[0].ParameterType.ResolveGenericParameters(adderRef), Module));
154 Context.IL.Emit(Callvirt, adderRef);
155 if (adderRef.ReturnType.FullName != "System.Void")
156 Context.IL.Emit(Pop);
158 else if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null) {
159 var name = new XmlName(node.NamespaceURI, contentProperty);
160 if (skips.Contains(name))
162 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
164 Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node));
167 throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
169 else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
172 // IL_000e: callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Xamarin.Forms.Core]Xamarin.Forms.Layout`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::get_Children()
174 // IL_0014: callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::Add(!0)
176 var parentList = (ListNode)parentNode;
177 var parent = Context.Variables[((IElementNode)parentNode.Parent)];
179 if (skips.Contains(parentList.XmlName))
181 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
183 var elementType = parent.VariableType;
184 var localname = parentList.XmlName.LocalName;
186 TypeReference propertyType;
187 Context.IL.Append(GetPropertyValue(parent, parentList.XmlName, Context, node, out propertyType));
189 if (CanAddToResourceDictionary(parent, propertyType, node, node, Context)) {
190 Context.IL.Append(AddToResourceDictionary(node, node, Context));
193 var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).FirstOrDefault();
194 if (adderTuple == null)
195 throw new XamlParseException($"Can not Add() elements to {parent.VariableType}.{localname}", node);
196 var adderRef = Module.ImportReference(adderTuple.Item1);
197 adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
199 Context.IL.Append(vardef.LoadAs(adderRef.Parameters[0].ParameterType.ResolveGenericParameters(adderRef), Module));
200 Context.IL.Emit(OpCodes.Callvirt, adderRef);
201 if (adderRef.ReturnType.FullName != "System.Void")
202 Context.IL.Emit(OpCodes.Pop);
206 public void Visit(RootNode node, INode parentNode)
210 public void Visit(ListNode node, INode parentNode)
214 public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
216 name = default(XmlName);
217 if (!(parentNode is IElementNode parentElement))
219 foreach (var kvp in parentElement.Properties)
221 if (kvp.Value != node)
229 static bool IsCollectionItem(INode node, INode parentNode)
231 if (!(parentNode is IListNode parentList))
233 return parentList.CollectionItems.Contains(node);
236 internal static string GetContentProperty(TypeReference typeRef)
238 var typeDef = typeRef.ResolveCached();
239 var attributes = typeDef.CustomAttributes;
241 attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
243 return attr.ConstructorArguments[0].Value as string;
244 if (typeDef.BaseType == null)
246 return GetContentProperty(typeDef.BaseType);
249 public static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
250 ModuleDefinition module, ElementNode node, FieldReference bpRef = null,
251 PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
253 GenericInstanceType markupExtension;
254 IList<TypeReference> genericArguments;
255 if (vardefref.VariableDefinition.VariableType.FullName == "Xamarin.Forms.Xaml.ArrayExtension" &&
256 vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
257 out markupExtension, out genericArguments))
259 var markExt = markupExtension.ResolveCached();
260 var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
261 var provideValue = module.ImportReference(provideValueInfo);
263 module.ImportReference(provideValue.ResolveGenericParameters(markupExtension, module));
265 var typeNode = node.Properties[new XmlName("", "Type")];
266 TypeReference arrayTypeRef;
267 if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef))
268 vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(arrayTypeRef.MakeArrayType()));
270 vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(genericArguments.First()));
271 foreach (var instruction in context.Variables[node].LoadAs(markupExtension, module))
272 yield return instruction;
273 foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
274 yield return instruction;
275 yield return Instruction.Create(OpCodes.Callvirt, provideValue);
277 if (arrayTypeRef != null)
278 yield return Instruction.Create(OpCodes.Castclass, module.ImportReference(arrayTypeRef.MakeArrayType()));
279 yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
281 else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
282 out markupExtension, out genericArguments))
284 var acceptEmptyServiceProvider = vardefref.VariableDefinition.VariableType.GetCustomAttribute(module, ("XSF", "Xamarin.Forms.Xaml", "AcceptEmptyServiceProviderAttribute")) != null;
285 if ( vardefref.VariableDefinition.VariableType.FullName == "Xamarin.Forms.Xaml.BindingExtension"
286 && (node.Properties == null || !node.Properties.ContainsKey(new XmlName("", "Source"))) //do not compile bindings if Source is set
287 && bpRef != null //do not compile bindings if we're not gonna SetBinding
289 foreach (var instruction in CompileBindingPath(node, context, vardefref.VariableDefinition))
290 yield return instruction;
292 var markExt = markupExtension.ResolveCached();
293 var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
294 var provideValue = module.ImportReference(provideValueInfo);
296 module.ImportReference(provideValue.ResolveGenericParameters(markupExtension, module));
298 vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(genericArguments.First()));
299 foreach (var instruction in context.Variables[node].LoadAs(markupExtension, module))
300 yield return instruction;
301 if (acceptEmptyServiceProvider)
302 yield return Instruction.Create(OpCodes.Ldnull);
304 foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
305 yield return instruction;
306 yield return Instruction.Create(OpCodes.Callvirt, provideValue);
307 yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
309 else if (context.Variables[node].VariableType.ImplementsInterface(module.ImportReference(("XSF", "Xamarin.Forms.Xaml", "IMarkupExtension"))))
311 var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, ("XSF", "Xamarin.Forms.Xaml", "AcceptEmptyServiceProviderAttribute")) != null;
312 var markupExtensionType = ("XSF", "Xamarin.Forms.Xaml", "IMarkupExtension");
313 vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
314 foreach (var instruction in context.Variables[node].LoadAs(module.GetTypeDefinition(markupExtensionType), module))
315 yield return instruction;
316 if (acceptEmptyServiceProvider)
317 yield return Create(Ldnull);
319 foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
320 yield return instruction;
321 yield return Create(Callvirt, module.ImportMethodReference(markupExtensionType,
322 methodName: "ProvideValue",
323 parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
324 yield return Create(Stloc, vardefref.VariableDefinition);
326 else if (context.Variables[node].VariableType.ImplementsInterface(module.ImportReference(("XSF", "Xamarin.Forms.Xaml", "IValueProvider"))))
328 var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, ("XSF", "Xamarin.Forms.Xaml", "AcceptEmptyServiceProviderAttribute")) != null;
329 var valueProviderType = context.Variables[node].VariableType;
330 //If the IValueProvider has a ProvideCompiledAttribute that can be resolved, shortcut this
331 var compiledValueProviderName = valueProviderType?.GetCustomAttribute(module, ("XSF", "Xamarin.Forms.Xaml", "ProvideCompiledAttribute"))?.ConstructorArguments?[0].Value as string;
332 Type compiledValueProviderType;
333 if (compiledValueProviderName != null && (compiledValueProviderType = Type.GetType(compiledValueProviderName)) != null) {
334 var compiledValueProvider = Activator.CreateInstance(compiledValueProviderType);
335 var cProvideValue = typeof(ICompiledValueProvider).GetMethods().FirstOrDefault(md => md.Name == "ProvideValue");
336 var instructions = (IEnumerable<Instruction>)cProvideValue.Invoke(compiledValueProvider, new object[] {
338 context.Body.Method.Module,
341 foreach (var i in instructions)
346 var valueProviderInterface = ("XSF", "Xamarin.Forms.Xaml", "IValueProvider");
347 vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
348 foreach (var instruction in context.Variables[node].LoadAs(module.GetTypeDefinition(valueProviderInterface), module))
349 yield return instruction;
350 if (acceptEmptyServiceProvider)
351 yield return Create(Ldnull);
353 foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
354 yield return instruction;
355 yield return Create(Callvirt, module.ImportMethodReference(valueProviderInterface,
356 methodName: "ProvideValue",
357 parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
358 yield return Create(Stloc, vardefref.VariableDefinition);
362 //Once we get compiled IValueProvider, this will move to the BindingExpression
363 static IEnumerable<Instruction> CompileBindingPath(ElementNode node, ILContext context, VariableDefinition bindingExt)
365 //TODO support casting operators
366 var module = context.Module;
368 if (!node.Properties.TryGetValue(new XmlName("", "Path"), out INode pathNode) && node.CollectionItems.Any())
369 pathNode = node.CollectionItems[0];
370 var path = (pathNode as ValueNode)?.Value as string;
371 if ( !node.Properties.TryGetValue(new XmlName("", "Mode"), out INode modeNode)
372 || !Enum.TryParse((modeNode as ValueNode)?.Value as string, true, out BindingMode declaredmode))
373 declaredmode = BindingMode.TwoWay; //meaning the mode isn't specified in the Binding extension. generate getters, setters, handlers
375 INode dataTypeNode = null;
376 IElementNode n = node;
378 if (n.Properties.TryGetValue(XmlName.xDataType, out dataTypeNode))
380 n = n.Parent as IElementNode;
383 if (dataTypeNode is null)
386 if ( dataTypeNode is ElementNode enode
387 && enode.XmlType.NamespaceUri == XamlParser.X2009Uri
388 && enode.XmlType.Name == nameof(Xamarin.Forms.Xaml.NullExtension))
391 string dataType = null;
393 if ( dataTypeNode is ElementNode elementNode
394 && elementNode.XmlType.NamespaceUri == XamlParser.X2009Uri
395 && elementNode.XmlType.Name == nameof(Xamarin.Forms.Xaml.TypeExtension)
396 && elementNode.Properties.ContainsKey(new XmlName("", nameof(Xamarin.Forms.Xaml.TypeExtension.TypeName)))
397 && (elementNode.Properties[new XmlName("", nameof(Xamarin.Forms.Xaml.TypeExtension.TypeName))] as ValueNode)?.Value is string stringtype)
398 dataType = stringtype;
400 if ((dataTypeNode as ValueNode)?.Value is string sType)
403 if (dataType is null)
404 throw new XamlParseException("x:DataType expects a string literal, an {x:Type} markup or {x:Null}", dataTypeNode as IXmlLineInfo);
406 var prefix = dataType.Contains(":") ? dataType.Substring(0, dataType.IndexOf(":", StringComparison.Ordinal)) : "";
407 var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
408 if (!string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(namespaceuri))
409 throw new XamlParseException($"Undeclared xmlns prefix '{prefix}'", dataTypeNode as IXmlLineInfo);
411 var dtXType = new XmlType(namespaceuri, dataType, null);
413 var tSourceRef = dtXType.GetTypeReference(module, (IXmlLineInfo)node);
414 if (tSourceRef == null)
417 var properties = ParsePath(path, tSourceRef, node as IXmlLineInfo, module);
418 TypeReference tPropertyRef = tSourceRef;
419 if (properties != null && properties.Count > 0) {
420 var lastProp = properties[properties.Count - 1];
421 tPropertyRef = lastProp.property.PropertyType.ResolveGenericParameters(lastProp.propDeclTypeRef);
423 tPropertyRef = module.ImportReference(tPropertyRef);
424 var valuetupleRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "ValueTuple`2")).MakeGenericInstanceType(new[] { tPropertyRef, module.TypeSystem.Boolean }));
425 var funcRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, valuetupleRef }));
426 var actionRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Action`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef }));
427 var funcObjRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, module.TypeSystem.Object }));
428 var tupleRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Tuple`2")).MakeGenericInstanceType(new [] { funcObjRef, module.TypeSystem.String}));
429 var typedBindingRef = module.ImportReference(module.ImportReference(("XSF", "Xamarin.Forms.Internals", "TypedBinding`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef}));
431 //FIXME: make sure the non-deprecated one is used
432 var ctorInfo = module.ImportReference(typedBindingRef.ResolveCached().Methods.FirstOrDefault(md =>
435 && md.Parameters.Count == 3
436 && !md.HasCustomAttributes (module.ImportReference(("mscorlib", "System", "ObsoleteAttribute")))));
437 var ctorinforef = ctorInfo.MakeGeneric(typedBindingRef, funcRef, actionRef, tupleRef);
439 var bindingExtensionType = ("XSF", "Xamarin.Forms.Xaml", "BindingExtension");
441 foreach (var instruction in bindingExt.LoadAs(module.GetTypeDefinition(bindingExtensionType), module))
442 yield return instruction;
443 foreach (var instruction in CompiledBindingGetGetter(tSourceRef, tPropertyRef, properties, node, context))
444 yield return instruction;
445 if (declaredmode != BindingMode.OneTime && declaredmode != BindingMode.OneWay) { //if the mode is explicitly 1w, or 1t, no need for setters
446 foreach (var instruction in CompiledBindingGetSetter(tSourceRef, tPropertyRef, properties, node, context))
447 yield return instruction;
449 yield return Create(Ldnull);
450 if (declaredmode != BindingMode.OneTime) { //if the mode is explicitly 1t, no need for handlers
451 foreach (var instruction in CompiledBindingGetHandlers(tSourceRef, tPropertyRef, properties, node, context))
452 yield return instruction;
454 yield return Create(Ldnull);
455 yield return Create(Newobj, module.ImportReference(ctorinforef));
456 yield return Create(Callvirt, module.ImportPropertySetterReference(bindingExtensionType, propertyName: "TypedBinding"));
459 static IList<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)> ParsePath(string path, TypeReference tSourceRef, IXmlLineInfo lineInfo, ModuleDefinition module)
461 if (string.IsNullOrWhiteSpace(path))
463 path = path.Trim(' ', '.'); //trim leading or trailing dots
464 var parts = path.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
465 var properties = new List<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)>();
467 var previousPartTypeRef = tSourceRef;
468 foreach (var part in parts) {
470 string indexArg = null;
471 var lbIndex = p.IndexOf('[');
473 var rbIndex = p.LastIndexOf(']');
475 throw new XamlParseException("Binding: Indexer did not contain closing bracket", lineInfo);
477 var argLength = rbIndex - lbIndex - 1;
479 throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
481 indexArg = p.Substring(lbIndex + 1, argLength).Trim();
482 if (indexArg.Length == 0)
483 throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
485 p = p.Substring(0, lbIndex);
490 var property = previousPartTypeRef.GetProperty(pd => pd.Name == p && pd.GetMethod != null && pd.GetMethod.IsPublic, out var propDeclTypeRef)
491 ?? throw new XamlParseException($"Binding: Property '{p}' not found on '{previousPartTypeRef}'", lineInfo);
492 properties.Add((property, propDeclTypeRef, null));
493 previousPartTypeRef = property.PropertyType.ResolveGenericParameters(propDeclTypeRef);
495 if (indexArg != null) {
496 var defaultMemberAttribute = previousPartTypeRef.GetCustomAttribute(module, ("mscorlib", "System.Reflection", "DefaultMemberAttribute"));
497 var indexerName = defaultMemberAttribute?.ConstructorArguments?.FirstOrDefault().Value as string ?? "Item";
498 PropertyDefinition indexer = null;
499 TypeReference indexerDeclTypeRef = null;
500 if (int.TryParse(indexArg, out _))
501 indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName
502 && pd.GetMethod != null
503 && TypeRefComparer.Default.Equals(pd.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(previousPartTypeRef), module.ImportReference(("mscorlib", "System", "Int32")))
504 && pd.GetMethod.IsPublic, out indexerDeclTypeRef);
505 indexer = indexer ?? previousPartTypeRef.GetProperty(pd => pd.Name == indexerName
506 && pd.GetMethod != null
507 && TypeRefComparer.Default.Equals(pd.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(previousPartTypeRef), module.ImportReference(("mscorlib", "System", "String")))
508 && pd.GetMethod.IsPublic, out indexerDeclTypeRef);
509 indexer = indexer ?? previousPartTypeRef.GetProperty(pd => pd.Name == indexerName
510 && pd.GetMethod != null
511 && TypeRefComparer.Default.Equals(pd.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(previousPartTypeRef), module.ImportReference(("mscorlib", "System", "Object")))
512 && pd.GetMethod.IsPublic, out indexerDeclTypeRef);
514 properties.Add((indexer, indexerDeclTypeRef, indexArg));
515 var indexType = indexer.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(indexerDeclTypeRef);
516 if (!TypeRefComparer.Default.Equals(indexType, module.TypeSystem.String) && !TypeRefComparer.Default.Equals(indexType, module.TypeSystem.Int32))
517 throw new XamlParseException($"Binding: Unsupported indexer index type: {indexType.FullName}", lineInfo);
518 previousPartTypeRef = indexer.PropertyType.ResolveGenericParameters(indexerDeclTypeRef);
524 static IEnumerable<Instruction> DigProperties(IEnumerable<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)> properties, Dictionary<TypeReference, VariableDefinition> locs, Func<Instruction> fallback, IXmlLineInfo lineInfo, ModuleDefinition module)
528 foreach (var (property, propDeclTypeRef, indexArg) in properties) {
529 if (!first && propDeclTypeRef.IsValueType) {
530 var importedPropDeclTypeRef = module.ImportReference(propDeclTypeRef);
532 if (!locs.TryGetValue(importedPropDeclTypeRef, out var loc)) {
533 loc = new VariableDefinition(importedPropDeclTypeRef);
534 locs[importedPropDeclTypeRef] = loc;
537 yield return Create(Stloc, loc);
538 yield return Create(Ldloca, loc);
541 if (fallback != null && !propDeclTypeRef.IsValueType) {
542 yield return Create(Dup);
543 yield return Create(Brfalse, fallback());
546 if (indexArg != null) {
547 var indexType = property.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(propDeclTypeRef);
548 if (TypeRefComparer.Default.Equals(indexType, module.TypeSystem.String))
549 yield return Create(Ldstr, indexArg);
550 else if (TypeRefComparer.Default.Equals(indexType, module.TypeSystem.Int32) && int.TryParse(indexArg, out int index))
551 yield return Create(Ldc_I4, index);
553 throw new XamlParseException($"Binding: {indexArg} could not be parsed as an index for a {property.Name}", lineInfo);
556 var getMethod = module.ImportReference((module.ImportReference(property.GetMethod)).ResolveGenericParameters(propDeclTypeRef, module));
558 if (property.GetMethod.IsVirtual)
559 yield return Create(Callvirt, getMethod);
561 yield return Create(Call, getMethod);
567 static IEnumerable<Instruction> CompiledBindingGetGetter(TypeReference tSourceRef, TypeReference tPropertyRef, IList<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)> properties, ElementNode node, ILContext context)
569 // .method private static hidebysig default valuetype[mscorlib] System.ValueTuple`2<string, bool> '<Main>m__0' (class ViewModel A_0) cil managed
571 // .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
576 // IL_0005: brfalse IL_0013
580 // IL_000d: newobj instance void valuetype[mscorlib]System.ValueTuple`2<string, bool>::'.ctor'(!0, !1)
583 // IL_0014: call instance string class ViewModel::get_Text()
585 // IL_001a: newobj instance void valuetype[mscorlib]System.ValueTuple`2<string, bool>::'.ctor'(!0, !1)
589 var module = context.Module;
590 var tupleRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "ValueTuple`2")).MakeGenericInstanceType(new[] { tPropertyRef, module.TypeSystem.Boolean }));
591 var tupleCtorRef = module.ImportCtorReference(tupleRef, 2);
592 tupleCtorRef = module.ImportReference(tupleCtorRef.ResolveGenericParameters(tupleRef, module));
593 var getter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}",
594 MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static,
596 Parameters = { new ParameterDefinition(tSourceRef) },
597 CustomAttributes = { new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null)) }
600 getter.Body.InitLocals = true;
601 var il = getter.Body.GetILProcessor();
603 if (properties == null || properties.Count == 0) { //return self
605 il.Emit(Ldc_I4_1); //true
606 il.Emit(Newobj, tupleCtorRef);
610 var locs = new Dictionary<TypeReference, VariableDefinition>();
612 if (tSourceRef.IsValueType)
613 il.Emit(Ldarga_S, (byte)0);
617 Instruction pop = null;
618 il.Append(DigProperties(properties, locs, () => {
623 }, node as IXmlLineInfo, module));
625 foreach (var loc in locs.Values)
626 getter.Body.Variables.Add(loc);
628 il.Emit(Ldc_I4_1); //true
629 il.Emit(Newobj, tupleCtorRef);
633 if (!locs.TryGetValue(tupleRef, out var defaultValueVarDef)) {
634 defaultValueVarDef = new VariableDefinition(tupleRef);
635 getter.Body.Variables.Add(defaultValueVarDef);
639 il.Emit(Ldloca_S, defaultValueVarDef);
640 il.Emit(Initobj, tupleRef);
641 il.Emit(Ldloc, defaultValueVarDef);
645 context.Body.Method.DeclaringType.Methods.Add(getter);
648 // IL_02fb: ldftn valuetype[mscorlib]System.ValueTuple`2 <string,bool> class Test::'<Main>m__0'(class ViewModel)
649 // IL_0301: newobj instance void class [mscorlib] System.Func`2<class ViewModel, valuetype[mscorlib] System.ValueTuple`2<string, bool>>::'.ctor'(object, native int)
650 yield return Create(Ldnull);
651 yield return Create(Ldftn, getter);
652 yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Func`2"), paramCount: 2, classArguments: new[] { tSourceRef, tupleRef }));
655 static IEnumerable<Instruction> CompiledBindingGetSetter(TypeReference tSourceRef, TypeReference tPropertyRef, IList<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)> properties, ElementNode node, ILContext context)
657 if (properties == null || properties.Count == 0) {
658 yield return Create(Ldnull);
662 // .method private static hidebysig default void '<Main>m__1' (class ViewModel vm, string s) cil managed
664 // .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
667 // IL_0001: callvirt instance class ViewModel class ViewModel::get_Model()
669 // IL_0007: callvirt instance void class ViewModel::set_Text(string)
673 var module = context.Module;
674 var setter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}",
675 MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static,
676 module.TypeSystem.Void) {
678 new ParameterDefinition(tSourceRef),
679 new ParameterDefinition(tPropertyRef)
682 new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
685 setter.Body.InitLocals = true;
687 var il = setter.Body.GetILProcessor();
688 if (!properties.Any() || properties.Last().property.SetMethod == null) {
689 yield return Create(Ldnull); //throw or not ?
693 var setterRef = module.ImportReference(properties.Last().property.SetMethod);
694 setterRef = module.ImportReference(setterRef.ResolveGenericParameters(properties.Last().propDeclTypeRef, module));
696 if (tSourceRef.IsValueType)
697 il.Emit(Ldarga_S, (byte)0);
700 var locs = new Dictionary<TypeReference, VariableDefinition>();
701 Instruction pop = null;
702 il.Append(DigProperties(properties.Take(properties.Count - 1), locs, () => {
704 pop = Instruction.Create(Pop);
707 }, node as IXmlLineInfo, module));
709 foreach (var loc in locs.Values)
710 setter.Body.Variables.Add(loc);
712 (PropertyDefinition lastProperty, TypeReference lastPropDeclTypeRef, string lastIndexArg) = properties.Last();
713 if (lastPropDeclTypeRef.IsValueType) {
714 var importedPropDeclTypeRef = module.ImportReference(lastPropDeclTypeRef);
716 if (!locs.TryGetValue(importedPropDeclTypeRef, out var loc)) {
717 loc = new VariableDefinition(importedPropDeclTypeRef);
718 setter.Body.Variables.Add(loc);
722 il.Emit(Ldloca, loc);
725 pop = Instruction.Create(Pop);
728 il.Emit(Brfalse, pop);
731 if (lastIndexArg != null) {
732 var indexType = lastProperty.GetMethod.Parameters[0].ParameterType.ResolveGenericParameters(lastPropDeclTypeRef);
733 if (TypeRefComparer.Default.Equals(indexType, module.TypeSystem.String))
734 il.Emit(Ldstr, lastIndexArg);
735 else if (TypeRefComparer.Default.Equals(indexType, module.TypeSystem.Int32)) {
736 if (!int.TryParse(lastIndexArg, out int index))
737 throw new XamlParseException($"Binding: {lastIndexArg} could not be parsed as an index for a {lastProperty.Name}", node as IXmlLineInfo);
738 il.Emit(Ldc_I4, index);
744 if (properties.Last().property.SetMethod.IsVirtual)
745 il.Emit(Callvirt, setterRef);
747 il.Emit(Call, setterRef);
756 context.Body.Method.DeclaringType.Methods.Add(setter);
759 // IL_0025: ldftn void class Test::'<Main>m__1'(class ViewModel, string)
760 // IL_002b: newobj instance void class [mscorlib]System.Action`2<class ViewModel, string>::'.ctor'(object, native int)
761 yield return Create(Ldnull);
762 yield return Create(Ldftn, setter);
763 yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Action`2"),
766 new[] { tSourceRef, tPropertyRef }));
769 static IEnumerable<Instruction> CompiledBindingGetHandlers(TypeReference tSourceRef, TypeReference tPropertyRef, IList<(PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg)> properties, ElementNode node, ILContext context)
771 // .method private static hidebysig default object '<Main>m__2'(class ViewModel vm) cil managed {
772 // .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
775 // } // end of method Test::<Main>m__2
777 // .method private static hidebysig default object '<Main>m__3' (class ViewModel vm) cil managed {
778 // .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
780 // IL_0001: callvirt instance class ViewModel class ViewModel::get_Model()
784 var module = context.Module;
786 var partGetters = new List<MethodDefinition>();
787 if (properties == null || properties.Count == 0) {
788 yield return Create(Ldnull);
792 for (int i = 0; i < properties.Count; i++) {
793 var tuple = properties [i];
794 var partGetter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, module.TypeSystem.Object) {
796 new ParameterDefinition(tSourceRef)
799 new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
802 partGetter.Body.InitLocals = true;
803 var il = partGetter.Body.GetILProcessor();
805 if (i == 0) { //return self
807 if (tSourceRef.IsValueType)
808 il.Emit(Box, module.ImportReference(tSourceRef));
811 context.Body.Method.DeclaringType.Methods.Add(partGetter);
812 partGetters.Add(partGetter);
816 if (tSourceRef.IsValueType)
817 il.Emit(Ldarga_S, (byte)0);
820 var lastGetterTypeRef = properties[i - 1].property.PropertyType;
821 var locs = new Dictionary<TypeReference, VariableDefinition>();
822 il.Append(DigProperties(properties.Take(i), locs, null, node as IXmlLineInfo, module));
823 foreach (var loc in locs.Values)
824 partGetter.Body.Variables.Add(loc);
825 if (lastGetterTypeRef.IsValueType)
826 il.Emit(Box, module.ImportReference(lastGetterTypeRef));
829 context.Body.Method.DeclaringType.Methods.Add(partGetter);
830 partGetters.Add(partGetter);
833 var funcObjRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, module.TypeSystem.Object }));
834 var tupleRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "Tuple`2")).MakeGenericInstanceType(new [] { funcObjRef, module.TypeSystem.String }));
835 var funcCtor = module.ImportReference(funcObjRef.ResolveCached().GetConstructors().First());
836 funcCtor = funcCtor.MakeGeneric(funcObjRef, new [] { tSourceRef, module.TypeSystem.Object });
837 var tupleCtor = module.ImportReference(tupleRef.ResolveCached().GetConstructors().First());
838 tupleCtor = tupleCtor.MakeGeneric(tupleRef, new [] { funcObjRef, module.TypeSystem.String});
841 // IL_003b: newarr class [mscorlib] System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel,object>,string>
846 // IL_004a: ldftn object class Test::'<Main>m__2'(class ViewModel)
847 // IL_0050: newobj instance void class [mscorlib]System.Func`2<class ViewModel, object>::'.ctor'(object, native int)
848 // IL_005f: ldstr "Model"
849 // IL_0064: newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
850 // IL_0069: stelem.ref
855 // IL_0074: ldftn object class Test::'<Main>m__3'(class ViewModel)
856 // IL_007a: newobj instance void class [mscorlib]System.Func`2<class ViewModel, object>::'.ctor'(object, native int)
857 // IL_0089: ldstr "Text"
858 // IL_008e: newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
859 // IL_0093: stelem.ref
861 yield return Create(Ldc_I4, properties.Count);
862 yield return Create(Newarr, tupleRef);
864 for (var i = 0; i < properties.Count; i++) {
865 yield return Create(Dup);
866 yield return Create(Ldc_I4, i);
867 yield return Create(Ldnull);
868 yield return Create(Ldftn, partGetters [i]);
869 yield return Create(Newobj, module.ImportReference(funcCtor));
870 yield return Create(Ldstr, properties [i].Item1.Name);
871 yield return Create(Newobj, module.ImportReference(tupleCtor));
872 yield return Create(Stelem_Ref);
876 public static IEnumerable<Instruction> SetPropertyValue(VariableDefinition parent, XmlName propertyName, INode valueNode, ILContext context, IXmlLineInfo iXmlLineInfo)
878 var localName = propertyName.LocalName;
879 var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out System.Boolean attached, context, iXmlLineInfo);
881 //If the target is an event, connect
882 if (CanConnectEvent(parent, localName, valueNode, attached))
883 return ConnectEvent(parent, localName, valueNode, iXmlLineInfo, context);
885 //If Value is DynamicResource, SetDynamicResource
886 if (CanSetDynamicResource(bpRef, valueNode, context))
887 return SetDynamicResource(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
889 //If Value is a BindingBase and target is a BP, SetBinding
890 if (CanSetBinding(bpRef, valueNode, context))
891 return SetBinding(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
893 //If it's a BP, SetValue ()
894 if (CanSetValue(bpRef, attached, valueNode, iXmlLineInfo, context))
895 return SetValue(parent, bpRef, valueNode, iXmlLineInfo, context).Concat(RegisterSourceInfo(context, valueNode));
897 //If it's a property, set it
898 if (CanSet(parent, localName, valueNode, context))
899 return Set(parent, localName, valueNode, iXmlLineInfo, context).Concat(RegisterSourceInfo(context, valueNode));
901 //If it's an already initialized property, add to it
902 if (CanAdd(parent, propertyName, valueNode, iXmlLineInfo, context))
903 return Add(parent, propertyName, valueNode, iXmlLineInfo, context).Concat(RegisterSourceInfo(context, valueNode));
905 throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
908 internal static IEnumerable<Instruction> RegisterSourceInfo(ILContext context, INode valueNode)
910 if (!context.DefineDebug)
912 if (!(valueNode is IXmlLineInfo lineInfo))
914 if (!(valueNode is IElementNode elementNode))
916 if (context.Variables[elementNode].VariableType.IsValueType)
919 var module = context.Body.Method.Module;
921 yield return Create(Ldloc, context.Variables[elementNode]); //target
923 yield return Create(Ldstr, context.XamlFilePath);
924 yield return Create(Ldc_I4, (int)UriKind.RelativeOrAbsolute);
925 yield return Create(Newobj, module.ImportCtorReference(("System", "System", "Uri"),
926 parameterTypes: new[] {
927 ("mscorlib", "System", "String"),
928 ("System", "System", "UriKind"),
931 yield return Create(Ldc_I4, lineInfo.LineNumber); //lineNumber
932 yield return Create(Ldc_I4, lineInfo.LinePosition); //linePosition
934 yield return Create(Call, module.ImportMethodReference(("XSF", "Xamarin.Forms.Xaml.Diagnostics", "VisualDiagnostics"),
935 methodName: "RegisterSourceInfo",
936 parameterTypes: new[] {
937 ("mscorlib", "System", "Object"),
938 ("System", "System", "Uri"),
939 ("mscorlib", "System", "Int32"),
940 ("mscorlib", "System", "Int32")},
944 public static IEnumerable<Instruction> GetPropertyValue(VariableDefinition parent, XmlName propertyName, ILContext context, IXmlLineInfo lineInfo, out TypeReference propertyType)
946 var module = context.Body.Method.Module;
947 var localName = propertyName.LocalName;
949 var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
951 //If it's a BP, GetValue ()
952 if (CanGetValue(parent, bpRef, attached, lineInfo, context, out _))
953 return GetValue(parent, bpRef, lineInfo, context, out propertyType);
955 //If it's a property, set it
956 if (CanGet(parent, localName, context, out _))
957 return Get(parent, localName, lineInfo, context, out propertyType);
959 throw new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
962 static FieldReference GetBindablePropertyReference(VariableDefinition parent, string namespaceURI, ref string localName, out bool attached, ILContext context, IXmlLineInfo iXmlLineInfo)
964 var module = context.Body.Method.Module;
965 TypeReference declaringTypeReference;
967 //If it's an attached BP, update elementType and propertyName
968 var bpOwnerType = parent.VariableType;
969 attached = GetNameAndTypeRef(ref bpOwnerType, namespaceURI, ref localName, context, iXmlLineInfo);
970 var name = $"{localName}Property";
971 FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == name &&
973 (fd.IsPublic || fd.IsAssembly), out declaringTypeReference);
975 bpRef = module.ImportReference(bpRef.ResolveGenericParameters(declaringTypeReference));
976 bpRef.FieldType = module.ImportReference(bpRef.FieldType);
981 static bool CanConnectEvent(VariableDefinition parent, string localName, INode valueNode, bool attached)
983 return !attached && valueNode is ValueNode && parent.VariableType.GetEvent(ed => ed.Name == localName, out _) != null;
986 static IEnumerable<Instruction> ConnectEvent(VariableDefinition parent, string localName, INode valueNode, IXmlLineInfo iXmlLineInfo, ILContext context)
988 var elementType = parent.VariableType;
989 var module = context.Body.Method.Module;
990 TypeReference eventDeclaringTypeRef;
991 var eventinfo = elementType.GetEvent(ed => ed.Name == localName, out eventDeclaringTypeRef);
992 var adder = module.ImportReference(eventinfo.AddMethod);
993 adder = adder.ResolveGenericParameters(eventDeclaringTypeRef, module);
998 // IL_0009: ldftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
999 //OR, if the handler is virtual
1001 // IL_0009: ldvirtftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
1003 // IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
1004 // IL_0014: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::add_Clicked(class [mscorlib]System.EventHandler)
1006 var value = ((ValueNode)valueNode).Value;
1008 yield return Create(Ldloc, parent);
1009 var declaringType = context.Body.Method.DeclaringType;
1010 while (declaringType.IsNested)
1011 declaringType = declaringType.DeclaringType;
1012 var handler = declaringType.AllMethods().FirstOrDefault(md => {
1013 if (md.methodDef.Name != value as string)
1016 //check if the handler signature matches the Invoke signature;
1017 var invoke = module.ImportReference(eventinfo.EventType.ResolveCached().GetMethods().First(eventmd => eventmd.Name == "Invoke"));
1018 invoke = invoke.ResolveGenericParameters(eventinfo.EventType, module);
1019 if (!md.methodDef.ReturnType.InheritsFromOrImplements(invoke.ReturnType) || invoke.Parameters.Count != md.methodDef.Parameters.Count)
1022 if (!invoke.ContainsGenericParameter)
1023 for (var i = 0; i < invoke.Parameters.Count;i++)
1024 if (!invoke.Parameters[i].ParameterType.InheritsFromOrImplements(md.methodDef.Parameters[i].ParameterType))
1026 //TODO check generic parameters if any
1030 MethodReference handlerRef = null;
1031 if (handler.methodDef != null)
1032 handlerRef = handler.methodDef.ResolveGenericParameters(handler.declTypeRef, module);
1033 if (handler.methodDef == null)
1034 throw new XamlParseException($"EventHandler \"{value}\" with correct signature not found in type \"{declaringType}\"", iXmlLineInfo);
1036 //FIXME: eventually get the right ctor instead fo the First() one, just in case another one could exists (not even sure it's possible).
1037 var ctor = module.ImportReference(eventinfo.EventType.ResolveCached().GetConstructors().First());
1038 ctor = ctor.ResolveGenericParameters(eventinfo.EventType, module);
1040 if (handler.methodDef.IsStatic) {
1041 yield return Create(Ldnull);
1043 if (context.Root is VariableDefinition)
1044 foreach (var instruction in (context.Root as VariableDefinition).LoadAs(ctor.Parameters[0].ParameterType.ResolveGenericParameters(ctor), module))
1045 yield return instruction;
1046 else if (context.Root is FieldDefinition) {
1047 yield return Create(Ldarg_0);
1048 yield return Create(Ldfld, context.Root as FieldDefinition);
1050 throw new InvalidProgramException();
1053 if (handler.methodDef.IsVirtual) {
1054 yield return Create(Ldarg_0);
1055 yield return Create(Ldvirtftn, handlerRef);
1057 yield return Create(Ldftn, handlerRef);
1059 yield return Create(Newobj, module.ImportReference(ctor));
1060 //Check if the handler has the same signature as the ctor (it should)
1061 yield return Create(Callvirt, module.ImportReference(adder));
1064 static bool CanSetDynamicResource(FieldReference bpRef, INode valueNode, ILContext context)
1068 var elementNode = valueNode as IElementNode;
1069 if (elementNode == null)
1072 VariableDefinition varValue;
1073 if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue))
1075 return varValue.VariableType.FullName == typeof(DynamicResource).FullName;
1078 static IEnumerable<Instruction> SetDynamicResource(VariableDefinition parent, FieldReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, ILContext context)
1080 var module = context.Body.Method.Module;
1081 var dynamicResourceType = ("XSF", "Xamarin.Forms.Internals", "DynamicResource");
1082 var dynamicResourceHandlerType = ("XSF", "Xamarin.Forms.Internals", "IDynamicResourceHandler");
1084 foreach (var instruction in parent.LoadAs(module.GetTypeDefinition(dynamicResourceHandlerType), module))
1085 yield return instruction;
1086 yield return Create(Ldsfld, bpRef);
1087 foreach (var instruction in context.Variables[elementNode].LoadAs(module.GetTypeDefinition(dynamicResourceType), module))
1088 yield return instruction;
1089 yield return Create(Callvirt, module.ImportPropertyGetterReference(dynamicResourceType, propertyName: "Key"));
1090 yield return Create(Callvirt, module.ImportMethodReference(dynamicResourceHandlerType,
1091 methodName: "SetDynamicResource",
1092 parameterTypes: new[] {
1093 ("XSF", "Xamarin.Forms", "BindableProperty"),
1094 ("mscorlib", "System", "String"),
1098 static bool CanSetBinding(FieldReference bpRef, INode valueNode, ILContext context)
1100 var module = context.Body.Method.Module;
1104 if (!(valueNode is IElementNode elementNode))
1107 if (!context.Variables.TryGetValue(valueNode as IElementNode, out VariableDefinition varValue))
1109 var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.ImportReference(("XSF","Xamarin.Forms","BindingBase")), module);
1110 if (implicitOperator != null)
1113 return varValue.VariableType.InheritsFromOrImplements(module.ImportReference(("XSF", "Xamarin.Forms", "BindingBase")));
1116 static IEnumerable<Instruction> SetBinding(VariableDefinition parent, FieldReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, ILContext context)
1118 var module = context.Body.Method.Module;
1119 var bindableObjectType = ("XSF", "Xamarin.Forms", "BindableObject");
1120 var parameterTypes = new[] {
1121 ("XSF", "Xamarin.Forms", "BindableProperty"),
1122 ("XSF", "Xamarin.Forms", "BindingBase"),
1125 //TODO: check if parent is a BP
1126 foreach (var instruction in parent.LoadAs(module.GetTypeDefinition(bindableObjectType), module))
1127 yield return instruction;
1128 yield return Create(Ldsfld, bpRef);
1129 foreach (var instruction in context.Variables [elementNode].LoadAs(module.GetTypeDefinition(parameterTypes[1]), module))
1130 yield return instruction;
1131 yield return Create(Callvirt, module.ImportMethodReference(("XSF", "Xamarin.Forms", "BindableObject"),
1132 methodName: "SetBinding",
1133 parameterTypes: parameterTypes));
1136 static bool CanSetValue(FieldReference bpRef, bool attached, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1138 var module = context.Body.Method.Module;
1143 if (node is ValueNode valueNode && valueNode.CanConvertValue(context, bpRef))
1146 if (!(node is IElementNode elementNode))
1149 if (!context.Variables.TryGetValue(elementNode, out VariableDefinition varValue))
1152 var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1153 // If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here.
1154 // Worst case scenario ? InvalidCastException at runtime
1155 if (attached && varValue.VariableType.FullName == "System.Object")
1157 var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
1158 if (implicitOperator != null)
1161 //as we're in the SetValue Scenario, we can accept value types, they'll be boxed
1162 if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object")
1165 return varValue.VariableType.InheritsFromOrImplements(bpTypeRef);
1168 static bool CanGetValue(VariableDefinition parent, FieldReference bpRef, bool attached, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
1170 var module = context.Body.Method.Module;
1171 propertyType = null;
1176 if (!parent.VariableType.InheritsFromOrImplements(module.ImportReference(("XSF", "Xamarin.Forms", "BindableObject"))))
1179 propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1183 static IEnumerable<Instruction> SetValue(VariableDefinition parent, FieldReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1185 var valueNode = node as ValueNode;
1186 var elementNode = node as IElementNode;
1187 var module = context.Body.Method.Module;
1188 var bindableObjectType = ("XSF", "Xamarin.Forms", "BindableObject");
1191 // IL_0008: ldsfld class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty [Xamarin.Forms.Core]Xamarin.Forms.Label::TextProperty
1192 // IL_000d: ldstr "foo"
1193 // IL_0012: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.BindableObject::SetValue(class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty, object)
1195 foreach (var instruction in parent.LoadAs(module.GetTypeDefinition(bindableObjectType), module))
1196 yield return instruction;
1198 yield return Create(Ldsfld, bpRef);
1200 if (valueNode != null) {
1201 foreach (var instruction in valueNode.PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef:bpRef), true, false))
1202 yield return instruction;
1203 } else if (elementNode != null) {
1204 var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1205 foreach (var instruction in context.Variables[elementNode].LoadAs(bpTypeRef, module))
1206 yield return instruction;
1207 if (bpTypeRef.IsValueType)
1208 yield return Create(Box, module.ImportReference(bpTypeRef));
1210 yield return Create(Callvirt, module.ImportMethodReference(bindableObjectType,
1211 methodName: "SetValue",
1212 parameterTypes: new[] {
1213 ("XSF", "Xamarin.Forms", "BindableProperty"),
1214 ("mscorlib", "System", "Object"),
1218 static IEnumerable<Instruction> GetValue(VariableDefinition parent, FieldReference bpRef, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
1220 propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, context.Body.Method.Module);
1221 return GetValue(parent, bpRef, iXmlLineInfo, context);
1224 static IEnumerable<Instruction> GetValue(VariableDefinition parent, FieldReference bpRef, IXmlLineInfo iXmlLineInfo, ILContext context)
1226 var module = context.Body.Method.Module;
1227 var bindableObjectType = ("XSF", "Xamarin.Forms", "BindableObject");
1229 foreach (var instruction in parent.LoadAs(module.GetTypeDefinition(bindableObjectType), module))
1230 yield return instruction;
1232 yield return Create(Ldsfld, bpRef);
1233 yield return Create(Callvirt, module.ImportMethodReference(bindableObjectType,
1234 methodName: "GetValue",
1235 parameterTypes: new[] { ("XSF", "Xamarin.Forms", "BindableProperty")}));
1238 static bool CanSet(VariableDefinition parent, string localName, INode node, ILContext context)
1240 var module = context.Body.Method.Module;
1241 TypeReference declaringTypeReference;
1242 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
1243 if (property == null)
1245 var propertyType = property.PropertyType.ResolveGenericParameters(declaringTypeReference);
1246 var propertySetter = property.SetMethod;
1247 if (propertySetter == null || !propertySetter.IsPublic || propertySetter.IsStatic)
1250 var valueNode = node as ValueNode;
1251 if (valueNode != null && valueNode.CanConvertValue(context, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached()}))
1254 var elementNode = node as IElementNode;
1255 if (elementNode == null)
1258 var vardef = context.Variables [elementNode];
1259 var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
1261 if (vardef.VariableType.InheritsFromOrImplements(propertyType))
1263 if (implicitOperator != null)
1265 if (propertyType.FullName == "System.Object")
1268 //I'd like to get rid of this condition. This comment used to be //TODO replace latest check by a runtime type check
1269 if (vardef.VariableType.FullName == "System.Object")
1275 static bool CanGet(VariableDefinition parent, string localName, ILContext context, out TypeReference propertyType)
1277 var module = context.Body.Method.Module;
1278 propertyType = null;
1279 TypeReference declaringTypeReference;
1280 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
1281 if (property == null)
1283 var propertyGetter = property.GetMethod;
1284 if (propertyGetter == null || !propertyGetter.IsPublic || propertyGetter.IsStatic)
1287 module.ImportReference(parent.VariableType.ResolveCached());
1288 var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
1289 propertyGetterRef.ImportTypes(module);
1290 propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
1295 static IEnumerable<Instruction> Set(VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1297 var module = context.Body.Method.Module;
1298 TypeReference declaringTypeReference;
1299 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
1300 var propertySetter = property.SetMethod;
1303 // IL_0008: ldstr "foo"
1304 // IL_000d: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Label::set_Text(string)
1306 module.ImportReference(parent.VariableType.ResolveCached());
1307 var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
1308 propertySetterRef.ImportTypes(module);
1309 var propertyType = property.PropertyType.ResolveGenericParameters(declaringTypeReference);
1310 var valueNode = node as ValueNode;
1311 var elementNode = node as IElementNode;
1313 //if it's a value type, load the address so we can invoke methods on it
1314 if (parent.VariableType.IsValueType)
1315 yield return Instruction.Create(OpCodes.Ldloca, parent);
1317 yield return Instruction.Create(OpCodes.Ldloc, parent);
1319 if (valueNode != null) {
1320 foreach (var instruction in valueNode.PushConvertedValue(context, propertyType, new ICustomAttributeProvider [] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(context, propertyRef:property), false, true))
1321 yield return instruction;
1322 if (parent.VariableType.IsValueType)
1323 yield return Instruction.Create(OpCodes.Call, propertySetterRef);
1325 yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
1326 } else if (elementNode != null) {
1327 foreach (var instruction in context.Variables [elementNode].LoadAs(propertyType, module))
1328 yield return instruction;
1329 if (parent.VariableType.IsValueType)
1330 yield return Instruction.Create(OpCodes.Call, propertySetterRef);
1332 yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
1336 static IEnumerable<Instruction> Get(VariableDefinition parent, string localName, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
1338 var module = context.Body.Method.Module;
1339 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out var declaringTypeReference);
1340 var propertyGetter = property.GetMethod;
1342 module.ImportReference(parent.VariableType.ResolveCached());
1343 var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
1344 propertyGetterRef.ImportTypes(module);
1345 propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
1347 if (parent.VariableType.IsValueType)
1349 Instruction.Create(OpCodes.Ldloca, parent),
1350 Instruction.Create(OpCodes.Call, propertyGetterRef),
1354 Instruction.Create(OpCodes.Ldloc, parent),
1355 Instruction.Create(OpCodes.Callvirt, propertyGetterRef),
1359 static bool CanAdd(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo lineInfo, ILContext context)
1361 var module = context.Body.Method.Module;
1362 var localName = propertyName.LocalName;
1364 var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
1365 TypeReference propertyType;
1367 if ( !CanGetValue(parent, bpRef, attached, null, context, out propertyType)
1368 && !CanGet(parent, localName, context, out propertyType))
1371 //TODO check md.Parameters[0] type
1372 var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
1373 if (adderTuple == null)
1379 static Dictionary<VariableDefinition, IList<string>> resourceNamesInUse = new Dictionary<VariableDefinition, IList<string>>();
1380 static bool CanAddToResourceDictionary(VariableDefinition parent, TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, ILContext context)
1382 if ( collectionType.FullName != "Xamarin.Forms.ResourceDictionary"
1383 && collectionType.ResolveCached().BaseType?.FullName != "Xamarin.Forms.ResourceDictionary")
1387 if (node.Properties.ContainsKey(XmlName.xKey)) {
1388 var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
1389 if (!resourceNamesInUse.TryGetValue(parent, out var names))
1390 resourceNamesInUse[parent] = (names = new List<string>());
1391 if (names.Contains(key))
1392 throw new XamlParseException($"A resource with the key '{key}' is already present in the ResourceDictionary.", lineInfo);
1397 //is there a RD.Add() overrides that accepts this ?
1398 var nodeTypeRef = context.Variables[node].VariableType;
1399 var module = context.Body.Method.Module;
1400 if (module.ImportMethodReference(module.GetTypeDefinition(("XSF", "Xamarin.Forms", "ResourceDictionary")),
1402 parameterTypes: new[] { (nodeTypeRef) }) != null)
1405 throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
1408 static IEnumerable<Instruction> Add(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1410 var module = context.Body.Method.Module;
1411 var elementNode = node as IElementNode;
1412 var vardef = context.Variables [elementNode];
1414 TypeReference propertyType;
1415 foreach (var instruction in GetPropertyValue(parent, propertyName, context, iXmlLineInfo, out propertyType))
1416 yield return instruction;
1418 if (CanAddToResourceDictionary(parent, propertyType, elementNode, iXmlLineInfo, context)) {
1419 foreach (var instruction in AddToResourceDictionary(elementNode, iXmlLineInfo, context))
1420 yield return instruction;
1424 var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
1425 var adderRef = module.ImportReference(adderTuple.Item1);
1426 adderRef = module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
1428 foreach (var instruction in vardef.LoadAs(adderRef.Parameters[0].ParameterType.ResolveGenericParameters(adderRef), module))
1429 yield return instruction;
1430 yield return Instruction.Create(OpCodes.Callvirt, adderRef);
1431 if (adderRef.ReturnType.FullName != "System.Void")
1432 yield return Instruction.Create(OpCodes.Pop);
1435 static IEnumerable<Instruction> AddToResourceDictionary(IElementNode node, IXmlLineInfo lineInfo, ILContext context)
1437 var module = context.Body.Method.Module;
1439 if (node.Properties.ContainsKey(XmlName.xKey)) {
1440 // IL_0014: ldstr "key"
1441 // IL_0019: ldstr "foo"
1442 // IL_001e: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ResourceDictionary::Add(string, object)
1443 yield return Create(Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
1444 foreach (var instruction in context.Variables[node].LoadAs(module.TypeSystem.Object, module))
1445 yield return instruction;
1446 yield return Create(Callvirt, module.ImportMethodReference(("XSF", "Xamarin.Forms", "ResourceDictionary"),
1448 parameterTypes: new[] {
1449 ("mscorlib", "System", "String"),
1450 ("mscorlib", "System", "Object"),
1455 var nodeTypeRef = context.Variables[node].VariableType;
1456 yield return Create(Ldloc, context.Variables[node]);
1457 yield return Create(Callvirt, module.ImportMethodReference(("XSF", "Xamarin.Forms", "ResourceDictionary"),
1459 parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }));
1463 static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname,
1464 ILContext context, IXmlLineInfo lineInfo)
1466 var dotIdx = localname.IndexOf('.');
1469 var typename = localname.Substring(0, dotIdx);
1470 localname = localname.Substring(dotIdx + 1);
1471 elementType = new XmlType(namespaceURI, typename, null).GetTypeReference(context.Body.Method.Module, lineInfo);
1477 static void SetDataTemplate(IElementNode parentNode, ElementNode node, ILContext parentContext,
1478 IXmlLineInfo xmlLineInfo)
1480 var module = parentContext.Module;
1481 var dataTemplateType = ("XSF", "Xamarin.Forms.Internals", "IDataTemplate");
1482 var parentVar = parentContext.Variables[parentNode];
1483 //Push the DataTemplate to the stack, for setting the template
1484 parentContext.IL.Append(parentVar.LoadAs(module.GetTypeDefinition(dataTemplateType), module));
1486 //Create nested class
1487 // .class nested private auto ansi sealed beforefieldinit '<Main>c__AnonStorey0'
1488 // extends [mscorlib]System.Object
1491 var anonType = new TypeDefinition(
1493 "<" + parentContext.Body.Method.Name + ">_anonXamlCDataTemplate_" + dtcount++,
1494 TypeAttributes.BeforeFieldInit |
1495 TypeAttributes.Sealed |
1496 TypeAttributes.NestedPrivate) {
1497 BaseType = module.TypeSystem.Object,
1498 CustomAttributes = {
1499 new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null)),
1503 parentContext.Body.Method.DeclaringType.NestedTypes.Add(anonType);
1504 var ctor = anonType.AddDefaultConstructor();
1506 var loadTemplate = new MethodDefinition("LoadDataTemplate",
1507 MethodAttributes.Assembly | MethodAttributes.HideBySig,
1508 module.TypeSystem.Object);
1509 loadTemplate.Body.InitLocals = true;
1510 anonType.Methods.Add(loadTemplate);
1512 var parentValues = new FieldDefinition("parentValues", FieldAttributes.Assembly, module.ImportArrayReference(("mscorlib", "System", "Object")));
1513 anonType.Fields.Add(parentValues);
1515 TypeReference rootType = null;
1516 var vdefRoot = parentContext.Root as VariableDefinition;
1517 if (vdefRoot != null)
1518 rootType = vdefRoot.VariableType;
1519 var fdefRoot = parentContext.Root as FieldDefinition;
1520 if (fdefRoot != null)
1521 rootType = fdefRoot.FieldType;
1523 var root = new FieldDefinition("root", FieldAttributes.Assembly, rootType);
1524 anonType.Fields.Add(root);
1526 //Fill the loadTemplate Body
1527 var templateIl = loadTemplate.Body.GetILProcessor();
1528 templateIl.Emit(OpCodes.Nop);
1529 var templateContext = new ILContext(templateIl, loadTemplate.Body, module, parentValues)
1532 DefineDebug = parentContext.DefineDebug,
1533 XamlFilePath = parentContext.XamlFilePath,
1535 node.Accept(new CreateObjectVisitor(templateContext), null);
1536 node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null);
1537 node.Accept(new SetFieldVisitor(templateContext), null);
1538 node.Accept(new SetResourcesVisitor(templateContext), null);
1539 node.Accept(new SetPropertiesVisitor(templateContext, stopOnResourceDictionary: true), null);
1541 templateIl.Append(templateContext.Variables[node].LoadAs(module.TypeSystem.Object, module));
1542 templateIl.Emit(OpCodes.Ret);
1544 //Instanciate nested class
1545 var parentIl = parentContext.IL;
1546 parentIl.Emit(OpCodes.Newobj, ctor);
1548 //Copy required local vars
1549 parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance
1550 parentIl.Append(node.PushParentObjectsArray(parentContext));
1551 parentIl.Emit(OpCodes.Stfld, parentValues);
1552 parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance
1553 if (parentContext.Root is VariableDefinition)
1554 parentIl.Append((parentContext.Root as VariableDefinition).LoadAs(module.TypeSystem.Object, module));
1555 else if (parentContext.Root is FieldDefinition)
1557 parentIl.Emit(OpCodes.Ldarg_0);
1558 parentIl.Emit(OpCodes.Ldfld, parentContext.Root as FieldDefinition);
1561 throw new InvalidProgramException();
1562 parentIl.Emit(OpCodes.Stfld, root);
1565 parentIl.Emit(Ldftn, loadTemplate);
1566 parentIl.Emit(Newobj, module.ImportCtorReference(("mscorlib", "System", "Func`1"),
1567 classArguments: new[] { ("mscorlib", "System", "Object") },
1570 parentContext.IL.Emit(OpCodes.Callvirt, module.ImportPropertySetterReference(dataTemplateType, propertyName: "LoadTemplate"));
1572 loadTemplate.Body.Optimize();
1575 bool TrySetRuntimeName(XmlName propertyName, VariableDefinition variableDefinition, ValueNode node)
1577 if (propertyName != XmlName.xName)
1580 var attributes = variableDefinition.VariableType.ResolveCached()
1581 .CustomAttributes.Where(attribute => attribute.AttributeType.FullName == "Xamarin.Forms.Xaml.RuntimeNamePropertyAttribute").ToList();
1583 if (!attributes.Any())
1586 var runTimeName = attributes[0].ConstructorArguments[0].Value as string;
1588 if (string.IsNullOrEmpty(runTimeName))
1591 Context.IL.Append(SetPropertyValue(variableDefinition, new XmlName("", runTimeName), node, Context, node));
1596 class VariableDefinitionReference
1598 public VariableDefinitionReference(VariableDefinition vardef)
1600 VariableDefinition = vardef;
1603 public VariableDefinition VariableDefinition { get; set; }
1605 public static implicit operator VariableDefinition(VariableDefinitionReference vardefref)
1607 return vardefref.VariableDefinition;