2 // ResolveFromXmlStep.cs
5 // Jb Evain (jbevain@gmail.com)
8 // (C) 2007 Novell, Inc.
9 // Copyright 2013 Xamarin Inc.
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using SR = System.Reflection;
34 using System.Text.RegularExpressions;
35 using System.Xml.XPath;
39 namespace Mono.Linker.Steps {
41 public class ResolveFromXmlStep : ResolveStep {
43 static readonly string _signature = "signature";
44 static readonly string _fullname = "fullname";
45 static readonly string _required = "required";
46 static readonly string _preserve = "preserve";
47 static readonly string _ns = string.Empty;
49 XPathDocument _document;
51 public ResolveFromXmlStep (XPathDocument document)
56 protected override void Process ()
58 XPathNavigator nav = _document.CreateNavigator ();
59 nav.MoveToFirstChild ();
60 ProcessAssemblies (Context, nav.SelectChildren ("assembly", _ns));
63 void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator)
65 while (iterator.MoveNext ()) {
66 AssemblyDefinition assembly = GetAssembly (context, GetFullName (iterator.Current));
67 ProcessTypes (assembly, iterator.Current.SelectChildren ("type", _ns));
68 ProcessNamespaces (assembly, iterator.Current.SelectChildren ("namespace", _ns));
72 void ProcessNamespaces (AssemblyDefinition assembly, XPathNodeIterator iterator)
74 while (iterator.MoveNext ()) {
75 string fullname = GetFullName (iterator.Current);
76 foreach (TypeDefinition type in assembly.MainModule.Types) {
77 if (type.Namespace != fullname)
80 MarkAndPreserveAll (type);
85 void MarkAndPreserveAll (TypeDefinition type)
87 Annotations.Mark (type);
88 Annotations.SetPreserve (type, TypePreserve.All);
90 if (!type.HasNestedTypes)
93 foreach (TypeDefinition nested in type.NestedTypes)
94 MarkAndPreserveAll (nested);
97 void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator)
99 while (iterator.MoveNext ()) {
100 XPathNavigator nav = iterator.Current;
101 string fullname = GetFullName (nav);
103 if (IsTypePattern (fullname)) {
104 ProcessTypePattern (fullname, assembly, nav);
108 TypeDefinition type = assembly.MainModule.GetType (fullname);
112 ProcessType (type, nav);
116 static bool IsTypePattern (string fullname)
118 return fullname.IndexOf ("*") != -1;
121 static Regex CreateRegexFromPattern (string pattern)
123 return new Regex (pattern.Replace(".", @"\.").Replace("*", "(.*)"));
126 void ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavigator nav)
128 Regex regex = CreateRegexFromPattern (fullname);
130 foreach (TypeDefinition type in assembly.MainModule.Types) {
131 if (!regex.Match (type.FullName).Success)
134 ProcessType (type, nav);
138 void ProcessType (TypeDefinition type, XPathNavigator nav)
140 TypePreserve preserve = GetTypePreserve (nav);
142 if (!IsRequired (nav)) {
143 Annotations.SetPreserve (type, preserve);
147 Annotations.Mark (type);
150 case TypePreserve.Nothing:
151 if (!nav.HasChildren)
152 Annotations.SetPreserve (type, TypePreserve.All);
155 Annotations.SetPreserve (type, preserve);
159 if (nav.HasChildren) {
160 MarkSelectedFields (nav, type);
161 MarkSelectedMethods (nav, type);
165 void MarkSelectedFields (XPathNavigator nav, TypeDefinition type)
167 XPathNodeIterator fields = nav.SelectChildren ("field", _ns);
168 if (fields.Count == 0)
171 ProcessFields (type, fields);
174 void MarkSelectedMethods (XPathNavigator nav, TypeDefinition type)
176 XPathNodeIterator methods = nav.SelectChildren ("method", _ns);
177 if (methods.Count == 0)
180 ProcessMethods (type, methods);
183 static TypePreserve GetTypePreserve (XPathNavigator nav)
185 string attribute = GetAttribute (nav, _preserve);
186 if (attribute == null || attribute.Length == 0)
187 return TypePreserve.Nothing;
190 return (TypePreserve) Enum.Parse (typeof (TypePreserve), attribute, true);
192 return TypePreserve.Nothing;
196 void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
198 while (iterator.MoveNext ()) {
199 string value = GetSignature (iterator.Current);
200 if (!String.IsNullOrEmpty (value))
201 ProcessFieldSignature (type, value);
203 value = GetAttribute (iterator.Current, "name");
204 if (!String.IsNullOrEmpty (value))
205 ProcessFieldName (type, value);
209 void ProcessFieldSignature (TypeDefinition type, string signature)
211 FieldDefinition field = GetField (type, signature);
212 MarkField (type, field, signature);
215 void MarkField (TypeDefinition type, FieldDefinition field, string signature)
218 Annotations.Mark (field);
220 AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
223 void ProcessFieldName (TypeDefinition type, string name)
228 foreach (FieldDefinition field in type.Fields)
229 if (field.Name == name)
230 MarkField (type, field, name);
233 static FieldDefinition GetField (TypeDefinition type, string signature)
238 foreach (FieldDefinition field in type.Fields)
239 if (signature == GetFieldSignature (field))
245 static string GetFieldSignature (FieldDefinition field)
247 return field.FieldType.FullName + " " + field.Name;
250 void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
252 while (iterator.MoveNext()) {
253 string value = GetSignature (iterator.Current);
254 if (!String.IsNullOrEmpty (value))
255 ProcessMethodSignature (type, value);
257 value = GetAttribute (iterator.Current, "name");
258 if (!String.IsNullOrEmpty (value))
259 ProcessMethodName (type, value);
263 void ProcessMethodSignature (TypeDefinition type, string signature)
265 MethodDefinition meth = GetMethod (type, signature);
266 MarkMethod (type, meth, signature);
269 void MarkMethod (TypeDefinition type, MethodDefinition method, string signature)
271 if (method != null) {
272 Annotations.Mark (method);
273 Annotations.SetAction (method, MethodAction.Parse);
275 AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
278 void ProcessMethodName (TypeDefinition type, string name)
280 if (!type.HasMethods)
283 foreach (MethodDefinition method in type.Methods)
284 if (name == method.Name)
285 MarkMethod (type, method, name);
288 static MethodDefinition GetMethod (TypeDefinition type, string signature)
291 foreach (MethodDefinition meth in type.Methods)
292 if (signature == GetMethodSignature (meth))
298 static string GetMethodSignature (MethodDefinition meth)
300 StringBuilder sb = new StringBuilder ();
301 sb.Append (meth.ReturnType.FullName);
303 sb.Append (meth.Name);
305 if (meth.HasParameters) {
306 for (int i = 0; i < meth.Parameters.Count; i++) {
310 sb.Append (meth.Parameters [i].ParameterType.FullName);
314 return sb.ToString ();
317 static AssemblyDefinition GetAssembly (LinkContext context, string assemblyName)
319 AssemblyNameReference reference = AssemblyNameReference.Parse (assemblyName);
320 AssemblyDefinition assembly;
322 assembly = context.Resolve (reference);
324 ProcessReferences (assembly, context);
328 static void ProcessReferences (AssemblyDefinition assembly, LinkContext context)
330 foreach (AssemblyNameReference name in assembly.MainModule.AssemblyReferences)
331 context.Resolve (name);
334 static bool IsRequired (XPathNavigator nav)
336 string attribute = GetAttribute (nav, _required);
337 if (attribute == null || attribute.Length == 0)
340 return TryParseBool (attribute);
343 static bool TryParseBool (string s)
346 return bool.Parse (s);
352 static string GetSignature (XPathNavigator nav)
354 return GetAttribute (nav, _signature);
357 static string GetFullName (XPathNavigator nav)
359 return GetAttribute (nav, _fullname);
362 static string GetAttribute (XPathNavigator nav, string attribute)
364 return nav.GetAttribute (attribute, _ns);