3dee36ae97df5d1619e46bb38866ee495862b434
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / ResolveFromXmlStep.cs
1 //
2 // ResolveFromXmlStep.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 Jb Evain
8 // (C) 2007 Novell, Inc.
9 //
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:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
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.
28 //
29
30 using System;
31 using SR = System.Reflection;
32 using System.Text;
33 using System.Text.RegularExpressions;
34 using System.Xml.XPath;
35
36 using Mono.Cecil;
37
38 namespace Mono.Linker.Steps {
39
40         public class ResolveFromXmlStep : ResolveStep {
41
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;
47
48                 XPathDocument _document;
49
50                 public ResolveFromXmlStep (XPathDocument document)
51                 {
52                         _document = document;
53                 }
54
55                 public override void Process (LinkContext context)
56                 {
57                         XPathNavigator nav = _document.CreateNavigator ();
58                         nav.MoveToFirstChild ();
59                         ProcessAssemblies (context, nav.SelectChildren ("assembly", _ns));
60                 }
61
62                 void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator)
63                 {
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));
68                         }
69                 }
70
71                 void ProcessNamespaces (AssemblyDefinition assembly, XPathNodeIterator iterator)
72                 {
73                         while (iterator.MoveNext ()) {
74                                 string fullname = GetFullName (iterator.Current);
75                                 foreach (TypeDefinition type in assembly.MainModule.Types) {
76                                         if (type.Namespace != fullname)
77                                                 continue;
78
79                                         MarkAndPreserveAll (type);
80                                 }
81                         }
82                 }
83
84                 static void MarkAndPreserveAll (TypeDefinition type)
85                 {
86                         Annotations.Mark (type);
87                         Annotations.SetPreserve (type, TypePreserve.All);
88
89                         if (!type.HasNestedTypes)
90                                 return;
91
92                         foreach (TypeDefinition nested in type.NestedTypes)
93                                 MarkAndPreserveAll (nested);
94                 }
95
96                 void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator)
97                 {
98                         while (iterator.MoveNext ()) {
99                                 XPathNavigator nav = iterator.Current;
100                                 string fullname = GetFullName (nav);
101
102                                 if (IsTypePattern (fullname)) {
103                                         ProcessTypePattern (fullname, assembly, nav);
104                                         continue;
105                                 }
106
107                                 TypeDefinition type = assembly.MainModule.Types [fullname];
108                                 if (type == null)
109                                         continue;
110
111                                 ProcessType (type, nav);
112                         }
113                 }
114
115                 static bool IsTypePattern (string fullname)
116                 {
117                         return fullname.IndexOf ("*") != -1;
118                 }
119
120                 static Regex CreateRegexFromPattern (string pattern)
121                 {
122                         return new Regex (pattern.Replace(".", @"\.").Replace("*", "(.*)"));
123                 }
124
125                 void ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavigator nav)
126                 {
127                         Regex regex = CreateRegexFromPattern (fullname);
128
129                         foreach (TypeDefinition type in assembly.MainModule.Types) {
130                                 if (!regex.Match (type.FullName).Success)
131                                         continue;
132
133                                 ProcessType (type, nav);
134                         }
135                 }
136
137                 void ProcessType (TypeDefinition type, XPathNavigator nav)
138                 {
139                         TypePreserve preserve = GetTypePreserve (nav);
140
141                         if (!IsRequired (nav)) {
142                                 Annotations.SetPreserve (type, preserve);
143                                 return;
144                         }
145
146                         Annotations.Mark (type);
147
148                         switch (preserve) {
149                         case TypePreserve.Nothing:
150                                 if (nav.HasChildren) {
151                                         MarkSelectedFields (nav, type);
152                                         MarkSelectedMethods (nav, type);
153                                 } else
154                                         Annotations.SetPreserve (type, TypePreserve.All);
155                                 break;
156                         default:
157                                 Annotations.SetPreserve (type, preserve);
158                                 break;
159                         }
160                 }
161
162                 void MarkSelectedFields (XPathNavigator nav, TypeDefinition type)
163                 {
164                         XPathNodeIterator fields = nav.SelectChildren ("field", _ns);
165                         if (fields.Count == 0)
166                                 return;
167
168                         ProcessFields (type, fields);
169                 }
170
171                 void MarkSelectedMethods (XPathNavigator nav, TypeDefinition type)
172                 {
173                         XPathNodeIterator methods = nav.SelectChildren ("method", _ns);
174                         if (methods.Count == 0)
175                                 return;
176
177                         ProcessMethods (type, methods);
178                 }
179
180                 static TypePreserve GetTypePreserve (XPathNavigator nav)
181                 {
182                         string attribute = GetAttribute (nav, _preserve);
183                         if (attribute == null || attribute.Length == 0)
184                                 return TypePreserve.Nothing;
185
186                         try {
187                                 return (TypePreserve) Enum.Parse (typeof (TypePreserve), attribute, true);
188                         } catch {
189                                 return TypePreserve.Nothing;
190                         }
191                 }
192
193                 void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
194                 {
195                         while (iterator.MoveNext ()) {
196                                 string signature = GetSignature (iterator.Current);
197                                 FieldDefinition field = GetField (type, signature);
198                                 if (field != null)
199                                         Annotations.Mark (field);
200                                 else
201                                         AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
202                         }
203                 }
204
205                 static FieldDefinition GetField (TypeDefinition type, string signature)
206                 {
207                         if (!type.HasFields)
208                                 return null;
209
210                         foreach (FieldDefinition field in type.Fields)
211                                 if (signature == GetFieldSignature (field))
212                                         return field;
213
214                         return null;
215                 }
216
217                 static string GetFieldSignature (FieldDefinition field)
218                 {
219                         return field.FieldType.FullName + " " + field.Name;
220                 }
221
222                 void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
223                 {
224                         while (iterator.MoveNext()) {
225                                 string signature = GetSignature (iterator.Current);
226                                 MethodDefinition meth = GetMethod (type, signature);
227                                 if (meth != null) {
228                                         Annotations.Mark (meth);
229                                         Annotations.SetAction (meth, MethodAction.Parse);
230                                 } else
231                                         AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
232                         }
233                 }
234
235                 static MethodDefinition GetMethod (TypeDefinition type, string signature)
236                 {
237                         if (!type.HasMethods)
238                                 return null;
239
240                         foreach (MethodDefinition meth in type.Methods)
241                                 if (signature == GetMethodSignature (meth))
242                                         return meth;
243
244                         foreach (MethodDefinition ctor in type.Constructors)
245                                 if (signature == GetMethodSignature (ctor))
246                                         return ctor;
247
248                         return null;
249                 }
250
251                 static string GetMethodSignature (MethodDefinition meth)
252                 {
253                         StringBuilder sb = new StringBuilder ();
254                         sb.Append (meth.ReturnType.ReturnType.FullName);
255                         sb.Append (" ");
256                         sb.Append (meth.Name);
257                         sb.Append ("(");
258                         if (meth.HasParameters) {
259                                 for (int i = 0; i < meth.Parameters.Count; i++) {
260                                         if (i > 0)
261                                                 sb.Append (",");
262
263                                         sb.Append (meth.Parameters [i].ParameterType.FullName);
264                                 }
265                         }
266                         sb.Append (")");
267                         return sb.ToString ();
268                 }
269
270                 static AssemblyDefinition GetAssembly (LinkContext context, string assemblyName)
271                 {
272                         AssemblyNameReference reference = AssemblyNameReference.Parse (assemblyName);
273                         AssemblyDefinition assembly;
274
275                         assembly = context.Resolve (reference);
276
277                         ProcessReferences (assembly, context);
278                         return assembly;
279                 }
280
281                 static void ProcessReferences (AssemblyDefinition assembly, LinkContext context)
282                 {
283                         foreach (AssemblyNameReference name in assembly.MainModule.AssemblyReferences)
284                                 context.Resolve (name);
285                 }
286
287                 static bool IsRequired (XPathNavigator nav)
288                 {
289                         string attribute = GetAttribute (nav, _required);
290                         if (attribute == null || attribute.Length == 0)
291                                 return true;
292
293                         return TryParseBool (attribute);
294                 }
295
296                 static bool TryParseBool (string s)
297                 {
298                         try {
299                                 return bool.Parse (s);
300                         } catch {
301                                 return false;
302                         }
303                 }
304
305                 static string GetSignature (XPathNavigator nav)
306                 {
307                         return GetAttribute (nav, _signature);
308                 }
309
310                 static string GetFullName (XPathNavigator nav)
311                 {
312                         return GetAttribute (nav, _fullname);
313                 }
314
315                 static string GetAttribute (XPathNavigator nav, string attribute)
316                 {
317                         return nav.GetAttribute (attribute, _ns);
318                 }
319         }
320 }