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 XmlResolutionException
: Exception
{
42 public XmlResolutionException (string message
, Exception innerException
)
43 : base (message
, innerException
)
48 public class ResolveFromXmlStep
: ResolveStep
{
50 static readonly string _signature
= "signature";
51 static readonly string _fullname
= "fullname";
52 static readonly string _required
= "required";
53 static readonly string _preserve
= "preserve";
54 static readonly string _ns
= string.Empty
;
56 XPathDocument _document
;
57 string _xmlDocumentLocation
;
59 public ResolveFromXmlStep (XPathDocument document
, string xmlDocumentLocation
= "<unspecified>")
62 _xmlDocumentLocation
= xmlDocumentLocation
;
65 protected override void Process ()
67 XPathNavigator nav
= _document
.CreateNavigator ();
68 nav
.MoveToFirstChild ();
70 // This step can be created with XML files that aren't necessarily
71 // linker descriptor files. So bail if we don't have a <linker> element.
72 if (nav
.LocalName
!= "linker")
76 ProcessAssemblies (Context
, nav
.SelectChildren ("assembly", _ns
));
77 } catch (Exception ex
) {
78 throw new XmlResolutionException (string.Format ("Failed to process XML description: {0}", _xmlDocumentLocation
), ex
);
82 void ProcessAssemblies (LinkContext context
, XPathNodeIterator iterator
)
84 while (iterator
.MoveNext ()) {
85 AssemblyDefinition assembly
= GetAssembly (context
, GetFullName (iterator
.Current
));
86 ProcessTypes (assembly
, iterator
.Current
.SelectChildren ("type", _ns
));
87 ProcessNamespaces (assembly
, iterator
.Current
.SelectChildren ("namespace", _ns
));
91 void ProcessNamespaces (AssemblyDefinition assembly
, XPathNodeIterator iterator
)
93 while (iterator
.MoveNext ()) {
94 string fullname
= GetFullName (iterator
.Current
);
95 foreach (TypeDefinition type
in assembly
.MainModule
.Types
) {
96 if (type
.Namespace
!= fullname
)
99 MarkAndPreserveAll (type
);
104 void MarkAndPreserveAll (TypeDefinition type
)
106 Annotations
.Mark (type
);
107 Annotations
.SetPreserve (type
, TypePreserve
.All
);
109 if (!type
.HasNestedTypes
)
112 foreach (TypeDefinition nested
in type
.NestedTypes
)
113 MarkAndPreserveAll (nested
);
116 void ProcessTypes (AssemblyDefinition assembly
, XPathNodeIterator iterator
)
118 while (iterator
.MoveNext ()) {
119 XPathNavigator nav
= iterator
.Current
;
120 string fullname
= GetFullName (nav
);
122 if (IsTypePattern (fullname
)) {
123 ProcessTypePattern (fullname
, assembly
, nav
);
127 TypeDefinition type
= assembly
.MainModule
.GetType (fullname
);
131 ProcessType (type
, nav
);
135 static bool IsTypePattern (string fullname
)
137 return fullname
.IndexOf ("*") != -1;
140 static Regex
CreateRegexFromPattern (string pattern
)
142 return new Regex (pattern
.Replace(".", @"\.").Replace("*", "(.*)"));
145 void MatchType (TypeDefinition type
, Regex regex
, XPathNavigator nav
)
147 if (regex
.Match (type
.FullName
).Success
)
148 ProcessType (type
, nav
);
150 if (!type
.HasNestedTypes
)
153 foreach (var nt
in type
.NestedTypes
)
154 MatchType (nt
, regex
, nav
);
157 void ProcessTypePattern (string fullname
, AssemblyDefinition assembly
, XPathNavigator nav
)
159 Regex regex
= CreateRegexFromPattern (fullname
);
161 foreach (TypeDefinition type
in assembly
.MainModule
.Types
) {
162 MatchType (type
, regex
, nav
);
166 void ProcessType (TypeDefinition type
, XPathNavigator nav
)
168 TypePreserve preserve
= GetTypePreserve (nav
);
170 if (!IsRequired (nav
)) {
171 Annotations
.SetPreserve (type
, preserve
);
175 Annotations
.Mark (type
);
178 case TypePreserve
.Nothing
:
179 if (!nav
.HasChildren
)
180 Annotations
.SetPreserve (type
, TypePreserve
.All
);
183 Annotations
.SetPreserve (type
, preserve
);
187 if (nav
.HasChildren
) {
188 MarkSelectedFields (nav
, type
);
189 MarkSelectedMethods (nav
, type
);
193 void MarkSelectedFields (XPathNavigator nav
, TypeDefinition type
)
195 XPathNodeIterator fields
= nav
.SelectChildren ("field", _ns
);
196 if (fields
.Count
== 0)
199 ProcessFields (type
, fields
);
202 void MarkSelectedMethods (XPathNavigator nav
, TypeDefinition type
)
204 XPathNodeIterator methods
= nav
.SelectChildren ("method", _ns
);
205 if (methods
.Count
== 0)
208 ProcessMethods (type
, methods
);
211 static TypePreserve
GetTypePreserve (XPathNavigator nav
)
213 string attribute
= GetAttribute (nav
, _preserve
);
214 if (attribute
== null || attribute
.Length
== 0)
215 return TypePreserve
.Nothing
;
218 return (TypePreserve
) Enum
.Parse (typeof (TypePreserve
), attribute
, true);
220 return TypePreserve
.Nothing
;
224 void ProcessFields (TypeDefinition type
, XPathNodeIterator iterator
)
226 while (iterator
.MoveNext ()) {
227 string value = GetSignature (iterator
.Current
);
228 if (!String
.IsNullOrEmpty (value))
229 ProcessFieldSignature (type
, value);
231 value = GetAttribute (iterator
.Current
, "name");
232 if (!String
.IsNullOrEmpty (value))
233 ProcessFieldName (type
, value);
237 void ProcessFieldSignature (TypeDefinition type
, string signature
)
239 FieldDefinition field
= GetField (type
, signature
);
240 MarkField (type
, field
, signature
);
243 void MarkField (TypeDefinition type
, FieldDefinition field
, string signature
)
246 Annotations
.Mark (field
);
248 AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type
, signature
));
251 void ProcessFieldName (TypeDefinition type
, string name
)
256 foreach (FieldDefinition field
in type
.Fields
)
257 if (field
.Name
== name
)
258 MarkField (type
, field
, name
);
261 static FieldDefinition
GetField (TypeDefinition type
, string signature
)
266 foreach (FieldDefinition field
in type
.Fields
)
267 if (signature
== GetFieldSignature (field
))
273 static string GetFieldSignature (FieldDefinition field
)
275 return field
.FieldType
.FullName
+ " " + field
.Name
;
278 void ProcessMethods (TypeDefinition type
, XPathNodeIterator iterator
)
280 while (iterator
.MoveNext()) {
281 string value = GetSignature (iterator
.Current
);
282 if (!String
.IsNullOrEmpty (value))
283 ProcessMethodSignature (type
, value);
285 value = GetAttribute (iterator
.Current
, "name");
286 if (!String
.IsNullOrEmpty (value))
287 ProcessMethodName (type
, value);
291 void ProcessMethodSignature (TypeDefinition type
, string signature
)
293 MethodDefinition meth
= GetMethod (type
, signature
);
294 MarkMethod (type
, meth
, signature
);
297 void MarkMethod (TypeDefinition type
, MethodDefinition method
, string signature
)
299 if (method
!= null) {
300 Annotations
.Mark (method
);
301 Annotations
.SetAction (method
, MethodAction
.Parse
);
303 AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type
, signature
));
306 void ProcessMethodName (TypeDefinition type
, string name
)
308 if (!type
.HasMethods
)
311 foreach (MethodDefinition method
in type
.Methods
)
312 if (name
== method
.Name
)
313 MarkMethod (type
, method
, name
);
316 static MethodDefinition
GetMethod (TypeDefinition type
, string signature
)
319 foreach (MethodDefinition meth
in type
.Methods
)
320 if (signature
== GetMethodSignature (meth
))
326 static string GetMethodSignature (MethodDefinition meth
)
328 StringBuilder sb
= new StringBuilder ();
329 sb
.Append (meth
.ReturnType
.FullName
);
331 sb
.Append (meth
.Name
);
333 if (meth
.HasParameters
) {
334 for (int i
= 0; i
< meth
.Parameters
.Count
; i
++) {
338 sb
.Append (meth
.Parameters
[i
].ParameterType
.FullName
);
342 return sb
.ToString ();
345 static AssemblyDefinition
GetAssembly (LinkContext context
, string assemblyName
)
347 AssemblyNameReference reference
= AssemblyNameReference
.Parse (assemblyName
);
348 AssemblyDefinition assembly
;
350 assembly
= context
.Resolve (reference
);
352 ProcessReferences (assembly
, context
);
356 static void ProcessReferences (AssemblyDefinition assembly
, LinkContext context
)
358 foreach (AssemblyNameReference name
in assembly
.MainModule
.AssemblyReferences
)
359 context
.Resolve (name
);
362 static bool IsRequired (XPathNavigator nav
)
364 string attribute
= GetAttribute (nav
, _required
);
365 if (attribute
== null || attribute
.Length
== 0)
368 return TryParseBool (attribute
);
371 static bool TryParseBool (string s
)
374 return bool.Parse (s
);
380 static string GetSignature (XPathNavigator nav
)
382 return GetAttribute (nav
, _signature
);
385 static string GetFullName (XPathNavigator nav
)
387 return GetAttribute (nav
, _fullname
);
390 static string GetAttribute (XPathNavigator nav
, string attribute
)
392 return nav
.GetAttribute (attribute
, _ns
);