[linker] Mark declaring types of nested types resolved from xml descriptors. Fixes...
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / ResolveFromXmlStep.cs
index 3dee36ae97df5d1619e46bb38866ee495862b434..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
@@ -37,6 +38,13 @@ 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";
@@ -46,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)
@@ -81,7 +101,7 @@ namespace Mono.Linker.Steps {
                        }
                }
 
-               static void MarkAndPreserveAll (TypeDefinition type)
+               void MarkAndPreserveAll (TypeDefinition type)
                {
                        Annotations.Mark (type);
                        Annotations.SetPreserve (type, TypePreserve.All);
@@ -104,7 +124,7 @@ namespace Mono.Linker.Steps {
                                        continue;
                                }
 
-                               TypeDefinition type = assembly.MainModule.Types [fullname];
+                               TypeDefinition type = assembly.MainModule.GetType (fullname);
                                if (type == null)
                                        continue;
 
@@ -122,15 +142,24 @@ namespace Mono.Linker.Steps {
                        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) {
-                               if (!regex.Match (type.FullName).Success)
-                                       continue;
-
-                               ProcessType (type, nav);
+                               MatchType (type, regex, nav);
                        }
                }
 
@@ -145,18 +174,28 @@ namespace Mono.Linker.Steps {
 
                        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) {
-                                       MarkSelectedFields (nav, type);
-                                       MarkSelectedMethods (nav, type);
-                               } else
+                               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)
@@ -193,15 +232,40 @@ 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)
@@ -222,28 +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)
+               {
+                       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)
                {
                        if (!type.HasMethods)
-                               return null;
+                               return;
 
-                       foreach (MethodDefinition meth in type.Methods)
-                               if (signature == GetMethodSignature (meth))
-                                       return meth;
+                       foreach (MethodDefinition method in type.Methods)
+                               if (name == method.Name)
+                                       MarkMethod (type, method, name);
+               }
 
-                       foreach (MethodDefinition ctor in type.Constructors)
-                               if (signature == GetMethodSignature (ctor))
-                                       return ctor;
+               static MethodDefinition GetMethod (TypeDefinition type, string signature)
+               {
+                       if (type.HasMethods)
+                               foreach (MethodDefinition meth in type.Methods)
+                                       if (signature == GetMethodSignature (meth))
+                                               return meth;
 
                        return null;
                }
@@ -251,7 +334,7 @@ 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 ("(");