c43437fe40d869165c5b7d20f02eaa036c58a85f
[mono.git] / mcs / tools / corcompare / mono-api-info.cs
1 //
2 // mono-api-info.cs - Dumps public assembly information to an xml file.
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // Copyright (C) 2003-2008 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.Collections.Generic;
13 using System.Globalization;
14 using System.Linq;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
18 using System.Text;
19 using System.Xml;
20
21 using Mono.Cecil;
22 using Mono.Cecil.Cil;
23 using System.IO;
24
25 namespace CorCompare
26 {
27         public class Driver
28         {
29                 public static int Main (string [] args)
30                 {
31                         bool showHelp = false;
32                         AbiMode = false;
33                         FollowForwarders = false;
34
35                         var acoll = new AssemblyCollection ();
36
37                         var options = new Mono.Options.OptionSet {
38                                 "usage: mono-api-info [OPTIONS+] ASSEMBLY+",
39                                 "",
40                                 "Expose IL structure of CLR assemblies as XML.",
41                                 "",
42                                 "Available Options:",
43                                 { "abi",
44                                         "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
45                                         v => AbiMode = v != null },
46                                 { "f|follow-forwarders",
47                                         "Follow type forwarders.",
48                                         v => FollowForwarders = v != null },
49                                 { "d|L|lib|search-directory=",
50                                         "Check for assembly references in {DIRECTORY}.",
51                                         v => TypeHelper.Resolver.AddSearchDirectory (v) },
52                                 { "r=",
53                                         "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
54                                         v => TypeHelper.Resolver.ResolveFile (v) },
55                                 { "h|?|help",
56                                         "Show this message and exit.",
57                                         v => showHelp = v != null },
58                         };
59
60                         var asms = options.Parse (args);
61
62                         if (showHelp || asms.Count == 0) {
63                                 options.WriteOptionDescriptions (Console.Out);
64                                 Console.WriteLine ();
65                                 return showHelp? 0 :1;
66                         }
67
68                         string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
69                         string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
70                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
71
72                         foreach (string arg in asms) {
73                                 acoll.Add (arg);
74
75                                 if (arg.Contains ("v3.0")) {
76                                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
77                                 } else if (arg.Contains ("v3.5")) {
78                                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
79                                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
80                                 } else if (arg.Contains ("v4.0")) {
81                                         if (arg.Contains ("Silverlight")) {
82                                                 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
83                                         } else {
84                                                 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
85                                                 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
86                                         }
87                                 } else {
88                                         TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
89                                 }
90                         }
91
92                         XmlDocument doc = new XmlDocument ();
93                         acoll.Document = doc;
94                         acoll.DoOutput ();
95
96                         var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
97                         XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
98                         doc.InsertBefore (decl, doc.DocumentElement);
99                         doc.WriteTo (writer);
100                         return 0;
101                 }
102
103                 internal static bool AbiMode { get; private set; }
104                 internal static bool FollowForwarders { get; private set; }
105         }
106
107         public class Utils {
108
109                 public static string CleanupTypeName (TypeReference type)
110                 {
111                         return CleanupTypeName (type.FullName);
112                 }
113
114                 public static string CleanupTypeName (string t)
115                 {
116                         return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
117                 }
118         }
119
120         class AssemblyCollection
121         {
122                 XmlDocument document;
123                 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
124
125                 public AssemblyCollection ()
126                 {
127                 }
128
129                 public bool Add (string name)
130                 {
131                         AssemblyDefinition ass = LoadAssembly (name);
132                         if (ass == null) {
133                                 Console.Error.WriteLine ("Cannot load assembly file " + name);
134                                 return false;
135                         }
136
137                         assemblies.Add (ass);
138                         return true;
139                 }
140
141                 public void DoOutput ()
142                 {
143                         if (document == null)
144                                 throw new InvalidOperationException ("Document not set");
145
146                         XmlNode nassemblies = document.CreateElement ("assemblies", null);
147                         document.AppendChild (nassemblies);
148                         foreach (AssemblyDefinition a in assemblies) {
149                                 AssemblyData data = new AssemblyData (document, nassemblies, a);
150                                 data.DoOutput ();
151                         }
152                 }
153
154                 public XmlDocument Document {
155                         set { document = value; }
156                 }
157
158                 AssemblyDefinition LoadAssembly (string assembly)
159                 {
160                         try {
161                                 if (File.Exists (assembly))
162                                         return TypeHelper.Resolver.ResolveFile (assembly);
163
164                                 return TypeHelper.Resolver.Resolve (assembly);
165                         } catch (Exception e) {
166                                 Console.WriteLine (e);
167                                 return null;
168                         }
169                 }
170         }
171
172         abstract class BaseData
173         {
174                 protected XmlDocument document;
175                 protected XmlNode parent;
176
177                 protected BaseData (XmlDocument doc, XmlNode parent)
178                 {
179                         this.document = doc;
180                         this.parent = parent;
181                 }
182
183                 public abstract void DoOutput ();
184
185                 protected void AddAttribute (XmlNode node, string name, string value)
186                 {
187                         XmlAttribute attr = document.CreateAttribute (name);
188                         attr.Value = value;
189                         node.Attributes.Append (attr);
190                 }
191         }
192
193         class TypeForwardedToData : BaseData
194         {
195                 AssemblyDefinition ass;
196
197                 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
198                         : base (document, parent)
199                 {
200                         this.ass = ass;
201                 }
202
203                 public override void DoOutput ()
204                 {
205                         XmlNode natts = parent.SelectSingleNode("attributes");
206                         if (natts == null) {
207                                 natts = document.CreateElement ("attributes", null);
208                                 parent.AppendChild (natts);
209                         }
210
211                         foreach (ExportedType type in ass.MainModule.ExportedTypes) {
212
213                                 if (((uint)type.Attributes & 0x200000u) == 0)
214                                         continue;
215
216                                 XmlNode node = document.CreateElement ("attribute");
217                                 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
218                                 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
219                                 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
220                                 AddAttribute (property, "name", "Destination");
221                                 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
222                                 natts.AppendChild (node);
223                         }
224                 }
225
226                 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
227                 {
228                         TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
229                         tftd.DoOutput ();
230                 }
231         }
232
233         class AssemblyData : BaseData
234         {
235                 AssemblyDefinition ass;
236
237                 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
238                         : base (document, parent)
239                 {
240                         this.ass = ass;
241                 }
242
243                 public override void DoOutput ()
244                 {
245                         if (document == null)
246                                 throw new InvalidOperationException ("Document not set");
247
248                         XmlNode nassembly = document.CreateElement ("assembly", null);
249                         AssemblyNameDefinition aname = ass.Name;
250                         AddAttribute (nassembly, "name", aname.Name);
251                         AddAttribute (nassembly, "version", aname.Version.ToString ());
252                         parent.AppendChild (nassembly);
253
254                         if (!Driver.FollowForwarders) {
255                                 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
256                         }
257
258                         AttributeData.OutputAttributes (document, nassembly, ass);
259
260                         var types = new List<TypeDefinition> ();
261                         if (ass.MainModule.Types != null) {
262                                 types.AddRange (ass.MainModule.Types);
263                         }
264
265                         if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
266                                 foreach (var t in ass.MainModule.ExportedTypes) {
267                                         var forwarded = t.Resolve ();
268                                         if (forwarded == null) {
269                                                 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
270                                         }
271                                         types.Add (forwarded);
272                                 }
273                         }
274
275                         if (types.Count == 0) {
276                                 return;
277                         }
278
279                         types.Sort (TypeReferenceComparer.Default);
280
281                         XmlNode nss = document.CreateElement ("namespaces", null);
282                         nassembly.AppendChild (nss);
283
284                         string current_namespace = "$%&$&";
285                         XmlNode ns = null;
286                         XmlNode classes = null;
287                         foreach (TypeDefinition t in types) {
288                                 if (string.IsNullOrEmpty (t.Namespace))
289                                         continue;
290
291                                 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
292                                         continue;
293
294                                 if (t.DeclaringType != null)
295                                         continue; // enforce !nested
296
297                                 if (t.Namespace != current_namespace) {
298                                         current_namespace = t.Namespace;
299                                         ns = document.CreateElement ("namespace", null);
300                                         AddAttribute (ns, "name", current_namespace);
301                                         nss.AppendChild (ns);
302                                         classes = document.CreateElement ("classes", null);
303                                         ns.AppendChild (classes);
304                                 }
305
306                                 TypeData bd = new TypeData (document, classes, t);
307                                 bd.DoOutput ();
308                         }
309                 }
310         }
311
312         abstract class MemberData : BaseData
313         {
314                 MemberReference [] members;
315
316                 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
317                         : base (document, parent)
318                 {
319                         this.members = members;
320                 }
321
322                 public override void DoOutput ()
323                 {
324                         XmlNode mclass = document.CreateElement (ParentTag, null);
325                         parent.AppendChild (mclass);
326
327                         foreach (MemberReference member in members) {
328                                 XmlNode mnode = document.CreateElement (Tag, null);
329                                 mclass.AppendChild (mnode);
330                                 AddAttribute (mnode, "name", GetName (member));
331                                 if (!NoMemberAttributes)
332                                         AddAttribute (mnode, "attrib", GetMemberAttributes (member));
333
334                                 AttributeData.OutputAttributes (document, mnode, (ICustomAttributeProvider) member);
335
336                                 AddExtraData (mnode, member);
337                         }
338                 }
339
340                 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
341                 {
342                 }
343
344                 protected virtual string GetName (MemberReference memberDefenition)
345                 {
346                         return "NoNAME";
347                 }
348
349                 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
350                 {
351                         return null;
352                 }
353
354                 public virtual bool NoMemberAttributes {
355                         get { return false; }
356                         set {}
357                 }
358
359                 public virtual string ParentTag {
360                         get { return "NoPARENTTAG"; }
361                 }
362
363                 public virtual string Tag {
364                         get { return "NoTAG"; }
365                 }
366
367                 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
368                 {
369                         if (provider.GenericParameters.Count == 0)
370                                 return;
371
372                         var gparameters = provider.GenericParameters;
373
374                         XmlElement ngeneric = document.CreateElement ("generic-parameters");
375                         nclass.AppendChild (ngeneric);
376
377                         foreach (GenericParameter gp in gparameters) {
378                                 XmlElement nparam = document.CreateElement ("generic-parameter");
379                                 nparam.SetAttribute ("name", gp.Name);
380                                 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
381
382                                 AttributeData.OutputAttributes (document, nparam, gp);
383
384                                 ngeneric.AppendChild (nparam);
385
386                                 var constraints = gp.Constraints;
387                                 if (constraints.Count == 0)
388                                         continue;
389
390                                 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
391
392                                 foreach (TypeReference constraint in constraints) {
393                                         XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
394                                         ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
395                                         nconstraint.AppendChild (ncons);
396                                 }
397
398                                 nparam.AppendChild (nconstraint);
399                         }
400                 }
401         }
402
403         class TypeData : MemberData
404         {
405                 TypeDefinition type;
406
407                 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
408                         : base (document, parent, null)
409                 {
410                         this.type = type;
411                 }
412                 public override void DoOutput ()
413                 {
414                         if (document == null)
415                                 throw new InvalidOperationException ("Document not set");
416
417                         XmlNode nclass = document.CreateElement ("class", null);
418                         AddAttribute (nclass, "name", type.Name);
419                         string classType = GetClassType (type);
420                         AddAttribute (nclass, "type", classType);
421
422                         if (type.BaseType != null)
423                                 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
424
425                         if (type.IsSealed)
426                                 AddAttribute (nclass, "sealed", "true");
427
428                         if (type.IsAbstract)
429                                 AddAttribute (nclass, "abstract", "true");
430
431                         if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
432                                 AddAttribute (nclass, "serializable", "true");
433
434                         string charSet = GetCharSet (type);
435                         AddAttribute (nclass, "charset", charSet);
436
437                         string layout = GetLayout (type);
438                         if (layout != null)
439                                 AddAttribute (nclass, "layout", layout);
440
441                         if (type.PackingSize >= 0) {
442                                 AddAttribute (nclass, "pack", type.PackingSize.ToString ());
443                         }
444
445                         if (type.ClassSize >= 0) {
446                                 AddAttribute (nclass, "size", type.ClassSize.ToString ());
447                         }
448
449                         parent.AppendChild (nclass);
450
451                         AttributeData.OutputAttributes (document, nclass, type);
452
453                         XmlNode ifaces = null;
454
455                         foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) {
456                                 if (!TypeHelper.IsPublic (iface))
457                                         // we're only interested in public interfaces
458                                         continue;
459
460                                 if (ifaces == null) {
461                                         ifaces = document.CreateElement ("interfaces", null);
462                                         nclass.AppendChild (ifaces);
463                                 }
464
465                                 XmlNode iface_node = document.CreateElement ("interface", null);
466                                 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
467                                 ifaces.AppendChild (iface_node);
468                         }
469
470                         MemberData.OutputGenericParameters (document, nclass, type);
471
472                         ArrayList members = new ArrayList ();
473
474                         FieldDefinition [] fields = GetFields (type);
475                         if (fields.Length > 0) {
476                                 Array.Sort (fields, MemberReferenceComparer.Default);
477                                 FieldData fd = new FieldData (document, nclass, fields);
478                                 members.Add (fd);
479                         }
480
481                         if (type.IsEnum) {
482                                 var value_type = GetEnumValueField (type);
483                                 if (value_type == null)
484                                         throw new NotSupportedException ();
485
486                                 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
487                         }
488
489                         if (!Driver.AbiMode) {
490
491                                 MethodDefinition [] ctors = GetConstructors (type);
492                                 if (ctors.Length > 0) {
493                                         Array.Sort (ctors, MethodDefinitionComparer.Default);
494                                         members.Add (new ConstructorData (document, nclass, ctors));
495                                 }
496
497                                 PropertyDefinition[] properties = GetProperties (type);
498                                 if (properties.Length > 0) {
499                                         Array.Sort (properties, PropertyDefinitionComparer.Default);
500                                         members.Add (new PropertyData (document, nclass, properties));
501                                 }
502
503                                 EventDefinition [] events = GetEvents (type);
504                                 if (events.Length > 0) {
505                                         Array.Sort (events, MemberReferenceComparer.Default);
506                                         members.Add (new EventData (document, nclass, events));
507                                 }
508
509                                 MethodDefinition [] methods = GetMethods (type);
510                                 if (methods.Length > 0) {
511                                         Array.Sort (methods, MethodDefinitionComparer.Default);
512                                         members.Add (new MethodData (document, nclass, methods));
513                                 }
514                         }
515
516                         foreach (MemberData md in members)
517                                 md.DoOutput ();
518
519                         var nested = type.NestedTypes;
520                         //remove non public(familiy) and nested in second degree
521                         for (int i = nested.Count - 1; i >= 0; i--) {
522                                 TypeDefinition t = nested [i];
523                                 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
524                                         (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
525                                         (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
526                                         // public
527                                         if (t.DeclaringType == type)
528                                                 continue; // not nested of nested
529                                 }
530
531                                 nested.RemoveAt (i);
532                         }
533
534                         if (nested.Count > 0) {
535                                 var nestedArray = nested.ToArray ();
536                                 Array.Sort (nestedArray, TypeReferenceComparer.Default);
537
538                                 XmlNode classes = document.CreateElement ("classes", null);
539                                 nclass.AppendChild (classes);
540                                 foreach (TypeDefinition t in nestedArray) {
541                                         TypeData td = new TypeData (document, classes, t);
542                                         td.DoOutput ();
543                                 }
544                         }
545                 }
546
547                 static FieldReference GetEnumValueField (TypeDefinition type)
548                 {
549                         foreach (FieldDefinition field in type.Fields)
550                                 if (field.IsSpecialName && field.Name == "value__")
551                                         return field;
552
553                         return null;
554                 }
555
556                 protected override string GetMemberAttributes (MemberReference member)
557                 {
558                         if (member != type)
559                                 throw new InvalidOperationException ("odd");
560
561                         return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
562                 }
563
564                 public static bool MustDocumentMethod (MethodDefinition method) {
565                         // All other methods
566                         MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
567                         return maskedAccess == MethodAttributes.Public
568                                 || maskedAccess == MethodAttributes.Family
569                                 || maskedAccess == MethodAttributes.FamORAssem;
570                 }
571
572                 static string GetClassType (TypeDefinition t)
573                 {
574                         if (t.IsEnum)
575                                 return "enum";
576
577                         if (t.IsValueType)
578                                 return "struct";
579
580                         if (t.IsInterface)
581                                 return "interface";
582
583                         if (TypeHelper.IsDelegate(t))
584                                 return "delegate";
585
586                         if (t.IsPointer)
587                                 return "pointer";
588
589                         return "class";
590                 }
591
592                 static string GetCharSet (TypeDefinition type)
593                 {
594                         TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
595                         if (maskedStringFormat == TypeAttributes.AnsiClass)
596                                 return CharSet.Ansi.ToString ();
597
598                         if (maskedStringFormat == TypeAttributes.AutoClass)
599                                 return CharSet.Auto.ToString ();
600
601                         if (maskedStringFormat == TypeAttributes.UnicodeClass)
602                                 return CharSet.Unicode.ToString ();
603
604                         return CharSet.None.ToString ();
605                 }
606
607                 static string GetLayout (TypeDefinition type)
608                 {
609                         TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
610                         if (maskedLayout == TypeAttributes.AutoLayout)
611                                 return LayoutKind.Auto.ToString ();
612
613                         if (maskedLayout == TypeAttributes.ExplicitLayout)
614                                 return LayoutKind.Explicit.ToString ();
615
616                         if (maskedLayout == TypeAttributes.SequentialLayout)
617                                 return LayoutKind.Sequential.ToString ();
618
619                         return null;
620                 }
621
622                 FieldDefinition [] GetFields (TypeDefinition type) {
623                         ArrayList list = new ArrayList ();
624
625                         var fields = type.Fields;
626                         foreach (FieldDefinition field in fields) {
627                                 if (field.IsSpecialName)
628                                         continue;
629
630                                 if (Driver.AbiMode && field.IsStatic)
631                                         continue;
632
633                                 // we're only interested in public or protected members
634                                 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
635                                 if (Driver.AbiMode && !field.IsNotSerialized) {
636                                         list.Add (field);
637                                 } else {
638                                         if (maskedVisibility == FieldAttributes.Public
639                                                 || maskedVisibility == FieldAttributes.Family
640                                                 || maskedVisibility == FieldAttributes.FamORAssem) {
641                                                 list.Add (field);
642                                         }
643                                 }
644                         }
645
646                         return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
647                 }
648
649
650                 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
651                         ArrayList list = new ArrayList ();
652
653                         var properties = type.Properties;//type.GetProperties (flags);
654                         foreach (PropertyDefinition property in properties) {
655                                 MethodDefinition getMethod = property.GetMethod;
656                                 MethodDefinition setMethod = property.SetMethod;
657
658                                 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
659                                 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
660
661                                 // if neither the getter or setter should be documented, then
662                                 // skip the property
663                                 if (hasGetter || hasSetter) {
664                                         list.Add (property);
665                                 }
666                         }
667
668                         return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
669                 }
670
671                 private MethodDefinition[] GetMethods (TypeDefinition type)
672                 {
673                         ArrayList list = new ArrayList ();
674
675                         var methods = type.Methods;//type.GetMethods (flags);
676                         foreach (MethodDefinition method in methods) {
677                                 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
678                                         continue;
679
680                                 // we're only interested in public or protected members
681                                 if (!MustDocumentMethod(method))
682                                         continue;
683
684                                 if (IsFinalizer (method)) {
685                                         string name = method.DeclaringType.Name;
686                                         int arity = name.IndexOf ('`');
687                                         if (arity > 0)
688                                                 name = name.Substring (0, arity);
689
690                                         method.Name = "~" + name;
691                                 }
692
693                                 list.Add (method);
694                         }
695
696                         return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
697                 }
698
699                 static bool IsFinalizer (MethodDefinition method)
700                 {
701                         if (method.Name != "Finalize")
702                                 return false;
703
704                         if (!method.IsVirtual)
705                                 return false;
706
707                         if (method.Parameters.Count != 0)
708                                 return false;
709
710                         return true;
711                 }
712
713                 private MethodDefinition [] GetConstructors (TypeDefinition type)
714                 {
715                         ArrayList list = new ArrayList ();
716
717                         var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
718                         foreach (MethodDefinition constructor in ctors) {
719                                 // we're only interested in public or protected members
720                                 if (!MustDocumentMethod(constructor))
721                                         continue;
722
723                                 list.Add (constructor);
724                         }
725
726                         return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
727                 }
728
729                 private EventDefinition[] GetEvents (TypeDefinition type)
730                 {
731                         ArrayList list = new ArrayList ();
732
733                         var events = type.Events;//type.GetEvents (flags);
734                         foreach (EventDefinition eventDef in events) {
735                                 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
736
737                                 if (addMethod == null || !MustDocumentMethod (addMethod))
738                                         continue;
739
740                                 list.Add (eventDef);
741                         }
742
743                         return (EventDefinition []) list.ToArray (typeof (EventDefinition));
744                 }
745         }
746
747         class FieldData : MemberData
748         {
749                 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
750                         : base (document, parent, members)
751                 {
752                 }
753
754                 protected override string GetName (MemberReference memberDefenition)
755                 {
756                         FieldDefinition field = (FieldDefinition) memberDefenition;
757                         return field.Name;
758                 }
759
760                 protected override string GetMemberAttributes (MemberReference memberDefenition)
761                 {
762                         FieldDefinition field = (FieldDefinition) memberDefenition;
763                         return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
764                 }
765
766                 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
767                 {
768                         base.AddExtraData (p, memberDefenition);
769                         FieldDefinition field = (FieldDefinition) memberDefenition;
770                         AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
771
772                         if (field.IsLiteral) {
773                                 object value = field.Constant;//object value = field.GetValue (null);
774                                 string stringValue = null;
775                                 //if (value is Enum) {
776                                 //    // FIXME: when Mono bug #60090 has been
777                                 //    // fixed, we should just be able to use
778                                 //    // Convert.ToString
779                                 //    stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
780                                 //}
781                                 //else {
782                                         stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
783                                 //}
784
785                                 if (stringValue != null)
786                                         AddAttribute (p, "value", stringValue);
787                         }
788                 }
789
790                 public override string ParentTag {
791                         get { return "fields"; }
792                 }
793
794                 public override string Tag {
795                         get { return "field"; }
796                 }
797         }
798
799         class PropertyData : MemberData
800         {
801                 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
802                         : base (document, parent, members)
803                 {
804                 }
805
806                 protected override string GetName (MemberReference memberDefenition)
807                 {
808                         PropertyDefinition prop = (PropertyDefinition) memberDefenition;
809                         return prop.Name;
810                 }
811
812                 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
813                 {
814                         base.AddExtraData (p, memberDefenition);
815                         PropertyDefinition prop = (PropertyDefinition) memberDefenition;
816                         AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
817                         MethodDefinition _get = prop.GetMethod;
818                         MethodDefinition _set = prop.SetMethod;
819                         bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
820                         bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
821                         MethodDefinition [] methods;
822
823                         if (haveGet && haveSet) {
824                                 methods = new MethodDefinition [] { _get, _set };
825                         } else if (haveGet) {
826                                 methods = new MethodDefinition [] { _get };
827                         } else if (haveSet) {
828                                 methods = new MethodDefinition [] { _set };
829                         } else {
830                                 //odd
831                                 return;
832                         }
833
834                         if (haveGet || _set.Parameters.Count > 1) {
835                                 string parms = Parameters.GetSignature (methods [0].Parameters);
836                                 if (!string.IsNullOrEmpty (parms))
837                                         AddAttribute (p, "params", parms);
838                         }
839
840                         MethodData data = new MethodData (document, p, methods);
841                         //data.NoMemberAttributes = true;
842                         data.DoOutput ();
843                 }
844
845                 protected override string GetMemberAttributes (MemberReference memberDefenition)
846                 {
847                         PropertyDefinition prop = (PropertyDefinition) memberDefenition;
848                         return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
849                 }
850
851                 public override string ParentTag {
852                         get { return "properties"; }
853                 }
854
855                 public override string Tag {
856                         get { return "property"; }
857                 }
858         }
859
860         class EventData : MemberData
861         {
862                 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
863                         : base (document, parent, members)
864                 {
865                 }
866
867                 protected override string GetName (MemberReference memberDefenition)
868                 {
869                         EventDefinition evt = (EventDefinition) memberDefenition;
870                         return evt.Name;
871                 }
872
873                 protected override string GetMemberAttributes (MemberReference memberDefenition)
874                 {
875                         EventDefinition evt = (EventDefinition) memberDefenition;
876                         return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
877                 }
878
879                 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
880                 {
881                         base.AddExtraData (p, memberDefenition);
882                         EventDefinition evt = (EventDefinition) memberDefenition;
883                         AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
884                 }
885
886                 public override string ParentTag {
887                         get { return "events"; }
888                 }
889
890                 public override string Tag {
891                         get { return "event"; }
892                 }
893         }
894
895         class MethodData : MemberData
896         {
897                 bool noAtts;
898
899                 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
900                         : base (document, parent, members)
901                 {
902                 }
903
904                 protected override string GetName (MemberReference memberDefenition)
905                 {
906                         MethodDefinition method = (MethodDefinition) memberDefenition;
907                         string name = method.Name;
908                         string parms = Parameters.GetSignature (method.Parameters);
909
910                         return string.Format ("{0}({1})", name, parms);
911                 }
912
913                 protected override string GetMemberAttributes (MemberReference memberDefenition)
914                 {
915                         MethodDefinition method = (MethodDefinition) memberDefenition;
916                         return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
917                 }
918
919                 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
920                 {
921                         base.AddExtraData (p, memberDefenition);
922
923                         if (!(memberDefenition is MethodDefinition))
924                                 return;
925
926                         MethodDefinition mbase = (MethodDefinition) memberDefenition;
927
928                         ParameterData parms = new ParameterData (document, p, mbase.Parameters);
929                         parms.DoOutput ();
930
931                         if (mbase.IsAbstract)
932                                 AddAttribute (p, "abstract", "true");
933                         if (mbase.IsVirtual)
934                                 AddAttribute (p, "virtual", "true");
935                         if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
936                                 AddAttribute (p, "sealed", "true");
937                         if (mbase.IsStatic)
938                                 AddAttribute (p, "static", "true");
939
940                         string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
941                         if (rettype != "System.Void" || !mbase.IsConstructor)
942                                 AddAttribute (p, "returntype", (rettype));
943
944                         AttributeData.OutputAttributes (document, p, mbase.MethodReturnType);
945
946                         MemberData.OutputGenericParameters (document, p, mbase);
947                 }
948
949                 public override bool NoMemberAttributes {
950                         get { return noAtts; }
951                         set { noAtts = value; }
952                 }
953
954                 public override string ParentTag {
955                         get { return "methods"; }
956                 }
957
958                 public override string Tag {
959                         get { return "method"; }
960                 }
961         }
962
963         class ConstructorData : MethodData
964         {
965                 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
966                         : base (document, parent, members)
967                 {
968                 }
969
970                 public override string ParentTag {
971                         get { return "constructors"; }
972                 }
973
974                 public override string Tag {
975                         get { return "constructor"; }
976                 }
977         }
978
979         class ParameterData : BaseData
980         {
981                 private IList<ParameterDefinition> parameters;
982
983                 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
984                         : base (document, parent)
985                 {
986                         this.parameters = parameters;
987                 }
988
989                 public override void DoOutput ()
990                 {
991                         XmlNode parametersNode = document.CreateElement ("parameters");
992                         parent.AppendChild (parametersNode);
993
994                         foreach (ParameterDefinition parameter in parameters) {
995                                 XmlNode paramNode = document.CreateElement ("parameter");
996                                 parametersNode.AppendChild (paramNode);
997                                 AddAttribute (paramNode, "name", parameter.Name);
998                                 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
999                                 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
1000
1001                                 string direction = "in";
1002
1003                                 if (parameter.ParameterType is ByReferenceType)
1004                                         direction = parameter.IsOut ? "out" : "ref";
1005
1006                                 TypeReference t = parameter.ParameterType;
1007                                 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
1008
1009                                 if (parameter.IsOptional) {
1010                                         AddAttribute (paramNode, "optional", "true");
1011                                         if (parameter.HasConstant)
1012                                                 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1013                                 }
1014
1015                                 if (direction != "in")
1016                                         AddAttribute (paramNode, "direction", direction);
1017
1018                                 AttributeData.OutputAttributes (document, paramNode, parameter);
1019                         }
1020                 }
1021         }
1022
1023         class AttributeData : BaseData
1024         {
1025                 IList<CustomAttribute> atts;
1026
1027                 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1028                         : base (doc, parent)
1029                 {
1030                         atts = attributes;
1031                 }
1032
1033                 public override void DoOutput ()
1034                 {
1035                         if (document == null)
1036                                 throw new InvalidOperationException ("Document not set");
1037
1038                         if (atts == null || atts.Count == 0)
1039                                 return;
1040
1041                         XmlNode natts = parent.SelectSingleNode("attributes");
1042                         if (natts == null) {
1043                                 natts = document.CreateElement ("attributes", null);
1044                                 parent.AppendChild (natts);
1045                         }
1046
1047                         foreach (var att in atts.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) {
1048                                 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1049                                 if (SkipAttribute (att))
1050                                         continue;
1051
1052                                 XmlNode node = document.CreateElement ("attribute");
1053                                 AddAttribute (node, "name", attName);
1054
1055                                 XmlNode properties = null;
1056
1057                                 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
1058
1059                                 foreach (string name in attribute_mapping.Keys) {
1060                                         if (name == "TypeId")
1061                                                 continue;
1062
1063                                         if (properties == null) {
1064                                                 properties = node.AppendChild (document.CreateElement ("properties"));
1065                                         }
1066
1067                                         object o = attribute_mapping [name];
1068
1069                                         XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1070                                         AddAttribute (n, "name", name);
1071
1072                                         if (o == null) {
1073                                                 AddAttribute (n, "value", "null");
1074                                                 continue;
1075                                         }
1076                                         
1077                                         string value = o.ToString ();
1078                                         if (attName.EndsWith ("GuidAttribute"))
1079                                                 value = value.ToUpper ();
1080                                         AddAttribute (n, "value", value);
1081                                 }
1082
1083                                 natts.AppendChild (node);
1084                         }
1085                 }
1086
1087                 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1088                 {
1089                         var mapping = new Dictionary<string, object> ();
1090
1091                         PopulateMapping (mapping, attribute);
1092
1093                         var constructor = attribute.Constructor.Resolve ();
1094                         if (constructor == null || !constructor.HasParameters)
1095                                 return mapping;
1096
1097                         PopulateMapping (mapping, constructor, attribute);
1098
1099                         return mapping;
1100                 }
1101
1102                 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1103                 {
1104                         if (!attribute.HasProperties)
1105                                 return;
1106                         
1107                         foreach (var named_argument in attribute.Properties) {
1108                                 var name = named_argument.Name;
1109                                 var arg = named_argument.Argument;
1110
1111                                 if (arg.Value is CustomAttributeArgument)
1112                                         arg = (CustomAttributeArgument) arg.Value;
1113
1114                                 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1115                         }
1116                 }
1117
1118                 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1119                 {
1120                         Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1121
1122                         int? argument = null;
1123
1124                         foreach (Instruction instruction in constructor.Body.Instructions) {
1125                                 switch (instruction.OpCode.Code) {
1126                                 case Code.Ldarg_1:
1127                                         argument = 1;
1128                                         break;
1129                                 case Code.Ldarg_2:
1130                                         argument = 2;
1131                                         break;
1132                                 case Code.Ldarg_3:
1133                                         argument = 3;
1134                                         break;
1135                                 case Code.Ldarg:
1136                                 case Code.Ldarg_S:
1137                                         argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1138                                         break;
1139
1140                                 case Code.Stfld:
1141                                         FieldReference field = (FieldReference) instruction.Operand;
1142                                         if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1143                                                 continue;
1144
1145                                         if (!argument.HasValue)
1146                                                 break;
1147
1148                                         if (!field_mapping.ContainsKey (field))
1149                                                 field_mapping.Add (field, (int) argument - 1);
1150
1151                                         argument = null;
1152                                         break;
1153                                 }
1154                         }
1155
1156                         return field_mapping;
1157                 }
1158
1159                 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1160                 {
1161                         Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1162
1163                         foreach (PropertyDefinition property in type.Properties) {
1164                                 if (property.GetMethod == null)
1165                                         continue;
1166                                 if (!property.GetMethod.HasBody)
1167                                         continue;
1168
1169                                 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1170                                         if (instruction.OpCode.Code != Code.Ldfld)
1171                                                 continue;
1172
1173                                         FieldReference field = (FieldReference) instruction.Operand;
1174                                         if (field.DeclaringType.FullName != type.FullName)
1175                                                 continue;
1176
1177                                         property_mapping.Add (property, field);
1178                                         break;
1179                                 }
1180                         }
1181
1182                         return property_mapping;
1183                 }
1184
1185                 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1186                 {
1187                         if (!constructor.HasBody)
1188                                 return;
1189
1190                         // Custom handling for attributes with arguments which cannot be easily extracted
1191                         var ca = attribute.ConstructorArguments;
1192                         switch (constructor.DeclaringType.FullName) {
1193                         case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1194                                 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1195                                         new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1196                                         new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1197
1198                                 mapping.Add ("Value", dca.Value);
1199                                 return;
1200                         case "System.ComponentModel.BindableAttribute":
1201                                 if (ca.Count != 1)
1202                                         break;
1203
1204                                 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1205                                         mapping.Add ("Bindable", ca[0].Value);
1206                                 } else {
1207                                         throw new NotImplementedException ();
1208                                 }
1209
1210                                 return;
1211                         }
1212
1213                         var field_mapping = CreateArgumentFieldMapping (constructor);
1214                         var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1215
1216                         foreach (var pair in property_mapping) {
1217                                 int argument;
1218                                 if (!field_mapping.TryGetValue (pair.Value, out argument))
1219                                         continue;
1220
1221                                 var ca_arg = ca [argument];
1222                                 if (ca_arg.Value is CustomAttributeArgument)
1223                                         ca_arg = (CustomAttributeArgument) ca_arg.Value;
1224
1225                                 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1226                         }
1227                 }
1228
1229                 static object GetArgumentValue (TypeReference reference, object value)
1230                 {
1231                         var type = reference.Resolve ();
1232                         if (type == null)
1233                                 return value;
1234
1235                         if (type.IsEnum) {
1236                                 if (IsFlaggedEnum (type))
1237                                         return GetFlaggedEnumValue (type, value);
1238
1239                                 return GetEnumValue (type, value);
1240                         }
1241
1242                         return value;
1243                 }
1244
1245                 static bool IsFlaggedEnum (TypeDefinition type)
1246                 {
1247                         if (!type.IsEnum)
1248                                 return false;
1249
1250                         if (!type.HasCustomAttributes)
1251                                 return false;
1252
1253                         foreach (CustomAttribute attribute in type.CustomAttributes)
1254                                 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1255                                         return true;
1256
1257                         return false;
1258                 }
1259
1260                 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1261                 {
1262                         if (value is ulong)
1263                                 return GetFlaggedEnumValue (type, (ulong)value);
1264
1265                         long flags = Convert.ToInt64 (value);
1266                         var signature = new StringBuilder ();
1267
1268                         for (int i = type.Fields.Count - 1; i >= 0; i--) {
1269                                 FieldDefinition field = type.Fields [i];
1270
1271                                 if (!field.HasConstant)
1272                                         continue;
1273
1274                                 long flag = Convert.ToInt64 (field.Constant);
1275
1276                                 if (flag == 0)
1277                                         continue;
1278
1279                                 if ((flags & flag) == flag) {
1280                                         if (signature.Length != 0)
1281                                                 signature.Append (", ");
1282
1283                                         signature.Append (field.Name);
1284                                         flags -= flag;
1285                                 }
1286                         }
1287
1288                         return signature.ToString ();
1289                 }
1290
1291                 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1292                 {
1293                         var signature = new StringBuilder ();
1294
1295                         for (int i = type.Fields.Count - 1; i >= 0; i--) {
1296                                 FieldDefinition field = type.Fields [i];
1297
1298                                 if (!field.HasConstant)
1299                                         continue;
1300
1301                                 ulong flag = Convert.ToUInt64 (field.Constant);
1302
1303                                 if (flag == 0)
1304                                         continue;
1305
1306                                 if ((flags & flag) == flag) {
1307                                         if (signature.Length != 0)
1308                                                 signature.Append (", ");
1309
1310                                         signature.Append (field.Name);
1311                                         flags -= flag;
1312                                 }
1313                         }
1314
1315                         return signature.ToString ();
1316                 }
1317
1318                 static object GetEnumValue (TypeDefinition type, object value)
1319                 {
1320                         foreach (FieldDefinition field in type.Fields) {
1321                                 if (!field.HasConstant)
1322                                         continue;
1323
1324                                 if (Comparer.Default.Compare (field.Constant, value) == 0)
1325                                         return field.Name;
1326                         }
1327
1328                         return value;
1329                 }
1330
1331                 static bool SkipAttribute (CustomAttribute attribute)
1332                 {
1333                         var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1334
1335                         return !TypeHelper.IsPublic (attribute)
1336                                 || type_name.EndsWith ("TODOAttribute");
1337                 }
1338
1339                 public static void OutputAttributes (XmlDocument doc, XmlNode parent, ICustomAttributeProvider provider)
1340                 {
1341                         if (!provider.HasCustomAttributes)
1342                                 return;
1343                         
1344                         AttributeData ad = new AttributeData (doc, parent, provider.CustomAttributes);
1345                         ad.DoOutput ();
1346                 }
1347         }
1348
1349         static class Parameters {
1350
1351                 public static string GetSignature (IList<ParameterDefinition> infos)
1352                 {
1353                         if (infos == null || infos.Count == 0)
1354                                 return string.Empty;
1355
1356                         var signature = new StringBuilder ();
1357                         for (int i = 0; i < infos.Count; i++) {
1358
1359                                 if (i > 0)
1360                                         signature.Append (", ");
1361
1362                                 ParameterDefinition info = infos [i];
1363
1364                                 string modifier;
1365                                 if ((info.Attributes & ParameterAttributes.In) != 0)
1366                                         modifier = "in";
1367                                 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1368                                         modifier = "out";
1369                                 else
1370                                         modifier = string.Empty;
1371
1372                                 if (modifier.Length > 0) {
1373                                         signature.Append (modifier);
1374                                         signature.Append (" ");
1375                                 }
1376
1377                                 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1378                         }
1379
1380                         return signature.ToString ();
1381                 }
1382
1383         }
1384
1385         class TypeReferenceComparer : IComparer<TypeReference>
1386         {
1387                 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1388
1389                 public int Compare (TypeReference a, TypeReference b)
1390                 {
1391                         int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1392                         if (result != 0)
1393                                 return result;
1394
1395                         return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1396                 }
1397         }
1398
1399         class MemberReferenceComparer : IComparer
1400         {
1401                 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1402
1403                 public int Compare (object a, object b)
1404                 {
1405                         MemberReference ma = (MemberReference) a;
1406                         MemberReference mb = (MemberReference) b;
1407                         return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1408                 }
1409         }
1410
1411         class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1412         {
1413                 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1414
1415                 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1416                 {
1417                         int res = String.Compare (ma.Name, mb.Name);
1418                         if (res != 0)
1419                                 return res;
1420
1421                         if (!ma.HasParameters && !mb.HasParameters)
1422                                 return 0;
1423
1424                         if (!ma.HasParameters)
1425                                 return -1;
1426
1427                         if (!mb.HasParameters)
1428                                 return 1;
1429
1430                         return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1431                 }
1432         }
1433
1434         class MethodDefinitionComparer : IComparer
1435         {
1436                 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1437
1438                 public int Compare (object a, object b)
1439                 {
1440                         MethodDefinition ma = (MethodDefinition) a;
1441                         MethodDefinition mb = (MethodDefinition) b;
1442                         int res = String.Compare (ma.Name, mb.Name);
1443                         if (res != 0)
1444                                 return res;
1445
1446                         if (!ma.HasParameters && !mb.HasParameters)
1447                                 return 0;
1448
1449                         if (!ma.HasParameters)
1450                                 return -1;
1451
1452                         if (!mb.HasParameters)
1453                                 return 1;
1454
1455                         res = Compare (ma.Parameters, mb.Parameters);
1456                         if (res != 0)
1457                                 return res;
1458
1459                         // operators can differ by only return type
1460                         return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1461                 }
1462
1463                 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1464                 {
1465                         var res = pia.Count - pib.Count;
1466                         if (res != 0)
1467                                 return res;
1468
1469                         string siga = Parameters.GetSignature (pia);
1470                         string sigb = Parameters.GetSignature (pib);
1471                         return String.Compare (siga, sigb);
1472                 }
1473         }
1474 }
1475