summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Build.Tasks/XmlTypeExtensions.cs
blob: db1828475beb1e93b3821d9beb7da4256dcb3c4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Mono.Cecil;
using Mono.Cecil.Rocks;
using Xamarin.Forms.Xaml;

namespace Xamarin.Forms.Build.Tasks
{
	static class XmlTypeExtensions
	{
 		public static TypeReference GetTypeReference (string namespaceURI, string typename, ModuleDefinition module, IXmlLineInfo xmlInfo)
 		{
 			return new XmlType (namespaceURI, typename, null).GetTypeReference (module, xmlInfo);
 		}

		public static TypeReference GetTypeReference(this XmlType xmlType, ModuleDefinition module, IXmlLineInfo xmlInfo)
		{
			var namespaceURI = xmlType.NamespaceUri;
			var elementName = xmlType.Name;
			var typeArguments = xmlType.TypeArguments;

			List<Tuple<string, string>> lookupAssemblies = new List<Tuple<string, string>>(); //assembly, namespace
			List<string> lookupNames = new List<string>();

			if (!XmlnsHelper.IsCustom(namespaceURI))
			{
				lookupAssemblies.Add(new Tuple<string, string>("Xamarin.Forms.Core", "Xamarin.Forms"));
				lookupAssemblies.Add(new Tuple<string, string>("Xamarin.Forms.Xaml", "Xamarin.Forms.Xaml"));
			}
			else if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml" ||
			         namespaceURI == "http://schemas.microsoft.com/winfx/2006/xaml")
			{
				lookupAssemblies.Add(new Tuple<string, string>("Xamarin.Forms.Xaml", "Xamarin.Forms.Xaml"));
				lookupAssemblies.Add(new Tuple<string, string>("mscorlib", "System"));
				lookupAssemblies.Add(new Tuple<string, string>("System", "System"));
			}
			else
			{
				string ns;
				string typename;
				string asmstring;
				string targetPlatform;

				XmlnsHelper.ParseXmlns(namespaceURI, out typename, out ns, out asmstring, out targetPlatform);
				asmstring = asmstring ?? module.Assembly.Name.Name;
				lookupAssemblies.Add(new Tuple<string, string>(asmstring, ns));
			}

			lookupNames.Add(elementName);
			if (namespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml")
				lookupNames.Add(elementName + "Extension");
			for (var i = 0; i < lookupNames.Count; i++)
			{
				var name = lookupNames[i];
				if (name.Contains(":"))
					name = name.Substring(name.LastIndexOf(':') + 1);
				if (typeArguments != null)
					name += "`" + typeArguments.Count; //this will return an open generic Type
				lookupNames[i] = name;
			}

			TypeReference type = null;
			foreach (var asm in lookupAssemblies)
			{
				if (type != null)
					break;
				foreach (var name in lookupNames)
				{
					if (type != null)
						break;

					var assemblydefinition = module.Assembly.Name.Name == asm.Item1
						? module.Assembly
						: module.AssemblyResolver.Resolve(asm.Item1);
					type = assemblydefinition.MainModule.GetType(asm.Item2, name);
					if (type == null)
					{
						var exportedtype =
							assemblydefinition.MainModule.ExportedTypes.FirstOrDefault(
								(ExportedType arg) => arg.IsForwarder && arg.Namespace == asm.Item2 && arg.Name == name);
						if (exportedtype != null)
							type = exportedtype.Resolve();
					}
				}
			}

			if (type != null && typeArguments != null && type.HasGenericParameters)
			{
				type =
					module.Import(type)
						.MakeGenericInstanceType(typeArguments.Select(x => GetTypeReference(x, module, xmlInfo)).ToArray());
			}

			if (type == null)
				throw new XamlParseException(string.Format("Type {0} not found in xmlns {1}", elementName, namespaceURI), xmlInfo);

			return module.Import(type);
		}
	}
}