a1227bf4076520e54f470a0c3de4ca475c9be8f2
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / XamlBuild / XmlTypeExtensions.cs
1 using System.Collections.Generic;
2 using System.Linq;
3 using System.Xml;
4 using Mono.Cecil;
5 using Mono.Cecil.Rocks;
6 using Tizen.NUI.Binding;
7 using Tizen.NUI.Xaml;
8
9 namespace Tizen.NUI.Xaml.Build.Tasks
10 {
11     static class XmlTypeExtensions
12     {
13         static internal IList<XmlnsDefinitionAttribute> s_xmlnsDefinitions;
14
15         static void GatherXmlnsDefinitionAttributes()
16         {
17             //this could be extended to look for [XmlnsDefinition] in all assemblies
18             s_xmlnsDefinitions = XamlTask.s_xmlnsDefinitions.OrderByDescending(a => a.Level).ToList(); ;
19         }
20
21         public static TypeReference GetTypeReference(string xmlType, ModuleDefinition module, BaseNode node)
22         {
23             var split = xmlType.Split(':');
24             if (split.Length > 2)
25                 throw new XamlParseException($"Type \"{xmlType}\" is invalid", node as IXmlLineInfo);
26
27             string prefix, name;
28             if (split.Length == 2) {
29                 prefix = split[0];
30                 name = split[1];
31             } else {
32                 prefix = "";
33                 name = split[0];
34             }
35             var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
36             return GetTypeReference(new XmlType(namespaceuri, name, null), module, node as IXmlLineInfo);
37         }
38
39         public static TypeReference GetTypeReference(string namespaceURI, string typename, ModuleDefinition module, IXmlLineInfo xmlInfo)
40         {
41             return new XmlType(namespaceURI, typename, null).GetTypeReference(module, xmlInfo);
42         }
43
44         public static TypeReference GetTypeReference(this XmlType xmlType, ModuleDefinition module, IXmlLineInfo xmlInfo, bool fromAllAssembly = false)
45         {
46             if (s_xmlnsDefinitions == null)
47                 GatherXmlnsDefinitionAttributes();
48
49             var namespaceURI = xmlType.NamespaceUri;
50             var elementName = xmlType.Name;
51             var typeArguments = xmlType.TypeArguments;
52
53             if (elementName.Contains("-"))
54             {
55                 elementName = elementName.Replace('-', '+');
56             }
57
58             var lookupAssemblies = new List<XmlnsDefinitionAttribute>();
59
60             var lookupNames = new List<string>();
61
62             if (true == fromAllAssembly)
63             {
64                 foreach (var xmlnsDef in s_xmlnsDefinitions)
65                 {
66                     lookupAssemblies.Add(xmlnsDef);
67                 }
68             }
69             else
70             {
71                 foreach (var xmlnsDef in s_xmlnsDefinitions)
72                 {
73                     if (xmlnsDef.XmlNamespace != namespaceURI)
74                         continue;
75                     lookupAssemblies.Add(xmlnsDef);
76                 }
77             }
78
79             if (lookupAssemblies.Count == 0) {
80                 string ns;
81                 string typename;
82                 string asmstring;
83                 string targetPlatform;
84
85                 XmlnsHelper.ParseXmlns(namespaceURI, out typename, out ns, out asmstring, out targetPlatform);
86                 asmstring = asmstring ?? module.Assembly.Name.Name;
87                 if (ns != null)
88                     lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns, 0) {
89                         AssemblyName = asmstring
90                     });
91             }
92
93             lookupNames.Add(elementName);
94             lookupNames.Add(elementName + "Extension");
95
96             for (var i = 0; i < lookupNames.Count; i++)
97             {
98                 var name = lookupNames[i];
99                 if (name.Contains(":"))
100                     name = name.Substring(name.LastIndexOf(':') + 1);
101                 if (typeArguments != null)
102                     name += "`" + typeArguments.Count; //this will return an open generic Type
103                 lookupNames[i] = name;
104             }
105
106             TypeReference type = null;
107             foreach (var asm in lookupAssemblies)
108             {
109                 if (type != null)
110                     break;
111                 foreach (var name in lookupNames)
112                 {
113                     if (type != null)
114                         break;
115
116                     var clrNamespace = asm.ClrNamespace;
117                     var typeName = name.Replace('+', '/'); //Nested types
118                     var idx = typeName.LastIndexOf('.');
119                     if (idx >= 0) {
120                         clrNamespace += '.' + typeName.Substring(0, typeName.LastIndexOf('.'));
121                         typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
122                     }
123                     type = module.GetTypeDefinition((asm.AssemblyName, clrNamespace, typeName));
124                 }
125             }
126
127             if (type != null && typeArguments != null && type.HasGenericParameters)
128             {
129                 type =
130                     module.ImportReference(type)
131                         .MakeGenericInstanceType(typeArguments.Select(x => GetTypeReference(x, module, xmlInfo)).ToArray());
132             }
133
134             if (type == null)
135                 throw new XamlParseException(string.Format("Type {0} not found in xmlns {1}", elementName, namespaceURI), xmlInfo);
136
137             return module.ImportReference(type);
138         }
139
140         public static TypeReference GetTypeExtensionReference(this XmlType xmlType, ModuleDefinition module, IXmlLineInfo xmlInfo, bool fromAllAssembly = false)
141         {
142             if (s_xmlnsDefinitions == null)
143                 GatherXmlnsDefinitionAttributes();
144
145             var namespaceURI = xmlType.NamespaceUri;
146             var elementName = xmlType.Name;
147             var typeArguments = xmlType.TypeArguments;
148
149             if (elementName.Contains("-"))
150             {
151                 elementName = elementName.Replace('-', '+');
152             }
153
154             var lookupAssemblies = new List<XmlnsDefinitionAttribute>();
155
156             var lookupNames = new List<string>();
157
158             if (true == fromAllAssembly)
159             {
160                 foreach (var xmlnsDef in s_xmlnsDefinitions)
161                 {
162                     lookupAssemblies.Add(xmlnsDef);
163                 }
164             }
165             else
166             {
167                 foreach (var xmlnsDef in s_xmlnsDefinitions)
168                 {
169                     if (xmlnsDef.XmlNamespace != namespaceURI)
170                         continue;
171                     lookupAssemblies.Add(xmlnsDef);
172                 }
173             }
174
175             if (lookupAssemblies.Count == 0)
176             {
177                 string ns;
178                 string typename;
179                 string asmstring;
180                 string targetPlatform;
181
182                 XmlnsHelper.ParseXmlns(namespaceURI, out typename, out ns, out asmstring, out targetPlatform);
183                 asmstring = asmstring ?? module.Assembly.Name.Name;
184                 if (ns != null)
185                     lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns, 0)
186                     {
187                         AssemblyName = asmstring
188                     });
189             }
190
191             lookupNames.Add(elementName + "Extension");
192
193             for (var i = 0; i < lookupNames.Count; i++)
194             {
195                 var name = lookupNames[i];
196                 if (name.Contains(":"))
197                     name = name.Substring(name.LastIndexOf(':') + 1);
198                 if (typeArguments != null)
199                     name += "`" + typeArguments.Count; //this will return an open generic Type
200                 lookupNames[i] = name;
201             }
202
203             TypeReference type = null;
204             foreach (var asm in lookupAssemblies)
205             {
206                 if (type != null)
207                     break;
208                 foreach (var name in lookupNames)
209                 {
210                     if (type != null)
211                         break;
212
213                     var clrNamespace = asm.ClrNamespace;
214                     var typeName = name.Replace('+', '/'); //Nested types
215                     var idx = typeName.LastIndexOf('.');
216                     if (idx >= 0)
217                     {
218                         clrNamespace += '.' + typeName.Substring(0, typeName.LastIndexOf('.'));
219                         typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
220                     }
221                     type = module.GetTypeDefinition((asm.AssemblyName, clrNamespace, typeName));
222
223                     if (null == type)
224                     {
225                         type = module.GetTypeDefinition((module.Assembly.Name.Name, clrNamespace, typeName));
226                     }
227                 }
228             }
229
230             if (type != null && typeArguments != null && type.HasGenericParameters)
231             {
232                 type =
233                     module.ImportReference(type)
234                         .MakeGenericInstanceType(typeArguments.Select(x => GetTypeReference(x, module, xmlInfo)).ToArray());
235             }
236
237             if (type == null)
238                 throw new XamlParseException(string.Format("Type {0} not found in xmlns {1}", elementName, namespaceURI), xmlInfo);
239
240             return module.ImportReference(type);
241         }
242     }
243 }