Merge pull request #2366 from xmcclure/scripts-babysitter
[mono.git] / mcs / tools / corcompare / mono-api-info.cs
index b32394dd5f79d0b8aec634b48cb236b5981f15d3..c43437fe40d869165c5b7d20f02eaa036c58a85f 100644 (file)
@@ -28,38 +28,64 @@ namespace CorCompare
        {
                public static int Main (string [] args)
                {
-                       if (args.Length == 0)
-                               return 1;
-
+                       bool showHelp = false;
                        AbiMode = false;
-
-                       AssemblyCollection acoll = new AssemblyCollection ();
+                       FollowForwarders = false;
+
+                       var acoll = new AssemblyCollection ();
+
+                       var options = new Mono.Options.OptionSet {
+                               "usage: mono-api-info [OPTIONS+] ASSEMBLY+",
+                               "",
+                               "Expose IL structure of CLR assemblies as XML.",
+                               "",
+                               "Available Options:",
+                               { "abi",
+                                       "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
+                                       v => AbiMode = v != null },
+                               { "f|follow-forwarders",
+                                       "Follow type forwarders.",
+                                       v => FollowForwarders = v != null },
+                               { "d|L|lib|search-directory=",
+                                       "Check for assembly references in {DIRECTORY}.",
+                                       v => TypeHelper.Resolver.AddSearchDirectory (v) },
+                               { "r=",
+                                       "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
+                                       v => TypeHelper.Resolver.ResolveFile (v) },
+                               { "h|?|help",
+                                       "Show this message and exit.",
+                                       v => showHelp = v != null },
+                       };
+
+                       var asms = options.Parse (args);
+
+                       if (showHelp || asms.Count == 0) {
+                               options.WriteOptionDescriptions (Console.Out);
+                               Console.WriteLine ();
+                               return showHelp? 0 :1;
+                       }
 
                        string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
                        string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                        TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
 
-                       foreach (string arg in args) {
-                               if (arg == "--abi") {
-                                       AbiMode = true;
-                               } else {
-                                       acoll.Add (arg);
-
-                                       if (arg.Contains ("v3.0")) {
-                                               TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
-                                       } else if (arg.Contains ("v3.5")) {
-                                               TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
-                                               TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
-                                       } else if (arg.Contains ("v4.0")) {
-                                               if (arg.Contains ("Silverlight")) {
-                                                       TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
-                                               } else {
-                                                       TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
-                                                       TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
-                                               }
+                       foreach (string arg in asms) {
+                               acoll.Add (arg);
+
+                               if (arg.Contains ("v3.0")) {
+                                       TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
+                               } else if (arg.Contains ("v3.5")) {
+                                       TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
+                                       TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
+                               } else if (arg.Contains ("v4.0")) {
+                                       if (arg.Contains ("Silverlight")) {
+                                               TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
                                        } else {
-                                               TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
+                                               TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
+                                               TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
                                        }
+                               } else {
+                                       TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
                                }
                        }
 
@@ -75,6 +101,7 @@ namespace CorCompare
                }
 
                internal static bool AbiMode { get; private set; }
+               internal static bool FollowForwarders { get; private set; }
        }
 
        public class Utils {
@@ -223,16 +250,33 @@ namespace CorCompare
                        AddAttribute (nassembly, "name", aname.Name);
                        AddAttribute (nassembly, "version", aname.Version.ToString ());
                        parent.AppendChild (nassembly);
-                       TypeForwardedToData.OutputForwarders (document, nassembly, ass);
+
+                       if (!Driver.FollowForwarders) {
+                               TypeForwardedToData.OutputForwarders (document, nassembly, ass);
+                       }
+
                        AttributeData.OutputAttributes (document, nassembly, ass);
-                       var typesCollection = ass.MainModule.Types;
-                       if (typesCollection == null || typesCollection.Count == 0)
+
+                       var types = new List<TypeDefinition> ();
+                       if (ass.MainModule.Types != null) {
+                               types.AddRange (ass.MainModule.Types);
+                       }
+
+                       if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
+                               foreach (var t in ass.MainModule.ExportedTypes) {
+                                       var forwarded = t.Resolve ();
+                                       if (forwarded == null) {
+                                               throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
+                                       }
+                                       types.Add (forwarded);
+                               }
+                       }
+
+                       if (types.Count == 0) {
                                return;
-                       var typesArray = new TypeDefinition [typesCollection.Count];
-                       for (int i = 0; i < typesCollection.Count; i++) {
-                               typesArray [i] = typesCollection [i];
                        }
-                       Array.Sort (typesArray, TypeReferenceComparer.Default);
+
+                       types.Sort (TypeReferenceComparer.Default);
 
                        XmlNode nss = document.CreateElement ("namespaces", null);
                        nassembly.AppendChild (nss);
@@ -240,7 +284,7 @@ namespace CorCompare
                        string current_namespace = "$%&$&";
                        XmlNode ns = null;
                        XmlNode classes = null;
-                       foreach (TypeDefinition t in typesArray) {
+                       foreach (TypeDefinition t in types) {
                                if (string.IsNullOrEmpty (t.Namespace))
                                        continue;
 
@@ -452,7 +496,7 @@ namespace CorCompare
 
                                PropertyDefinition[] properties = GetProperties (type);
                                if (properties.Length > 0) {
-                                       Array.Sort (properties, MemberReferenceComparer.Default);
+                                       Array.Sort (properties, PropertyDefinitionComparer.Default);
                                        members.Add (new PropertyData (document, nclass, properties));
                                }
 
@@ -1000,9 +1044,7 @@ namespace CorCompare
                                parent.AppendChild (natts);
                        }
 
-                       for (int i = 0; i < atts.Count; ++i) {
-                               CustomAttribute att = atts [i];
-
+                       foreach (var att in atts.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) {
                                string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
                                if (SkipAttribute (att))
                                        continue;
@@ -1340,19 +1382,17 @@ namespace CorCompare
 
        }
 
-       class TypeReferenceComparer : IComparer
+       class TypeReferenceComparer : IComparer<TypeReference>
        {
                public static TypeReferenceComparer Default = new TypeReferenceComparer ();
 
-               public int Compare (object a, object b)
+               public int Compare (TypeReference a, TypeReference b)
                {
-                       TypeReference ta = (TypeReference) a;
-                       TypeReference tb = (TypeReference) b;
-                       int result = String.Compare (ta.Namespace, tb.Namespace);
+                       int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
                        if (result != 0)
                                return result;
 
-                       return String.Compare (ta.Name, tb.Name);
+                       return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
                }
        }
 
@@ -1364,7 +1404,30 @@ namespace CorCompare
                {
                        MemberReference ma = (MemberReference) a;
                        MemberReference mb = (MemberReference) b;
-                       return String.Compare (ma.Name, mb.Name);
+                       return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
+               }
+       }
+
+       class PropertyDefinitionComparer : IComparer<PropertyDefinition>
+       {
+               public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
+
+               public int Compare (PropertyDefinition ma, PropertyDefinition mb)
+               {
+                       int res = String.Compare (ma.Name, mb.Name);
+                       if (res != 0)
+                               return res;
+
+                       if (!ma.HasParameters && !mb.HasParameters)
+                               return 0;
+
+                       if (!ma.HasParameters)
+                               return -1;
+
+                       if (!mb.HasParameters)
+                               return 1;
+
+                       return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
                }
        }
 
@@ -1389,9 +1452,17 @@ namespace CorCompare
                        if (!mb.HasParameters)
                                return 1;
 
-                       IList<ParameterDefinition> pia = ma.Parameters ;
-                       IList<ParameterDefinition> pib = mb.Parameters;
-                       res = pia.Count - pib.Count;
+                       res = Compare (ma.Parameters, mb.Parameters);
+                       if (res != 0)
+                               return res;
+
+                       // operators can differ by only return type
+                       return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
+               }
+
+               public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
+               {
+                       var res = pia.Count - pib.Count;
                        if (res != 0)
                                return res;