[linker] Mark declaring types of nested types resolved from xml descriptors. Fixes...
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / ResolveFromXmlStep.cs
index 6a7493415089fe748206b766266af0840a5e598a..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,6 +174,14 @@ 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)
@@ -195,17 +232,18 @@ namespace Mono.Linker.Steps {
                void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
                {
                        while (iterator.MoveNext ()) {
-                               if (GetAttribute (iterator.Current, "signature") != null)
-                                       ProcessFieldSignature (type, iterator.Current);
+                               string value = GetSignature (iterator.Current);
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessFieldSignature (type, value);
 
-                               if (GetAttribute (iterator.Current, "name") != null)
-                                       ProcessFieldName (type, iterator.Current);
+                               value = GetAttribute (iterator.Current, "name");
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessFieldName (type, value);
                        }
                }
 
-               void ProcessFieldSignature (TypeDefinition type, XPathNavigator nav)
+               void ProcessFieldSignature (TypeDefinition type, string signature)
                {
-                       string signature = GetSignature (nav);
                        FieldDefinition field = GetField (type, signature);
                        MarkField (type, field, signature);
                }
@@ -218,12 +256,11 @@ namespace Mono.Linker.Steps {
                                AddUnresolveMarker (string.Format ("T: {0}; F: {1}", type, signature));
                }
 
-               void ProcessFieldName (TypeDefinition type, XPathNavigator nav)
+               void ProcessFieldName (TypeDefinition type, string name)
                {
                        if (!type.HasFields)
                                return;
 
-                       string name = GetAttribute (nav, "name");
                        foreach (FieldDefinition field in type.Fields)
                                if (field.Name == name)
                                        MarkField (type, field, name);
@@ -249,22 +286,23 @@ namespace Mono.Linker.Steps {
                void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
                {
                        while (iterator.MoveNext()) {
-                               if (GetAttribute (iterator.Current, "signature") != null)
-                                       ProcessMethodSignature (type, iterator.Current);
+                               string value = GetSignature (iterator.Current);
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessMethodSignature (type, value);
 
-                               if (GetAttribute (iterator.Current, "name") != null)
-                                       ProcessMethodName (type, iterator.Current);
+                               value = GetAttribute (iterator.Current, "name");
+                               if (!String.IsNullOrEmpty (value))
+                                       ProcessMethodName (type, value);
                        }
                }
 
-               void ProcessMethodSignature (TypeDefinition type, XPathNavigator nav)
+               void ProcessMethodSignature (TypeDefinition type, string signature)
                {
-                       string signature = GetSignature (nav);
                        MethodDefinition meth = GetMethod (type, signature);
                        MarkMethod (type, meth, signature);
                }
 
-               private void MarkMethod (TypeDefinition type, MethodDefinition method, string signature)
+               void MarkMethod (TypeDefinition type, MethodDefinition method, string signature)
                {
                        if (method != null) {
                                Annotations.Mark (method);
@@ -273,18 +311,14 @@ namespace Mono.Linker.Steps {
                                AddUnresolveMarker (string.Format ("T: {0}; M: {1}", type, signature));
                }
 
-               void ProcessMethodName (TypeDefinition type, XPathNavigator nav)
+               void ProcessMethodName (TypeDefinition type, string name)
                {
-                       string name = GetAttribute (nav, "name");
-                       if (name == ".ctor" || name == ".cctor" && type.HasConstructors)
-                               foreach (MethodDefinition ctor in type.Constructors)
-                                       if (name == ctor.Name)
-                                               MarkMethod (type, ctor, name);
+                       if (!type.HasMethods)
+                               return;
 
-                       if (type.HasMethods)
-                               foreach (MethodDefinition method in type.Methods)
-                                       if (name == method.Name)
-                                               MarkMethod (type, method, name);
+                       foreach (MethodDefinition method in type.Methods)
+                               if (name == method.Name)
+                                       MarkMethod (type, method, name);
                }
 
                static MethodDefinition GetMethod (TypeDefinition type, string signature)
@@ -294,18 +328,13 @@ namespace Mono.Linker.Steps {
                                        if (signature == GetMethodSignature (meth))
                                                return meth;
 
-                       if (type.HasConstructors)
-                               foreach (MethodDefinition ctor in type.Constructors)
-                                       if (signature == GetMethodSignature (ctor))
-                                               return ctor;
-
                        return null;
                }
 
                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 ("(");