2 // ResolveFromXmlStep.cs
5 // Jb Evain (jbevain@gmail.com)
8 // (C) 2007 Novell, Inc.
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using SR = System.Reflection;
33 using System.Text.RegularExpressions;
34 using System.Xml.XPath;
38 namespace Mono.Linker.Steps {
40 public class ResolveFromXmlStep : ResolveStep {
42 static readonly string _signature = "signature";
43 static readonly string _fullname = "fullname";
44 static readonly string _required = "required";
45 static readonly string _preserve = "preserve";
46 static readonly string _ns = string.Empty;
48 XPathDocument _document;
50 public ResolveFromXmlStep (XPathDocument document)
55 public override void Process (LinkContext context)
57 XPathNavigator nav = _document.CreateNavigator ();
58 nav.MoveToFirstChild ();
59 ProcessAssemblies (context, nav.SelectChildren ("assembly", _ns));
62 void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator)
64 while (iterator.MoveNext ()) {
65 AssemblyDefinition assembly = GetAssembly (context, GetFullName (iterator.Current));
66 ProcessTypes (assembly, iterator.Current.SelectChildren ("type", _ns));
67 ProcessNamespaces (assembly, iterator.Current.SelectChildren ("namespace", _ns));
71 void ProcessNamespaces (AssemblyDefinition assembly, XPathNodeIterator iterator)
73 while (iterator.MoveNext ()) {
74 string fullname = GetFullName (iterator.Current);
75 foreach (TypeDefinition type in assembly.MainModule.Types) {
76 if (type.Namespace != fullname)
79 MarkAndPreserveAll (type);
84 static void MarkAndPreserveAll (TypeDefinition type)
86 Annotations.Mark (type);
87 Annotations.SetPreserve (type, TypePreserve.All);
89 if (!type.HasNestedTypes)
92 foreach (TypeDefinition nested in type.NestedTypes)
93 MarkAndPreserveAll (nested);
96 void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator)
98 while (iterator.MoveNext ()) {
99 XPathNavigator nav = iterator.Current;
100 string fullname = GetFullName (nav);
102 if (IsTypePattern (fullname)) {
103 ProcessTypePattern (fullname, assembly, nav);
107 TypeDefinition type = assembly.MainModule.Types [fullname];
111 ProcessType (type, nav);
115 static bool IsTypePattern (string fullname)
117 return fullname.IndexOf ("*") != -1;
120 static Regex CreateRegexFromPattern (string pattern)
122 return new Regex (pattern.Replace(".", @"\.").Replace("*", "(.*)"));
125 void ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavigator nav)
127 Regex regex = CreateRegexFromPattern (fullname);
129 foreach (TypeDefinition type in assembly.MainModule.Types) {
130 if (!regex.Match (type.FullName).Success)
133 ProcessType (type, nav);
137 void ProcessType (TypeDefinition type, XPathNavigator nav)
139 TypePreserve preserve = GetTypePreserve (nav);
141 if (!IsRequired (nav)) {
142 Annotations.SetPreserve (type, preserve);
146 Annotations.Mark (type);
149 case TypePreserve.Nothing:
150 if (nav.HasChildren) {
151 MarkSelectedFields (nav, type);
152 MarkSelectedMethods (nav, type);
154 Annotations.SetPreserve (type, TypePreserve.All);
157 Annotations.SetPreserve (type, preserve);
162 void MarkSelectedFields (XPathNavigator nav, TypeDefinition type)
164 XPathNodeIterator fields = nav.SelectChildren ("field", _ns);
165 if (fields.Count == 0)
168 ProcessFields (type, fields);
171 void MarkSelectedMethods (XPathNavigator nav, TypeDefinition type)
173 XPathNodeIterator methods = nav.SelectChildren ("method", _ns);
174 if (methods.Count == 0)
177 ProcessMethods (type, methods);
180 static TypePreserve GetTypePreserve (XPathNavigator nav)
182 string attribute = GetAttribute (nav, _preserve);
183 if (attribute == null || attribute.Length == 0)
184 return TypePreserve.Nothing;
187 return (TypePreserve) Enum.Parse (typeof (TypePreserve), attribute, true);
189 return TypePreserve.Nothing;
193 void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
195 while (iterator.MoveNext ()) {
196 string signature = GetSignature (iterator.Current);
197 FieldDefinition field = GetField (type, signature);
199 Annotations.Mark (field);
201 AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
205 static FieldDefinition GetField (TypeDefinition type, string signature)
210 foreach (FieldDefinition field in type.Fields)
211 if (signature == GetFieldSignature (field))
217 static string GetFieldSignature (FieldDefinition field)
219 return field.FieldType.FullName + " " + field.Name;
222 void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
224 while (iterator.MoveNext()) {
225 string signature = GetSignature (iterator.Current);
226 MethodDefinition meth = GetMethod (type, signature);
228 Annotations.Mark (meth);
229 Annotations.SetAction (meth, MethodAction.Parse);
231 AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
235 static MethodDefinition GetMethod (TypeDefinition type, string signature)
237 if (!type.HasMethods)
240 foreach (MethodDefinition meth in type.Methods)
241 if (signature == GetMethodSignature (meth))
244 foreach (MethodDefinition ctor in type.Constructors)
245 if (signature == GetMethodSignature (ctor))
251 static string GetMethodSignature (MethodDefinition meth)
253 StringBuilder sb = new StringBuilder ();
254 sb.Append (meth.ReturnType.ReturnType.FullName);
256 sb.Append (meth.Name);
258 if (meth.HasParameters) {
259 for (int i = 0; i < meth.Parameters.Count; i++) {
263 sb.Append (meth.Parameters [i].ParameterType.FullName);
267 return sb.ToString ();
270 static AssemblyDefinition GetAssembly (LinkContext context, string assemblyName)
272 AssemblyNameReference reference = AssemblyNameReference.Parse (assemblyName);
273 AssemblyDefinition assembly;
275 assembly = context.Resolve (reference);
277 ProcessReferences (assembly, context);
281 static void ProcessReferences (AssemblyDefinition assembly, LinkContext context)
283 foreach (AssemblyNameReference name in assembly.MainModule.AssemblyReferences)
284 context.Resolve (name);
287 static bool IsRequired (XPathNavigator nav)
289 string attribute = GetAttribute (nav, _required);
290 if (attribute == null || attribute.Length == 0)
293 return TryParseBool (attribute);
296 static bool TryParseBool (string s)
299 return bool.Parse (s);
305 static string GetSignature (XPathNavigator nav)
307 return GetAttribute (nav, _signature);
310 static string GetFullName (XPathNavigator nav)
312 return GetAttribute (nav, _fullname);
315 static string GetAttribute (XPathNavigator nav, string attribute)
317 return nav.GetAttribute (attribute, _ns);