Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / ResolveFromXmlStep.cs
index 39c77f42e6103b7f47520ae9782e47ac2b7bab0f..5e9f681fd1784d25dfd201c93fc913c409c6fa9f 100644 (file)
@@ -6,6 +6,7 @@
 //
 // (C) 2006 Jb Evain
 // (C) 2007 Novell, Inc.
+// Copyright 2013 Xamarin Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 using System;
 using SR = System.Reflection;
 using System.Text;
+using System.Text.RegularExpressions;
 using System.Xml.XPath;
 
 using Mono.Cecil;
 
 namespace Mono.Linker.Steps {
 
+       public class XmlResolutionException : Exception {
+               public XmlResolutionException (string message, Exception innerException)
+                       : base (message, innerException)
+               {
+               }
+       }
+
        public class ResolveFromXmlStep : ResolveStep {
 
                static readonly string _signature = "signature";
@@ -45,17 +54,29 @@ namespace Mono.Linker.Steps {
                static readonly string _ns = string.Empty;
 
                XPathDocument _document;
+               string _xmlDocumentLocation;
 
-               public ResolveFromXmlStep (XPathDocument document)
+               public ResolveFromXmlStep (XPathDocument document, string xmlDocumentLocation = "<unspecified>")
                {
                        _document = document;
+                       _xmlDocumentLocation = xmlDocumentLocation;
                }
 
-               public override void Process (LinkContext context)
+               protected override void Process ()
                {
                        XPathNavigator nav = _document.CreateNavigator ();
                        nav.MoveToFirstChild ();
-                       ProcessAssemblies (context, nav.SelectChildren ("assembly", _ns));
+
+                       // This step can be created with XML files that aren't necessarily
+                       // linker descriptor files. So bail if we don't have a <linker> element.
+                       if (nav.LocalName != "linker")
+                               return;
+
+                       try {
+                               ProcessAssemblies (Context, nav.SelectChildren ("assembly", _ns));
+                       } catch (Exception ex) {
+                               throw new XmlResolutionException (string.Format ("Failed to process XML description: {0}", _xmlDocumentLocation), ex);
+                       }
                }
 
                void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator)
@@ -80,10 +101,14 @@ namespace Mono.Linker.Steps {
                        }
                }
 
-               static void MarkAndPreserveAll (TypeDefinition type)
+               void MarkAndPreserveAll (TypeDefinition type)
                {
                        Annotations.Mark (type);
                        Annotations.SetPreserve (type, TypePreserve.All);
+
+                       if (!type.HasNestedTypes)
+                               return;
+
                        foreach (TypeDefinition nested in type.NestedTypes)
                                MarkAndPreserveAll (nested);
                }
@@ -93,31 +118,75 @@ namespace Mono.Linker.Steps {
                        while (iterator.MoveNext ()) {
                                XPathNavigator nav = iterator.Current;
                                string fullname = GetFullName (nav);
-                               TypeDefinition type = assembly.MainModule.Types [fullname];
+
+                               if (IsTypePattern (fullname)) {
+                                       ProcessTypePattern (fullname, assembly, nav);
+                                       continue;
+                               }
+
+                               TypeDefinition type = assembly.MainModule.GetType (fullname);
                                if (type == null)
                                        continue;
 
-                               TypePreserve preserve = GetTypePreserve (nav);
+                               ProcessType (type, nav);
+                       }
+               }
 
-                               if (!IsRequired (nav)) {
-                                       Annotations.SetPreserve (type, preserve);
-                                       continue;
-                               }
+               static bool IsTypePattern (string fullname)
+               {
+                       return fullname.IndexOf ("*") != -1;
+               }
 
-                               Annotations.Mark (type);
-
-                               switch (preserve) {
-                               case TypePreserve.Nothing:
-                                       if (nav.HasChildren) {
-                                               MarkSelectedFields (nav, type);
-                                               MarkSelectedMethods (nav, type);
-                                       } else
-                                               Annotations.SetPreserve (type, TypePreserve.All);
-                                       break;
-                               default:
-                                       Annotations.SetPreserve (type, preserve);
-                                       break;
-                               }
+               static Regex CreateRegexFromPattern (string pattern)
+               {
+                       return new Regex (pattern.Replace(".", @"\.").Replace("*", "(.*)"));
+               }
+
+               void MatchType (TypeDefinition type, Regex regex, XPathNavigator nav)
+               {
+                       if (regex.Match (type.FullName).Success)
+                               ProcessType (type, nav);
+
+                       if (!type.HasNestedTypes)
+                               return;
+
+                       foreach (var nt in type.NestedTypes)
+                               MatchType (nt, regex, nav);
+               }
+
+               void ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavigator nav)
+               {
+                       Regex regex = CreateRegexFromPattern (fullname);
+
+                       foreach (TypeDefinition type in assembly.MainModule.Types) {
+                               MatchType (type, regex, nav);
+                       }
+               }
+
+               void ProcessType (TypeDefinition type, XPathNavigator nav)
+               {
+                       TypePreserve preserve = GetTypePreserve (nav);
+
+                       if (!IsRequired (nav)) {
+                               Annotations.SetPreserve (type, preserve);
+                               return;
+                       }
+
+                       Annotations.Mark (type);
+
+                       switch (preserve) {
+                       case TypePreserve.Nothing:
+                               if (!nav.HasChildren)
+                                       Annotations.SetPreserve (type, TypePreserve.All);
+                               break;
+                       default:
+                               Annotations.SetPreserve (type, preserve);
+                               break;
+                       }
+
+                       if (nav.HasChildren) {
+                               MarkSelectedFields (nav, type);
+                               MarkSelectedMethods (nav, type);
                        }
                }
 
@@ -155,17 +224,45 @@ namespace Mono.Linker.Steps {
                void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
                {
                        while (iterator.MoveNext ()) {
-                               string signature = GetSignature (iterator.Current);
-                               FieldDefinition field = GetField (type, signature);
-                               if (field != null)
-                                       Annotations.Mark (field);
-                               else
-                                       AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
+                               string value = GetSignature (iterator.Current);
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessFieldSignature (type, value);
+
+                               value = GetAttribute (iterator.Current, "name");
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessFieldName (type, value);
                        }
                }
 
+               void ProcessFieldSignature (TypeDefinition type, string signature)
+               {
+                       FieldDefinition field = GetField (type, signature);
+                       MarkField (type, field, signature);
+               }
+
+               void MarkField (TypeDefinition type, FieldDefinition field, string signature)
+               {
+                       if (field != null)
+                               Annotations.Mark (field);
+                       else
+                               AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
+               }
+
+               void ProcessFieldName (TypeDefinition type, string name)
+               {
+                       if (!type.HasFields)
+                               return;
+
+                       foreach (FieldDefinition field in type.Fields)
+                               if (field.Name == name)
+                                       MarkField (type, field, name);
+               }
+
                static FieldDefinition GetField (TypeDefinition type, string signature)
                {
+                       if (!type.HasFields)
+                               return null;
+
                        foreach (FieldDefinition field in type.Fields)
                                if (signature == GetFieldSignature (field))
                                        return field;
@@ -181,25 +278,47 @@ namespace Mono.Linker.Steps {
                void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
                {
                        while (iterator.MoveNext()) {
-                               string signature = GetSignature (iterator.Current);
-                               MethodDefinition meth = GetMethod (type, signature);
-                               if (meth != null) {
-                                       Annotations.Mark (meth);
-                                       Annotations.SetAction (meth, MethodAction.Parse);
-                               } else
-                                       AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
+                               string value = GetSignature (iterator.Current);
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessMethodSignature (type, value);
+
+                               value = GetAttribute (iterator.Current, "name");
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessMethodName (type, value);
                        }
                }
 
-               static MethodDefinition GetMethod (TypeDefinition type, string signature)
+               void ProcessMethodSignature (TypeDefinition type, string signature)
+               {
+                       MethodDefinition meth = GetMethod (type, signature);
+                       MarkMethod (type, meth, signature);
+               }
+
+               void MarkMethod (TypeDefinition type, MethodDefinition method, string signature)
+               {
+                       if (method != null) {
+                               Annotations.Mark (method);
+                               Annotations.SetAction (method, MethodAction.Parse);
+                       } else
+                               AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
+               }
+
+               void ProcessMethodName (TypeDefinition type, string name)
                {
-                       foreach (MethodDefinition meth in type.Methods)
-                               if (signature == GetMethodSignature (meth))
-                                       return meth;
+                       if (!type.HasMethods)
+                               return;
 
-                       foreach (MethodDefinition ctor in type.Constructors)
-                               if (signature == GetMethodSignature (ctor))
-                                       return ctor;
+                       foreach (MethodDefinition method in type.Methods)
+                               if (name == method.Name)
+                                       MarkMethod (type, method, name);
+               }
+
+               static MethodDefinition GetMethod (TypeDefinition type, string signature)
+               {
+                       if (type.HasMethods)
+                               foreach (MethodDefinition meth in type.Methods)
+                                       if (signature == GetMethodSignature (meth))
+                                               return meth;
 
                        return null;
                }
@@ -207,15 +326,17 @@ namespace Mono.Linker.Steps {
                static string GetMethodSignature (MethodDefinition meth)
                {
                        StringBuilder sb = new StringBuilder ();
-                       sb.Append (meth.ReturnType.ReturnType.FullName);
+                       sb.Append (meth.ReturnType.FullName);
                        sb.Append (" ");
                        sb.Append (meth.Name);
                        sb.Append ("(");
-                       for (int i = 0; i < meth.Parameters.Count; i++) {
-                               if (i > 0)
-                                       sb.Append (",");
+                       if (meth.HasParameters) {
+                               for (int i = 0; i < meth.Parameters.Count; i++) {
+                                       if (i > 0)
+                                               sb.Append (",");
 
-                               sb.Append (meth.Parameters [i].ParameterType.FullName);
+                                       sb.Append (meth.Parameters [i].ParameterType.FullName);
+                               }
                        }
                        sb.Append (")");
                        return sb.ToString ();
@@ -226,47 +347,18 @@ namespace Mono.Linker.Steps {
                        AssemblyNameReference reference = AssemblyNameReference.Parse (assemblyName);
                        AssemblyDefinition assembly;
 
-                       if (IsSimpleName (assemblyName)) {
-                               assembly = SearchAssemblyInContext (context, assemblyName);
-                               if (assembly != null)
-                                       return assembly;
-                       }
-
                        assembly = context.Resolve (reference);
 
-                       if (IsSimpleName (assemblyName))
-                               UpdateReferenceInCache (context, reference, assembly);
-
                        ProcessReferences (assembly, context);
                        return assembly;
                }
 
-               static void UpdateReferenceInCache (LinkContext context, AssemblyNameReference reference, AssemblyDefinition assembly)
-               {
-                       context.Resolver.AssemblyCache.Remove (reference.FullName);
-                       context.Resolver.AssemblyCache.Add (assembly.Name.FullName, assembly);
-               }
-
-               static AssemblyDefinition SearchAssemblyInContext (LinkContext context, string name)
-               {
-                       foreach (AssemblyDefinition assembly in context.GetAssemblies ())
-                               if (assembly.Name.Name == name)
-                                       return assembly;
-
-                       return null;
-               }
-
                static void ProcessReferences (AssemblyDefinition assembly, LinkContext context)
                {
                        foreach (AssemblyNameReference name in assembly.MainModule.AssemblyReferences)
                                context.Resolve (name);
                }
 
-               static bool IsSimpleName (string assemblyName)
-               {
-                       return assemblyName.IndexOf (",") == -1;
-               }
-
                static bool IsRequired (XPathNavigator nav)
                {
                        string attribute = GetAttribute (nav, _required);