Merge pull request #2366 from xmcclure/scripts-babysitter
[mono.git] / mcs / tools / corcompare / mono-api-info.cs
index 203875b15ccf4701050a53f44fd36d1bffcf94f3..c43437fe40d869165c5b7d20f02eaa036c58a85f 100644 (file)
@@ -11,6 +11,7 @@ using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Security.Permissions;
@@ -19,6 +20,7 @@ using System.Xml;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
+using System.IO;
 
 namespace CorCompare
 {
@@ -26,13 +28,65 @@ namespace CorCompare
        {
                public static int Main (string [] args)
                {
-                       if (args.Length == 0)
-                               return 1;
-
-                       AssemblyCollection acoll = new AssemblyCollection ();
+                       bool showHelp = false;
+                       AbiMode = false;
+                       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;
+                       }
 
-                       foreach (string fullName in args) {
-                               acoll.Add (fullName);
+                       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 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.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));
+                               }
                        }
 
                        XmlDocument doc = new XmlDocument ();
@@ -45,6 +99,9 @@ namespace CorCompare
                        doc.WriteTo (writer);
                        return 0;
                }
+
+               internal static bool AbiMode { get; private set; }
+               internal static bool FollowForwarders { get; private set; }
        }
 
        public class Utils {
@@ -54,7 +111,7 @@ namespace CorCompare
                        return CleanupTypeName (type.FullName);
                }
 
-               static string CleanupTypeName (string t)
+               public static string CleanupTypeName (string t)
                {
                        return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
                }
@@ -72,8 +129,10 @@ namespace CorCompare
                public bool Add (string name)
                {
                        AssemblyDefinition ass = LoadAssembly (name);
-                       if (ass == null)
+                       if (ass == null) {
+                               Console.Error.WriteLine ("Cannot load assembly file " + name);
                                return false;
+                       }
 
                        assemblies.Add (ass);
                        return true;
@@ -99,8 +158,12 @@ namespace CorCompare
                AssemblyDefinition LoadAssembly (string assembly)
                {
                        try {
+                               if (File.Exists (assembly))
+                                       return TypeHelper.Resolver.ResolveFile (assembly);
+
                                return TypeHelper.Resolver.Resolve (assembly);
-                       } catch {
+                       } catch (Exception e) {
+                               Console.WriteLine (e);
                                return null;
                        }
                }
@@ -144,13 +207,10 @@ namespace CorCompare
                                natts = document.CreateElement ("attributes", null);
                                parent.AppendChild (natts);
                        }
-                       
-                       foreach (TypeReference tref in ass.MainModule.ExternTypes) {
-                               TypeDefinition def = tref.Resolve ();
-                               if (def == null)
-                                       continue;
 
-                               if (((uint)def.Attributes & 0x200000u) == 0)
+                       foreach (ExportedType type in ass.MainModule.ExportedTypes) {
+
+                               if (((uint)type.Attributes & 0x200000u) == 0)
                                        continue;
 
                                XmlNode node = document.CreateElement ("attribute");
@@ -158,7 +218,7 @@ namespace CorCompare
                                XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
                                XmlNode property = properties.AppendChild (document.CreateElement ("property"));
                                AddAttribute (property, "name", "Destination");
-                               AddAttribute (property, "value", Utils.CleanupTypeName (tref));
+                               AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
                                natts.AppendChild (node);
                        }
                }
@@ -169,7 +229,7 @@ namespace CorCompare
                        tftd.DoOutput ();
                }
        }
-       
+
        class AssemblyData : BaseData
        {
                AssemblyDefinition ass;
@@ -190,16 +250,33 @@ namespace CorCompare
                        AddAttribute (nassembly, "name", aname.Name);
                        AddAttribute (nassembly, "version", aname.Version.ToString ());
                        parent.AppendChild (nassembly);
-                       TypeForwardedToData.OutputForwarders (document, nassembly, ass);
-                       AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
-                       TypeDefinitionCollection typesCollection = ass.MainModule.Types;
-                       if (typesCollection == null || typesCollection.Count == 0)
+
+                       if (!Driver.FollowForwarders) {
+                               TypeForwardedToData.OutputForwarders (document, nassembly, ass);
+                       }
+
+                       AttributeData.OutputAttributes (document, nassembly, ass);
+
+                       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;
-                       object [] typesArray = new object [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);
@@ -207,11 +284,11 @@ 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;
 
-                               if ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)
+                               if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
                                        continue;
 
                                if (t.DeclaringType != null)
@@ -254,15 +331,12 @@ namespace CorCompare
                                if (!NoMemberAttributes)
                                        AddAttribute (mnode, "attrib", GetMemberAttributes (member));
 
-                               AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
+                               AttributeData.OutputAttributes (document, mnode, (ICustomAttributeProvider) member);
 
                                AddExtraData (mnode, member);
                        }
                }
 
-
-               protected abstract CustomAttributeCollection GetCustomAttributes (MemberReference member);
-
                protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
                {
                }
@@ -297,15 +371,15 @@ namespace CorCompare
 
                        var gparameters = provider.GenericParameters;
 
-                       XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
+                       XmlElement ngeneric = document.CreateElement ("generic-parameters");
                        nclass.AppendChild (ngeneric);
 
                        foreach (GenericParameter gp in gparameters) {
-                               XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
+                               XmlElement nparam = document.CreateElement ("generic-parameter");
                                nparam.SetAttribute ("name", gp.Name);
                                nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
 
-                               AttributeData.OutputAttributes (document, nparam, gp.CustomAttributes);
+                               AttributeData.OutputAttributes (document, nparam, gp);
 
                                ngeneric.AppendChild (nparam);
 
@@ -335,11 +409,6 @@ namespace CorCompare
                {
                        this.type = type;
                }
-
-               protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
-                       return ((TypeDefinition) member).CustomAttributes;
-               }
-
                public override void DoOutput ()
                {
                        if (document == null)
@@ -369,13 +438,21 @@ namespace CorCompare
                        if (layout != null)
                                AddAttribute (nclass, "layout", layout);
 
+                       if (type.PackingSize >= 0) {
+                               AddAttribute (nclass, "pack", type.PackingSize.ToString ());
+                       }
+
+                       if (type.ClassSize >= 0) {
+                               AddAttribute (nclass, "size", type.ClassSize.ToString ());
+                       }
+
                        parent.AppendChild (nclass);
 
-                       AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
+                       AttributeData.OutputAttributes (document, nclass, type);
 
                        XmlNode ifaces = null;
 
-                       foreach (TypeReference iface in  TypeHelper.GetInterfaces (type)) {
+                       foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) {
                                if (!TypeHelper.IsPublic (iface))
                                        // we're only interested in public interfaces
                                        continue;
@@ -409,34 +486,37 @@ namespace CorCompare
                                AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
                        }
 
-                       MethodDefinition [] ctors = GetConstructors (type);
-                       if (ctors.Length > 0) {
-                               Array.Sort (ctors, MemberReferenceComparer.Default);
-                               members.Add (new ConstructorData (document, nclass, ctors));
-                       }
+                       if (!Driver.AbiMode) {
 
-                       PropertyDefinition[] properties = GetProperties (type);
-                       if (properties.Length > 0) {
-                               Array.Sort (properties, MemberReferenceComparer.Default);
-                               members.Add (new PropertyData (document, nclass, properties));
-                       }
+                               MethodDefinition [] ctors = GetConstructors (type);
+                               if (ctors.Length > 0) {
+                                       Array.Sort (ctors, MethodDefinitionComparer.Default);
+                                       members.Add (new ConstructorData (document, nclass, ctors));
+                               }
 
-                       EventDefinition [] events = GetEvents (type);
-                       if (events.Length > 0) {
-                               Array.Sort (events, MemberReferenceComparer.Default);
-                               members.Add (new EventData (document, nclass, events));
-                       }
+                               PropertyDefinition[] properties = GetProperties (type);
+                               if (properties.Length > 0) {
+                                       Array.Sort (properties, PropertyDefinitionComparer.Default);
+                                       members.Add (new PropertyData (document, nclass, properties));
+                               }
+
+                               EventDefinition [] events = GetEvents (type);
+                               if (events.Length > 0) {
+                                       Array.Sort (events, MemberReferenceComparer.Default);
+                                       members.Add (new EventData (document, nclass, events));
+                               }
 
-                       MethodDefinition [] methods = GetMethods (type);
-                       if (methods.Length > 0) {
-                               Array.Sort (methods, MemberReferenceComparer.Default);
-                               members.Add (new MethodData (document, nclass, methods));
+                               MethodDefinition [] methods = GetMethods (type);
+                               if (methods.Length > 0) {
+                                       Array.Sort (methods, MethodDefinitionComparer.Default);
+                                       members.Add (new MethodData (document, nclass, methods));
+                               }
                        }
 
                        foreach (MemberData md in members)
                                md.DoOutput ();
 
-                       NestedTypeCollection nested = type.NestedTypes;
+                       var nested = type.NestedTypes;
                        //remove non public(familiy) and nested in second degree
                        for (int i = nested.Count - 1; i >= 0; i--) {
                                TypeDefinition t = nested [i];
@@ -451,11 +531,13 @@ namespace CorCompare
                                nested.RemoveAt (i);
                        }
 
-
                        if (nested.Count > 0) {
+                               var nestedArray = nested.ToArray ();
+                               Array.Sort (nestedArray, TypeReferenceComparer.Default);
+
                                XmlNode classes = document.CreateElement ("classes", null);
                                nclass.AppendChild (classes);
-                               foreach (TypeDefinition t in nested) {
+                               foreach (TypeDefinition t in nestedArray) {
                                        TypeData td = new TypeData (document, classes, t);
                                        td.DoOutput ();
                                }
@@ -501,6 +583,9 @@ namespace CorCompare
                        if (TypeHelper.IsDelegate(t))
                                return "delegate";
 
+                       if (t.IsPointer)
+                               return "pointer";
+
                        return "class";
                }
 
@@ -537,17 +622,24 @@ namespace CorCompare
                FieldDefinition [] GetFields (TypeDefinition type) {
                        ArrayList list = new ArrayList ();
 
-                       FieldDefinitionCollection fields = type.Fields;
+                       var fields = type.Fields;
                        foreach (FieldDefinition field in fields) {
                                if (field.IsSpecialName)
                                        continue;
 
+                               if (Driver.AbiMode && field.IsStatic)
+                                       continue;
+
                                // we're only interested in public or protected members
                                FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
-                               if (maskedVisibility == FieldAttributes.Public
-                                       || maskedVisibility == FieldAttributes.Family
-                                       || maskedVisibility == FieldAttributes.FamORAssem) {
+                               if (Driver.AbiMode && !field.IsNotSerialized) {
                                        list.Add (field);
+                               } else {
+                                       if (maskedVisibility == FieldAttributes.Public
+                                               || maskedVisibility == FieldAttributes.Family
+                                               || maskedVisibility == FieldAttributes.FamORAssem) {
+                                               list.Add (field);
+                                       }
                                }
                        }
 
@@ -558,7 +650,7 @@ namespace CorCompare
                internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
                        ArrayList list = new ArrayList ();
 
-                       PropertyDefinitionCollection properties = type.Properties;//type.GetProperties (flags);
+                       var properties = type.Properties;//type.GetProperties (flags);
                        foreach (PropertyDefinition property in properties) {
                                MethodDefinition getMethod = property.GetMethod;
                                MethodDefinition setMethod = property.SetMethod;
@@ -580,7 +672,7 @@ namespace CorCompare
                {
                        ArrayList list = new ArrayList ();
 
-                       MethodDefinitionCollection methods = type.Methods;//type.GetMethods (flags);
+                       var methods = type.Methods;//type.GetMethods (flags);
                        foreach (MethodDefinition method in methods) {
                                if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
                                        continue;
@@ -589,8 +681,14 @@ namespace CorCompare
                                if (!MustDocumentMethod(method))
                                        continue;
 
-                               if (IsFinalizer (method))
-                                       continue;
+                               if (IsFinalizer (method)) {
+                                       string name = method.DeclaringType.Name;
+                                       int arity = name.IndexOf ('`');
+                                       if (arity > 0)
+                                               name = name.Substring (0, arity);
+
+                                       method.Name = "~" + name;
+                               }
 
                                list.Add (method);
                        }
@@ -616,7 +714,7 @@ namespace CorCompare
                {
                        ArrayList list = new ArrayList ();
 
-                       ConstructorCollection ctors = type.Constructors;//type.GetConstructors (flags);
+                       var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
                        foreach (MethodDefinition constructor in ctors) {
                                // we're only interested in public or protected members
                                if (!MustDocumentMethod(constructor))
@@ -632,7 +730,7 @@ namespace CorCompare
                {
                        ArrayList list = new ArrayList ();
 
-                       EventDefinitionCollection events = type.Events;//type.GetEvents (flags);
+                       var events = type.Events;//type.GetEvents (flags);
                        foreach (EventDefinition eventDef in events) {
                                MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
 
@@ -653,10 +751,6 @@ namespace CorCompare
                {
                }
 
-               protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
-                       return ((FieldDefinition) member).CustomAttributes;
-               }
-
                protected override string GetName (MemberReference memberDefenition)
                {
                        FieldDefinition field = (FieldDefinition) memberDefenition;
@@ -709,10 +803,6 @@ namespace CorCompare
                {
                }
 
-               protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
-                       return ((PropertyDefinition) member).CustomAttributes;
-               }
-
                protected override string GetName (MemberReference memberDefenition)
                {
                        PropertyDefinition prop = (PropertyDefinition) memberDefenition;
@@ -741,9 +831,11 @@ namespace CorCompare
                                return;
                        }
 
-                       string parms = Parameters.GetSignature (methods [0].Parameters);
-                       if (!string.IsNullOrEmpty (parms))
-                               AddAttribute (p, "params", parms);
+                       if (haveGet || _set.Parameters.Count > 1) {
+                               string parms = Parameters.GetSignature (methods [0].Parameters);
+                               if (!string.IsNullOrEmpty (parms))
+                                       AddAttribute (p, "params", parms);
+                       }
 
                        MethodData data = new MethodData (document, p, methods);
                        //data.NoMemberAttributes = true;
@@ -772,10 +864,6 @@ namespace CorCompare
                {
                }
 
-               protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
-                       return ((EventDefinition) member).CustomAttributes;
-               }
-
                protected override string GetName (MemberReference memberDefenition)
                {
                        EventDefinition evt = (EventDefinition) memberDefenition;
@@ -813,10 +901,6 @@ namespace CorCompare
                {
                }
 
-               protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
-                       return ((MethodDefinition) member).CustomAttributes;
-               }
-
                protected override string GetName (MemberReference memberDefenition)
                {
                        MethodDefinition method = (MethodDefinition) memberDefenition;
@@ -848,14 +932,16 @@ namespace CorCompare
                                AddAttribute (p, "abstract", "true");
                        if (mbase.IsVirtual)
                                AddAttribute (p, "virtual", "true");
+                       if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
+                               AddAttribute (p, "sealed", "true");
                        if (mbase.IsStatic)
                                AddAttribute (p, "static", "true");
 
-                       string rettype = Utils.CleanupTypeName (mbase.ReturnType.ReturnType);
+                       string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
                        if (rettype != "System.Void" || !mbase.IsConstructor)
                                AddAttribute (p, "returntype", (rettype));
 
-                       AttributeData.OutputAttributes (document, p, mbase.ReturnType.CustomAttributes);
+                       AttributeData.OutputAttributes (document, p, mbase.MethodReturnType);
 
                        MemberData.OutputGenericParameters (document, p, mbase);
                }
@@ -892,9 +978,9 @@ namespace CorCompare
 
        class ParameterData : BaseData
        {
-               private ParameterDefinitionCollection parameters;
+               private IList<ParameterDefinition> parameters;
 
-               public ParameterData (XmlDocument document, XmlNode parent, ParameterDefinitionCollection parameters)
+               public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
                        : base (document, parent)
                {
                        this.parameters = parameters;
@@ -914,7 +1000,7 @@ namespace CorCompare
 
                                string direction = "in";
 
-                               if (parameter.ParameterType is ReferenceType)
+                               if (parameter.ParameterType is ByReferenceType)
                                        direction = parameter.IsOut ? "out" : "ref";
 
                                TypeReference t = parameter.ParameterType;
@@ -929,16 +1015,16 @@ namespace CorCompare
                                if (direction != "in")
                                        AddAttribute (paramNode, "direction", direction);
 
-                               AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
+                               AttributeData.OutputAttributes (document, paramNode, parameter);
                        }
                }
        }
 
        class AttributeData : BaseData
        {
-               CustomAttributeCollection atts;
+               IList<CustomAttribute> atts;
 
-               AttributeData (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
+               AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
                        : base (doc, parent)
                {
                        atts = attributes;
@@ -958,15 +1044,7 @@ namespace CorCompare
                                parent.AppendChild (natts);
                        }
 
-                       for (int i = 0; i < atts.Count; ++i) {
-                               CustomAttribute att = atts [i];
-                               try {
-                                       att.Resolve ();
-                               } catch {}
-
-                               if (!att.Resolved)
-                                       continue;
-
+                       foreach (var att in atts.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) {
                                string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
                                if (SkipAttribute (att))
                                        continue;
@@ -995,6 +1073,7 @@ namespace CorCompare
                                                AddAttribute (n, "value", "null");
                                                continue;
                                        }
+                                       
                                        string value = o.ToString ();
                                        if (attName.EndsWith ("GuidAttribute"))
                                                value = value.ToUpper ();
@@ -1012,7 +1091,7 @@ namespace CorCompare
                        PopulateMapping (mapping, attribute);
 
                        var constructor = attribute.Constructor.Resolve ();
-                       if (constructor == null || constructor.Parameters.Count == 0)
+                       if (constructor == null || !constructor.HasParameters)
                                return mapping;
 
                        PopulateMapping (mapping, constructor, attribute);
@@ -1022,10 +1101,17 @@ namespace CorCompare
 
                static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
                {
-                       foreach (DictionaryEntry entry in attribute.Properties) {
-                               var name = (string) entry.Key;
+                       if (!attribute.HasProperties)
+                               return;
+                       
+                       foreach (var named_argument in attribute.Properties) {
+                               var name = named_argument.Name;
+                               var arg = named_argument.Argument;
+
+                               if (arg.Value is CustomAttributeArgument)
+                                       arg = (CustomAttributeArgument) arg.Value;
 
-                               mapping.Add (name, GetArgumentValue (attribute.GetPropertyType (name), entry.Value));
+                               mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
                        }
                }
 
@@ -1048,7 +1134,7 @@ namespace CorCompare
                                        break;
                                case Code.Ldarg:
                                case Code.Ldarg_S:
-                                       argument = ((ParameterDefinition) instruction.Operand).Sequence;
+                                       argument = ((ParameterDefinition) instruction.Operand).Index + 1;
                                        break;
 
                                case Code.Stfld:
@@ -1101,6 +1187,29 @@ namespace CorCompare
                        if (!constructor.HasBody)
                                return;
 
+                       // Custom handling for attributes with arguments which cannot be easily extracted
+                       var ca = attribute.ConstructorArguments;
+                       switch (constructor.DeclaringType.FullName) {
+                       case "System.Runtime.CompilerServices.DecimalConstantAttribute":
+                               var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
+                                       new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
+                                       new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
+
+                               mapping.Add ("Value", dca.Value);
+                               return;
+                       case "System.ComponentModel.BindableAttribute":
+                               if (ca.Count != 1)
+                                       break;
+
+                               if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
+                                       mapping.Add ("Bindable", ca[0].Value);
+                               } else {
+                                       throw new NotImplementedException ();
+                               }
+
+                               return;
+                       }
+
                        var field_mapping = CreateArgumentFieldMapping (constructor);
                        var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
 
@@ -1109,7 +1218,11 @@ namespace CorCompare
                                if (!field_mapping.TryGetValue (pair.Value, out argument))
                                        continue;
 
-                               mapping.Add (pair.Key.Name, GetArgumentValue (constructor.Parameters [argument].ParameterType, attribute.ConstructorParameters [argument]));
+                               var ca_arg = ca [argument];
+                               if (ca_arg.Value is CustomAttributeArgument)
+                                       ca_arg = (CustomAttributeArgument) ca_arg.Value;
+
+                               mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
                        }
                }
 
@@ -1134,7 +1247,7 @@ namespace CorCompare
                        if (!type.IsEnum)
                                return false;
 
-                       if (type.CustomAttributes.Count == 0)
+                       if (!type.HasCustomAttributes)
                                return false;
 
                        foreach (CustomAttribute attribute in type.CustomAttributes)
@@ -1146,6 +1259,9 @@ namespace CorCompare
 
                static object GetFlaggedEnumValue (TypeDefinition type, object value)
                {
+                       if (value is ulong)
+                               return GetFlaggedEnumValue (type, (ulong)value);
+
                        long flags = Convert.ToInt64 (value);
                        var signature = new StringBuilder ();
 
@@ -1172,6 +1288,33 @@ namespace CorCompare
                        return signature.ToString ();
                }
 
+               static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
+               {
+                       var signature = new StringBuilder ();
+
+                       for (int i = type.Fields.Count - 1; i >= 0; i--) {
+                               FieldDefinition field = type.Fields [i];
+
+                               if (!field.HasConstant)
+                                       continue;
+
+                               ulong flag = Convert.ToUInt64 (field.Constant);
+
+                               if (flag == 0)
+                                       continue;
+
+                               if ((flags & flag) == flag) {
+                                       if (signature.Length != 0)
+                                               signature.Append (", ");
+
+                                       signature.Append (field.Name);
+                                       flags -= flag;
+                               }
+                       }
+
+                       return signature.ToString ();
+               }
+
                static object GetEnumValue (TypeDefinition type, object value)
                {
                        foreach (FieldDefinition field in type.Fields) {
@@ -1193,19 +1336,22 @@ namespace CorCompare
                                || type_name.EndsWith ("TODOAttribute");
                }
 
-               public static void OutputAttributes (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
+               public static void OutputAttributes (XmlDocument doc, XmlNode parent, ICustomAttributeProvider provider)
                {
-                       AttributeData ad = new AttributeData (doc, parent, attributes);
+                       if (!provider.HasCustomAttributes)
+                               return;
+                       
+                       AttributeData ad = new AttributeData (doc, parent, provider.CustomAttributes);
                        ad.DoOutput ();
                }
        }
 
        static class Parameters {
 
-               public static string GetSignature (ParameterDefinitionCollection infos)
+               public static string GetSignature (IList<ParameterDefinition> infos)
                {
                        if (infos == null || infos.Count == 0)
-                               return "";
+                               return string.Empty;
 
                        var signature = new StringBuilder ();
                        for (int i = 0; i < infos.Count; i++) {
@@ -1218,15 +1364,15 @@ namespace CorCompare
                                string modifier;
                                if ((info.Attributes & ParameterAttributes.In) != 0)
                                        modifier = "in";
-                               else if ((info.Attributes & ParameterAttributes.Retval) != 0)
-                                       modifier = "ref";
                                else if ((info.Attributes & ParameterAttributes.Out) != 0)
                                        modifier = "out";
                                else
                                        modifier = string.Empty;
 
-                               if (modifier.Length > 0)
-                                       signature.AppendFormat ("{0} ", modifier);
+                               if (modifier.Length > 0) {
+                                       signature.Append (modifier);
+                                       signature.Append (" ");
+                               }
 
                                signature.Append (Utils.CleanupTypeName (info.ParameterType));
                        }
@@ -1236,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);
                }
        }
 
@@ -1260,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);
                }
        }
 
@@ -1276,9 +1443,26 @@ namespace CorCompare
                        if (res != 0)
                                return res;
 
-                       ParameterDefinitionCollection pia = ma.Parameters ;
-                       ParameterDefinitionCollection pib = mb.Parameters;
-                       res = pia.Count - pib.Count;
+                       if (!ma.HasParameters && !mb.HasParameters)
+                               return 0;
+
+                       if (!ma.HasParameters)
+                               return -1;
+
+                       if (!mb.HasParameters)
+                               return 1;
+
+                       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;