135 строки
4.0 KiB
C#
135 строки
4.0 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Xml;
|
|
using Mono.Cecil;
|
|
using Mono.Cecil.Rocks;
|
|
using Xamarin.Forms.Internals;
|
|
using Xamarin.Forms.Xaml;
|
|
|
|
namespace Xamarin.Forms.Build.Tasks
|
|
{
|
|
static class XmlTypeExtensions
|
|
{
|
|
static IList<XmlnsDefinitionAttribute> s_xmlnsDefinitions;
|
|
|
|
static void GatherXmlnsDefinitionAttributes()
|
|
{
|
|
//this could be extended to look for [XmlnsDefinition] in all assemblies
|
|
var assemblies = new [] {
|
|
typeof(XamlLoader).Assembly,
|
|
typeof(View).Assembly,
|
|
};
|
|
|
|
s_xmlnsDefinitions = new List<XmlnsDefinitionAttribute>();
|
|
|
|
foreach (var assembly in assemblies)
|
|
foreach (XmlnsDefinitionAttribute attribute in assembly.GetCustomAttributes(typeof(XmlnsDefinitionAttribute), false)) {
|
|
s_xmlnsDefinitions.Add(attribute);
|
|
attribute.AssemblyName = attribute.AssemblyName ?? assembly.FullName;
|
|
}
|
|
}
|
|
|
|
public static TypeReference GetTypeReference(string xmlType, ModuleDefinition module, BaseNode node)
|
|
{
|
|
var split = xmlType.Split(':');
|
|
if (split.Length > 2)
|
|
throw new XamlParseException($"Type \"{xmlType}\" is invalid", node as IXmlLineInfo);
|
|
|
|
string prefix, name;
|
|
if (split.Length == 2) {
|
|
prefix = split[0];
|
|
name = split[1];
|
|
} else {
|
|
prefix = "";
|
|
name = split[0];
|
|
}
|
|
var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
|
|
return GetTypeReference(new XmlType(namespaceuri, name, null), module, node as IXmlLineInfo);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (s_xmlnsDefinitions == null)
|
|
GatherXmlnsDefinitionAttributes();
|
|
|
|
var namespaceURI = xmlType.NamespaceUri;
|
|
var elementName = xmlType.Name;
|
|
var typeArguments = xmlType.TypeArguments;
|
|
|
|
var lookupAssemblies = new List<XmlnsDefinitionAttribute>();
|
|
|
|
var lookupNames = new List<string>();
|
|
|
|
foreach (var xmlnsDef in s_xmlnsDefinitions) {
|
|
if (xmlnsDef.XmlNamespace != namespaceURI)
|
|
continue;
|
|
lookupAssemblies.Add(xmlnsDef);
|
|
}
|
|
|
|
if (lookupAssemblies.Count == 0) {
|
|
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;
|
|
if (ns != null)
|
|
lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns) {
|
|
AssemblyName = asmstring
|
|
});
|
|
}
|
|
|
|
lookupNames.Add(elementName + "Extension");
|
|
lookupNames.Add(elementName);
|
|
|
|
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 clrNamespace = asm.ClrNamespace;
|
|
var typeName = name.Replace('+', '/'); //Nested types
|
|
var idx = typeName.LastIndexOf('.');
|
|
if (idx >= 0) {
|
|
clrNamespace += '.' + typeName.Substring(0, typeName.LastIndexOf('.'));
|
|
typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
|
|
}
|
|
type = module.GetTypeDefinition((asm.AssemblyName, clrNamespace, typeName));
|
|
}
|
|
}
|
|
|
|
if (type != null && typeArguments != null && type.HasGenericParameters)
|
|
{
|
|
type =
|
|
module.ImportReference(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.ImportReference(type);
|
|
}
|
|
}
|
|
} |