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