* mono-api-info.cs: ignore non-public attributes
[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 // (C) 2003 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.Reflection;
13 using System.Text;
14 using System.Xml;
15
16 namespace Mono.AssemblyInfo
17 {
18         class Driver
19         {
20                 static int Main (string [] args)
21                 {
22                         if (args.Length == 0)
23                                 return 1;
24
25                         AssemblyCollection acoll = new AssemblyCollection ();
26                         
27                         foreach (string fullName in args) {
28                                 acoll.Add (fullName);
29                         }
30
31                         XmlDocument doc = new XmlDocument ();
32                         acoll.Document = doc;
33                         acoll.DoOutput ();
34
35                         XmlTextWriter writer = new XmlTextWriter (Console.Out);
36                         writer.Formatting = Formatting.Indented;
37                         XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
38                         doc.InsertBefore (decl, doc.DocumentElement);
39                         doc.WriteTo (writer);
40                         return 0;
41                 }
42         }
43
44         class AssemblyCollection
45         {
46                 XmlDocument document;
47                 ArrayList assemblies;
48
49                 public AssemblyCollection ()
50                 {
51                         assemblies = new ArrayList ();
52                 }
53
54                 public bool Add (string name)
55                 {
56                         Assembly ass = LoadAssembly (name);
57                         if (ass == null)
58                                 return false;
59
60                         assemblies.Add (ass);
61                         return true;
62                 }
63
64                 public void DoOutput ()
65                 {
66                         if (document == null)
67                                 throw new InvalidOperationException ("Document not set");
68
69                         XmlNode nassemblies = document.CreateElement ("assemblies", null);
70                         document.AppendChild (nassemblies);
71                         foreach (Assembly a in assemblies) {
72                                 AssemblyData data = new AssemblyData (document, nassemblies, a);
73                                 data.DoOutput ();
74                         }
75                 }
76
77                 public XmlDocument Document {
78                         set { document = value; }
79                 }
80                 
81                 static Assembly LoadAssembly (string aname)
82                 {
83                         Assembly ass = null;
84                         try {
85                                 string name = aname;
86                                 if (!name.EndsWith (".dll"))
87                                         name += ".dll";
88                                 ass = Assembly.LoadFrom (name);
89                                 return ass;
90                         } catch { }
91
92                         try {
93                                 ass = Assembly.LoadWithPartialName (aname);
94                                 return ass;
95                         } catch { }
96
97                         return null;
98                 }
99         }
100
101         abstract class BaseData
102         {
103                 protected XmlDocument document;
104                 protected XmlNode parent;
105
106                 protected BaseData (XmlDocument doc, XmlNode parent)
107                 {
108                         this.document = doc;
109                         this.parent = parent;
110                 }
111
112                 public abstract void DoOutput ();
113
114                 protected void AddAttribute (XmlNode node, string name, string value)
115                 {
116                         XmlAttribute attr = document.CreateAttribute (name);
117                         attr.Value = value;
118                         node.Attributes.Append (attr);
119                 }
120         }
121
122         class AssemblyData : BaseData
123         {
124                 Assembly ass;
125                 
126                 public AssemblyData (XmlDocument document, XmlNode parent, Assembly ass)
127                         : base (document, parent)
128                 {
129                         this.ass = ass;
130                 }
131
132                 public override void DoOutput ()
133                 {
134                         if (document == null)
135                                 throw new InvalidOperationException ("Document not set");
136
137                         XmlNode nassembly = document.CreateElement ("assembly", null);
138                         AssemblyName aname = ass.GetName ();
139                         AddAttribute (nassembly, "name", aname.Name);
140                         AddAttribute (nassembly, "version", aname.Version.ToString ());
141                         parent.AppendChild (nassembly);
142                         AttributeData.OutputAttributes (document, nassembly, ass.GetCustomAttributes (false));
143                         Type [] types = ass.GetTypes ();
144                         if (types == null || types.Length == 0)
145                                 return;
146
147                         Array.Sort (types, TypeComparer.Default);
148
149                         XmlNode nss = document.CreateElement ("namespaces", null);
150                         nassembly.AppendChild (nss);
151
152                         string currentNS = "$%&$&";
153                         XmlNode ns = null;
154                         XmlNode classes = null;
155                         foreach (Type t in types) {
156                                 if (t.Namespace == null || t.Namespace == "")
157                                         continue;
158
159                                 if (t.IsNotPublic)
160                                         continue;
161
162                                 if (t.IsNestedPublic || t.IsNestedAssembly || t.IsNestedFamANDAssem ||
163                                         t.IsNestedFamORAssem || t.IsNestedPrivate)
164                                         continue;
165
166                                 if (t.DeclaringType != null)
167                                         continue; // enforce !nested
168                                 
169                                 if (t.Namespace != currentNS) {
170                                         currentNS = t.Namespace;
171                                         ns = document.CreateElement ("namespace", null);
172                                         AddAttribute (ns, "name", currentNS);
173                                         nss.AppendChild (ns);
174                                         classes = document.CreateElement ("classes", null);
175                                         ns.AppendChild (classes);
176                                 }
177                                 
178                                 TypeData bd = new TypeData (document, classes, t);
179                                 bd.DoOutput ();
180                         }
181                 }
182         }
183
184         abstract class MemberData : BaseData
185         {
186                 MemberInfo [] members;
187
188                 public MemberData (XmlDocument document, XmlNode parent, MemberInfo [] members)
189                         : base (document, parent)
190                 {
191                         this.members = members;
192                 }
193
194                 public override void DoOutput ()
195                 {
196                         XmlNode mclass = document.CreateElement (ParentTag, null);
197                         parent.AppendChild (mclass);
198
199                         foreach (MemberInfo member in members) {
200                                 XmlNode mnode = document.CreateElement (Tag, null);
201                                 mclass.AppendChild (mnode);
202                                 AddAttribute (mnode, "name", GetName (member));
203                                 if (!NoMemberAttributes)
204                                         AddAttribute (mnode, "attrib", GetMemberAttributes (member));
205
206                                 AttributeData.OutputAttributes (document, mnode,
207                                                                 member.GetCustomAttributes (false));
208
209                                 AddExtraData (mnode, member);
210                         }
211                 }
212
213                 protected virtual void AddExtraData (XmlNode p, MemberInfo member)
214                 {
215                 }
216
217                 protected virtual string GetName (MemberInfo member)
218                 {
219                         return "NoNAME";
220                 }
221
222                 protected virtual string GetMemberAttributes (MemberInfo member)
223                 {
224                         return null;
225                 }
226
227                 public virtual bool NoMemberAttributes {
228                         get { return false; }
229                         set {}
230                 }
231
232                 public virtual string ParentTag {
233                         get { return "NoPARENTTAG"; }
234                 }
235                 
236                 public virtual string Tag {
237                         get { return "NoTAG"; }
238                 }
239         }
240
241         class TypeData : MemberData
242         {
243                 Type type;
244                 const BindingFlags flags = BindingFlags.Public | BindingFlags.Static |
245                                                 BindingFlags.Instance | BindingFlags.DeclaredOnly | 
246                                                 BindingFlags.NonPublic;
247                 
248                 public TypeData (XmlDocument document, XmlNode parent, Type type)
249                         : base (document, parent, null)
250                 {
251                         this.type = type;
252                 }
253
254                 public override void DoOutput ()
255                 {
256                         if (document == null)
257                                 throw new InvalidOperationException ("Document not set");
258
259                         XmlNode nclass = document.CreateElement ("class", null);
260                         AddAttribute (nclass, "name", type.Name);
261                         string classType = GetClassType (type);
262                         AddAttribute (nclass, "type", classType);
263                         if (type.BaseType != null)
264                                 AddAttribute (nclass, "base", type.BaseType.FullName);
265
266                         if (type.IsSealed)
267                                 AddAttribute (nclass, "sealed", "true");
268
269                         parent.AppendChild (nclass);
270                         
271                         AttributeData.OutputAttributes (document, nclass, type.GetCustomAttributes (false));
272
273                         Type [] interfaces = type.GetInterfaces ();
274                         if (interfaces != null && interfaces.Length > 0) {
275                                 XmlNode ifaces = document.CreateElement ("interfaces", null);
276                                 nclass.AppendChild (ifaces);
277                                 foreach (Type t in interfaces) {
278                                         if (!t.IsPublic) {
279                                                 // we're only interested in public interfaces
280                                                 continue;
281                                         }
282                                         XmlNode iface = document.CreateElement ("interface", null);
283                                         AddAttribute (iface, "name", t.FullName);
284                                         ifaces.AppendChild (iface);
285                                 }
286                         }
287
288                         ArrayList members = new ArrayList ();
289
290                         FieldInfo[] fields = GetFields (type);
291                         if (fields.Length > 0) {
292                                 Array.Sort (fields, MemberInfoComparer.Default);
293                                 FieldData fd = new FieldData (document, nclass, fields);
294                                 // Special case for enum fields
295                                 if (classType == "enum") {
296                                         string etype = fields [0].GetType ().FullName;
297                                         AddAttribute (nclass, "enumtype", etype);
298                                 }
299                                 members.Add (fd);
300                         }
301
302                         ConstructorInfo [] ctors = GetConstructors (type);
303                         if (ctors.Length > 0) {
304                                 Array.Sort (ctors, MemberInfoComparer.Default);
305                                 members.Add (new ConstructorData (document, nclass, ctors));
306                         }
307
308                         PropertyInfo[] properties = GetProperties (type);
309                         if (properties.Length > 0) {
310                                 Array.Sort (properties, MemberInfoComparer.Default);
311                                 members.Add (new PropertyData (document, nclass, properties));
312                         }
313
314                         EventInfo [] events = GetEvents (type);
315                         if (events.Length > 0) {
316                                 Array.Sort (events, MemberInfoComparer.Default);
317                                 members.Add (new EventData (document, nclass, events));
318                         }
319
320                         MethodInfo [] methods = GetMethods (type);
321                         if (methods.Length > 0) {
322                                 Array.Sort (methods, MemberInfoComparer.Default);
323                                 members.Add (new MethodData (document, nclass, methods));
324                         }
325
326                         foreach (MemberData md in members)
327                                 md.DoOutput ();
328
329                         Type [] nested = type.GetNestedTypes ();
330                         if (nested != null && nested.Length > 0) {
331                                 XmlNode classes = document.CreateElement ("classes", null);
332                                 nclass.AppendChild (classes);
333                                 foreach (Type t in nested) {
334                                         TypeData td = new TypeData (document, classes, t);
335                                         td.DoOutput ();
336                                 }
337                         }
338                 }
339
340                 protected override string GetMemberAttributes (MemberInfo member)
341                 {
342                         if (member != type)
343                                 throw new InvalidOperationException ("odd");
344                                 
345                         return ((int) type.Attributes).ToString ();
346                 }
347
348                 public static bool MustDocumentMethod(MethodBase method)
349                 {
350                         // All other methods
351                         return (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly);
352                 }
353
354                 static string GetClassType (Type t)
355                 {
356                         if (t.IsEnum)
357                                 return "enum";
358
359                         if (t.IsValueType)
360                                 return "struct";
361
362                         if (t.IsInterface)
363                                 return "interface";
364
365                         if (typeof (Delegate).IsAssignableFrom (t))
366                                 return "delegate";
367
368                         return "class";
369                 }
370
371                 private FieldInfo[] GetFields (Type type)
372                 {
373                         ArrayList list = new ArrayList ();
374
375                         FieldInfo[] fields = type.GetFields (flags);
376                         foreach (FieldInfo field in fields) {
377                                 if (field.IsSpecialName)
378                                         continue;
379
380                                 // we're only interested in public or protected members
381                                 if (!field.IsPublic && !field.IsFamily && !field.IsFamilyOrAssembly)
382                                         continue;
383
384                                 list.Add (field);
385                         }
386
387                         return (FieldInfo[]) list.ToArray (typeof (FieldInfo));
388                 }
389
390                 private PropertyInfo[] GetProperties (Type type)
391                 {
392                         ArrayList list = new ArrayList ();
393
394                         PropertyInfo[] properties = type.GetProperties (flags);
395                         foreach (PropertyInfo property in properties) {
396                                 MethodInfo getMethod = null;
397                                 MethodInfo setMethod = null;
398
399                                 if (property.CanRead) {
400                                         try { getMethod = property.GetGetMethod (true); }
401                                         catch (System.Security.SecurityException) { }
402                                 }
403                                 if (property.CanWrite) {
404                                         try { setMethod = property.GetSetMethod (true); }
405                                         catch (System.Security.SecurityException) { }
406                                 }
407
408                                 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
409                                 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
410
411                                 // if neither the getter or setter should be documented, then
412                                 // skip the property
413                                 if (!hasGetter && !hasSetter) {
414                                         continue;
415                                 }
416
417                                 list.Add (property);
418                         }
419
420                         return (PropertyInfo[]) list.ToArray (typeof (PropertyInfo));
421                 }
422
423                 private MethodInfo[] GetMethods (Type type)
424                 {
425                         ArrayList list = new ArrayList ();
426
427                         MethodInfo[] methods = type.GetMethods (flags);
428                         foreach (MethodInfo method in methods) {
429                                 if (method.IsSpecialName)
430                                         continue;
431
432                                 // we're only interested in public or protected members
433                                 if (!MustDocumentMethod(method))
434                                         continue;
435
436                                 list.Add (method);
437                         }
438
439                         return (MethodInfo[]) list.ToArray (typeof (MethodInfo));
440                 }
441
442                 private ConstructorInfo[] GetConstructors (Type type)
443                 {
444                         ArrayList list = new ArrayList ();
445
446                         ConstructorInfo[] ctors = type.GetConstructors (flags);
447                         foreach (ConstructorInfo constructor in ctors) {
448                                 // we're only interested in public or protected members
449                                 if (!constructor.IsPublic && !constructor.IsFamily && !constructor.IsFamilyOrAssembly)
450                                         continue;
451
452                                 list.Add (constructor);
453                         }
454
455                         return (ConstructorInfo[]) list.ToArray (typeof (ConstructorInfo));
456                 }
457
458                 private EventInfo[] GetEvents (Type type)
459                 {
460                         ArrayList list = new ArrayList ();
461
462                         EventInfo[] events = type.GetEvents (flags);
463                         foreach (EventInfo eventInfo in events) {
464                                 MethodInfo addMethod = eventInfo.GetAddMethod (true);
465
466                                 if (addMethod == null || !MustDocumentMethod (addMethod))
467                                         continue;
468
469                                 list.Add (eventInfo);
470                         }
471
472                         return (EventInfo[]) list.ToArray (typeof (EventInfo));
473                 }
474         }
475
476         class FieldData : MemberData
477         {
478                 public FieldData (XmlDocument document, XmlNode parent, FieldInfo [] members)
479                         : base (document, parent, members)
480                 {
481                 }
482
483                 protected override string GetName (MemberInfo member)
484                 {
485                         FieldInfo field = (FieldInfo) member;
486                         return field.Name;
487                 }
488
489                 protected override string GetMemberAttributes (MemberInfo member)
490                 {
491                         FieldInfo field = (FieldInfo) member;
492                         return ((int) field.Attributes).ToString ();
493                 }
494
495                 protected override void AddExtraData (XmlNode p, MemberInfo member)
496                 {
497                         base.AddExtraData (p, member);
498                         FieldInfo field = (FieldInfo) member;
499                         AddAttribute (p, "fieldtype", field.FieldType.FullName);
500                 }
501
502                 public override string ParentTag {
503                         get { return "fields"; }
504                 }
505
506                 public override string Tag {
507                         get { return "field"; }
508                 }
509         }
510
511         class PropertyData : MemberData
512         {
513                 public PropertyData (XmlDocument document, XmlNode parent, PropertyInfo [] members)
514                         : base (document, parent, members)
515                 {
516                 }
517
518                 protected override string GetName (MemberInfo member)
519                 {
520                         PropertyInfo prop = (PropertyInfo) member;
521                         return prop.Name;
522                 }
523
524                 protected override void AddExtraData (XmlNode p, MemberInfo member)
525                 {
526                         base.AddExtraData (p, member);
527                         PropertyInfo prop = (PropertyInfo) member;
528                         AddAttribute (p, "ptype", prop.PropertyType.FullName);
529                         MethodInfo _get = prop.GetGetMethod (true);
530                         MethodInfo _set = prop.GetSetMethod (true);
531                         bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
532                         bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
533                         MethodInfo [] methods;
534
535                         if (haveGet && haveSet) {
536                                 methods = new MethodInfo [] {_get, _set};
537                         } else if (haveGet) {
538                                 methods = new MethodInfo [] {_get};
539                         } else if (haveSet) {
540                                 methods = new MethodInfo [] {_set};
541                         } else {
542                                 //odd
543                                 return;
544                         }
545
546                         string parms = Parameters.GetSignature (methods [0].GetParameters ());
547                         AddAttribute (p, "params", parms);
548
549                         MethodData data = new MethodData (document, p, methods);
550                         data.NoMemberAttributes = true;
551                         data.DoOutput ();
552                 }
553
554                 protected override string GetMemberAttributes (MemberInfo member)
555                 {
556                         PropertyInfo prop = (PropertyInfo) member;
557                         return ((int) prop.Attributes).ToString ();
558                 }
559
560                 public override string ParentTag {
561                         get { return "properties"; }
562                 }
563
564                 public override string Tag {
565                         get { return "property"; }
566                 }
567         }
568
569         class EventData : MemberData
570         {
571                 public EventData (XmlDocument document, XmlNode parent, EventInfo [] members)
572                         : base (document, parent, members)
573                 {
574                 }
575
576                 protected override string GetName (MemberInfo member)
577                 {
578                         EventInfo evt = (EventInfo) member;
579                         return evt.Name;
580                 }
581
582                 protected override string GetMemberAttributes (MemberInfo member)
583                 {
584                         EventInfo evt = (EventInfo) member;
585                         return ((int) evt.Attributes).ToString ();
586                 }
587
588                 protected override void AddExtraData (XmlNode p, MemberInfo member)
589                 {
590                         base.AddExtraData (p, member);
591                         EventInfo evt = (EventInfo) member;
592                         AddAttribute (p, "eventtype", evt.EventHandlerType.FullName);
593                 }
594
595                 public override string ParentTag {
596                         get { return "events"; }
597                 }
598
599                 public override string Tag {
600                         get { return "event"; }
601                 }
602         }
603
604         class MethodData : MemberData
605         {
606                 bool noAtts;
607
608                 public MethodData (XmlDocument document, XmlNode parent, MethodBase [] members)
609                         : base (document, parent, members)
610                 {
611                 }
612
613                 protected override string GetName (MemberInfo member)
614                 {
615                         MethodBase method = (MethodBase) member;
616                         string name = method.Name;
617                         string parms = Parameters.GetSignature (method.GetParameters ());
618                         return String.Format ("{0}({1})", name, parms);
619                 }
620
621                 protected override string GetMemberAttributes (MemberInfo member)
622                 {
623                         MethodBase method = (MethodBase) member;
624                         return ((int) method.Attributes).ToString ();
625                 }
626
627                 protected override void AddExtraData (XmlNode p, MemberInfo member)
628                 {
629                         base.AddExtraData (p, member);
630                         if (!(member is MethodInfo))
631                                 return;
632                                 
633                         MethodInfo method = (MethodInfo) member;
634                         AddAttribute (p, "returntype", method.ReturnType.FullName);
635                 }
636
637                 public override bool NoMemberAttributes {
638                         get { return noAtts; }
639                         set { noAtts = value; }
640                 }
641                 
642                 public override string ParentTag {
643                         get { return "methods"; }
644                 }
645
646                 public override string Tag {
647                         get { return "method"; }
648                 }
649         }
650
651         class ConstructorData : MethodData
652         {
653                 public ConstructorData (XmlDocument document, XmlNode parent, ConstructorInfo [] members)
654                         : base (document, parent, members)
655                 {
656                 }
657
658                 public override string ParentTag {
659                         get { return "constructors"; }
660                 }
661
662                 public override string Tag {
663                         get { return "constructor"; }
664                 }
665         }
666
667         class AttributeData : BaseData
668         {
669                 object [] atts;
670
671                 AttributeData (XmlDocument doc, XmlNode parent, object [] attributes)
672                         : base (doc, parent)
673                 {
674                         this.atts = attributes;
675                 }
676
677                 public override void DoOutput ()
678                 {
679                         if (document == null)
680                                 throw new InvalidOperationException ("Document not set");
681
682                         if (atts == null || atts.Length == 0)
683                                 return;
684
685                         XmlNode natts = document.CreateElement ("attributes", null);
686                         parent.AppendChild (natts);
687
688                         ArrayList typeList = new ArrayList (atts.Length);
689                         string comment = null;
690                         for (int i = atts.Length - 1; i >= 0; i--) {
691                                 Type attType = atts [i].GetType ();
692                                 if (!MustDocumentAttribute (attType))
693                                         continue;
694                                 typeList.Add (attType);
695                                 if (attType.Name.EndsWith ("TODOAttribute")) {
696                                         PropertyInfo prop = attType.GetProperty ("Comment");
697                                         if (prop != null)
698                                                 comment = (string) prop.GetValue (atts [i], null);
699                                 }
700                         }
701
702                         Type[] types = (Type[]) typeList.ToArray (typeof (Type));
703                         Array.Sort (types, TypeComparer.Default);
704                         foreach (Type t in types) {
705                                 XmlNode node = document.CreateElement ("attribute");
706                                 AddAttribute (node, "name", t.FullName);
707                                 if (comment != null && t.Name.EndsWith ("TODOAttribute"))
708                                         AddAttribute (node, "comment", comment);
709
710                                 natts.AppendChild (node);
711                         }
712                 }
713
714                 public static void OutputAttributes (XmlDocument doc, XmlNode parent, object [] attributes)
715                 {
716                         AttributeData ad = new AttributeData (doc, parent, attributes);
717                         ad.DoOutput ();
718                 }
719
720                 private static bool MustDocumentAttribute (Type attributeType)
721                 {
722                         // only document public attributes
723                         return attributeType.IsPublic;
724                 }
725         }
726
727         class Parameters
728         {
729                 private Parameters () {}
730
731                 public static string GetSignature (ParameterInfo [] infos)
732                 {
733                         if (infos == null || infos.Length == 0)
734                                 return "";
735
736                         StringBuilder sb = new StringBuilder ();
737                         foreach (ParameterInfo info in infos) {
738                                 string modifier;
739                                 if (info.IsIn)
740                                         modifier = "in ";
741                                 else if (info.IsRetval)
742                                         modifier = "ref ";
743                                 else if (info.IsOut)
744                                         modifier = "out ";
745                                 else
746                                         modifier = "";
747
748                                 //TODO: parameter attributes
749                                 
750                                 string type_name = info.ParameterType.ToString ();
751                                 sb.AppendFormat ("{0}{1}, ", modifier, type_name);
752                         }
753
754                         sb.Length -= 2; // remove ", "
755                         return sb.ToString ();
756                 }
757
758         }
759         
760         class TypeComparer : IComparer
761         {
762                 public static TypeComparer Default = new TypeComparer ();
763
764                 public int Compare (object a, object b)
765                 {
766                         Type ta = (Type) a;
767                         Type tb = (Type) b;
768                         int result = String.Compare (ta.Namespace, tb.Namespace);
769                         if (result != 0)
770                                 return result;
771
772                         return String.Compare (ta.Name, tb.Name);
773                 }
774         }
775
776         class MemberInfoComparer : IComparer
777         {
778                 public static MemberInfoComparer Default = new MemberInfoComparer ();
779
780                 public int Compare (object a, object b)
781                 {
782                         MemberInfo ma = (MemberInfo) a;
783                         MemberInfo mb = (MemberInfo) b;
784                         return String.Compare (ma.Name, mb.Name);
785                 }
786         }
787
788         class MethodBaseComparer : IComparer
789         {
790                 public static MethodBaseComparer Default = new MethodBaseComparer ();
791
792                 public int Compare (object a, object b)
793                 {
794                         MethodBase ma = (MethodBase) a;
795                         MethodBase mb = (MethodBase) b;
796                         int res = String.Compare (ma.Name, mb.Name);
797                         if (res != 0)
798                                 return res;
799
800                         ParameterInfo [] pia = ma.GetParameters ();
801                         ParameterInfo [] pib = mb.GetParameters ();
802                         if (pia.Length != pib.Length)
803                                 return pia.Length - pib.Length;
804
805                         string siga = Parameters.GetSignature (pia);
806                         string sigb = Parameters.GetSignature (pib);
807                         return String.Compare (siga, sigb);
808                 }
809         }
810 }
811