File: BindablePropertyReferenceExtensions.cs
Web Access
Project: src\src\Controls\src\Build.Tasks\Controls.Build.Tasks.csproj (Microsoft.Maui.Controls.Build.Tasks)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.Maui.Controls.Xaml;
using Mono.Cecil;
 
namespace Microsoft.Maui.Controls.Build.Tasks
{
	static class BindablePropertyReferenceExtensions
	{
		public static TypeReference GetBindablePropertyType(this FieldReference bpRef, XamlCache cache, IXmlLineInfo iXmlLineInfo, ModuleDefinition module)
		{
			if (!bpRef.Name.EndsWith("Property", StringComparison.InvariantCulture))
				throw new BuildException(BuildExceptionCode.BPName, iXmlLineInfo, null, bpRef.Name);
			var bpName = bpRef.Name.Substring(0, bpRef.Name.Length - 8);
			var owner = bpRef.DeclaringType;
 
			var getter = owner.GetProperty(cache, pd => pd.Name == bpName, out TypeReference declaringTypeRef)?.GetMethod;
			if (getter == null || getter.IsStatic || !getter.IsPublic)
				getter = null;
			getter = getter ?? owner.GetMethods(cache, md => md.Name == $"Get{bpName}" &&
												md.IsStatic &&
												md.IsPublic &&
												md.Parameters.Count == 1 &&
												md.Parameters[0].ParameterType.InheritsFromOrImplements(cache, module.ImportReference(cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "BindableObject"))), module).FirstOrDefault()?.Item1;
			if (getter == null)
				throw new BuildException(BuildExceptionCode.BPName, iXmlLineInfo, null, bpName, bpRef.DeclaringType);
 
			return getter.ResolveGenericReturnType(declaringTypeRef, module);
		}
 
		public static TypeReference GetBindablePropertyTypeConverter(this FieldReference bpRef, XamlCache cache, ModuleDefinition module)
		{
			var owner = bpRef.DeclaringType;
			var bpName = bpRef.Name.EndsWith("Property", StringComparison.Ordinal) ? bpRef.Name.Substring(0, bpRef.Name.Length - 8) : bpRef.Name;
			var property = owner.GetProperty(cache, pd => pd.Name == bpName, out TypeReference propertyDeclaringType);
			var propertyType = property?.PropertyType?.ResolveGenericParameters(propertyDeclaringType);
			var staticGetter = owner.GetMethods(cache, md => md.Name == $"Get{bpName}" &&
												md.IsStatic &&
												md.IsPublic &&
												md.Parameters.Count == 1 &&
												md.Parameters[0].ParameterType.InheritsFromOrImplements(cache, module.ImportReference(cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "BindableObject"))), module).FirstOrDefault()?.Item1;
 
			var attributes = new List<CustomAttribute>();
			if (property != null && property.HasCustomAttributes)
				attributes.AddRange(property.CustomAttributes);
			if (propertyType != null && propertyType.ResolveCached(cache).HasCustomAttributes)
				attributes.AddRange(propertyType.ResolveCached(cache).CustomAttributes);
			if (staticGetter != null && staticGetter.HasCustomAttributes)
				attributes.AddRange(staticGetter.CustomAttributes);
			if (staticGetter != null && staticGetter.ReturnType.ResolveGenericParameters(bpRef.DeclaringType).ResolveCached(cache).HasCustomAttributes)
				attributes.AddRange(staticGetter.ReturnType.ResolveGenericParameters(bpRef.DeclaringType).ResolveCached(cache).CustomAttributes);
 
			if (attributes.FirstOrDefault(cad => cad.AttributeType.FullName == "System.ComponentModel.TypeConverterAttribute")?.ConstructorArguments[0].Value is TypeReference typeConverter)
				return typeConverter;
 
			propertyType = propertyType ?? staticGetter?.ReturnType;
			return null;
		}
	}
 
	static class KVPExtensions
	{
		public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> kvp, out TKey key, out TValue value)
		{
			key = kvp.Key;
			value = kvp.Value;
		}
	}
}