[w32handle] Stop returning 0 in every cases for locking/unlocking (#3926)
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / ResolveFromXmlStep.cs
index ac806fb0a67f96069aa1b7d8f7df05a72b28b87d..aa4f6afc760388c38a5f1267ab4f2aa69f9ce473 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,32 +118,84 @@ 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;
+               }
+
+               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);
 
-                               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;
+                       if (!IsRequired (nav)) {
+                               Annotations.SetPreserve (type, preserve);
+                               return;
+                       }
+
+                       Annotations.Mark (type);
+
+                       if (type.IsNested) {
+                               var parent = type;
+                               while (parent.IsNested) {
+                                       parent = parent.DeclaringType;
+                                       Annotations.Mark (parent);
                                }
                        }
+
+                       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);
+                       }
                }
 
                void MarkSelectedFields (XPathNavigator nav, TypeDefinition type)
@@ -155,17 +232,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 +286,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)
                {
-                       foreach (MethodDefinition meth in type.Methods)
-                               if (signature == GetMethodSignature (meth))
-                                       return meth;
+                       if (method != null) {
+                               Annotations.Mark (method);
+                               Annotations.SetAction (method, MethodAction.Parse);
+                       } else
+                               AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
+               }
 
-                       foreach (MethodDefinition ctor in type.Constructors)
-                               if (signature == GetMethodSignature (ctor))
-                                       return ctor;
+               void ProcessMethodName (TypeDefinition type, string name)
+               {
+                       if (!type.HasMethods)
+                               return;
+
+                       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 +334,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 ();