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