* outline.cs: Support for methods with generic parameters.
[mono.git] / mcs / tools / monop / outline.cs
1 //
2 // outline -- support for rendering in monop
3 // Some code stolen from updater.cs in monodoc.
4 //
5 // Authors:
6 //      Ben Maurer (bmaurer@users.sourceforge.net)
7 //
8 // (C) 2004 Ben Maurer
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Reflection;
34 using System.Collections;
35 using System.CodeDom.Compiler;
36 using System.IO;
37 using System.Text;
38         
39 public class Outline {
40         
41         Options options;
42         IndentedTextWriter o;
43         Type t;
44         
45         public Outline (Type t, TextWriter output, Options options)
46         {
47                 this.t = t;
48                 this.o = new IndentedTextWriter (output, "    ");
49                 this.options = options;
50         }
51
52         public void OutlineType ()
53         {
54                 bool first;
55                 
56                 OutlineAttributes ();
57                 o.Write (GetTypeVisibility (t));
58                 
59                 if (t.IsClass && !t.IsSubclassOf (typeof (System.MulticastDelegate))) {
60                         if (t.IsSealed)
61                                 o.Write (t.IsAbstract ? " static" : " sealed");
62                         else if (t.IsAbstract)
63                                 o.Write (" abstract");
64                 }
65                 
66                 o.Write (" ");
67                 o.Write (GetTypeKind (t));
68                 o.Write (" ");
69                 
70                 Type [] interfaces = (Type []) Comparer.Sort (t.GetInterfaces ());
71                 Type parent = t.BaseType;
72
73                 if (t.IsSubclassOf (typeof (System.MulticastDelegate))) {
74                         MethodInfo method;
75
76                         method = t.GetMethod ("Invoke");
77
78                         o.Write (FormatType (method.ReturnType));
79                         o.Write (" ");
80                         o.Write (GetTypeName (t));
81                         o.Write (" (");
82                         OutlineParams (method.GetParameters ());
83                         o.WriteLine (");");
84
85                         return;
86                 }
87                 
88                 o.Write (GetTypeName (t));
89                 if (((parent != null && parent != typeof (object) && parent != typeof (ValueType)) || interfaces.Length != 0) && ! t.IsEnum) {
90                         first = true;
91                         o.Write (" : ");
92                         
93                         if (parent != null && parent != typeof (object) && parent != typeof (ValueType)) {
94                                 o.Write (FormatType (parent));
95                                 first = false;
96                         }
97                         
98                         foreach (Type intf in interfaces) {
99                                 if (!first) o.Write (", ");
100                                 first = false;
101                                 
102                                 o.Write (FormatType (intf));
103                         }
104                 }
105
106                 if (t.IsEnum) {
107                         Type underlyingType = Enum.GetUnderlyingType (t);
108                         if (underlyingType != typeof (int))
109                                 o.Write (" : {0}", FormatType (underlyingType));
110                 }
111                 
112                 o.WriteLine (" {");
113                 o.Indent++;
114
115                 if (t.IsEnum) {
116                         bool is_first = true;
117                         foreach (FieldInfo fi in t.GetFields (BindingFlags.Public | BindingFlags.Static)) {
118                                 
119                                 if (! is_first)
120                                         o.WriteLine (",");
121                                 is_first = false;
122                                 o.Write (fi.Name);
123                         }
124                         o.WriteLine ();
125                         o.Indent--; o.WriteLine ("}");
126                         return;
127                 }
128                 
129                 first = true;
130                 
131                 foreach (ConstructorInfo ci in t.GetConstructors (DefaultFlags)) {
132                         
133                         if (! ShowMember (ci))
134                                 continue;
135                         
136                         if (first)
137                                 o.WriteLine ();
138                         first = false;
139                         
140                         OutlineConstructor (ci);
141                         
142                         o.WriteLine ();
143                 }
144                 
145
146                 first = true;
147                 
148                 foreach (MethodInfo m in Comparer.Sort (t.GetMethods (DefaultFlags))) {
149                         
150                         if (! ShowMember (m))
151                                 continue;               
152                         
153                         if ((m.Attributes & MethodAttributes.SpecialName) != 0)
154                                 continue;
155                         
156                         if (first)
157                                 o.WriteLine ();
158                         first = false;
159                         
160                         OutlineMethod (m);
161                         
162                         o.WriteLine ();
163                 }
164                 
165                 first = true;
166                 
167                 foreach (MethodInfo m in t.GetMethods (DefaultFlags)) {
168                         
169                         if (! ShowMember (m))
170                                 continue;
171                         
172                         if ((m.Attributes & MethodAttributes.SpecialName) == 0)
173                                 continue;
174                         if (!(m.Name.StartsWith ("op_")))
175                                 continue;
176
177                         if (first)
178                                 o.WriteLine ();
179                         first = false;
180                         
181                         OutlineOperator (m);
182                         
183                         o.WriteLine ();
184                 }
185
186                 first = true;
187                 
188                 foreach (PropertyInfo pi in Comparer.Sort (t.GetProperties (DefaultFlags))) {
189                         
190                         if (! ((pi.CanRead  && ShowMember (pi.GetGetMethod (true))) ||
191                                (pi.CanWrite && ShowMember (pi.GetSetMethod (true)))))
192                                 continue;
193                         
194                         if (first)
195                                 o.WriteLine ();
196                         first = false;
197                         
198                         OutlineProperty (pi);
199                         
200                         o.WriteLine ();
201                 }
202                 
203                 first = true;
204
205                 foreach (FieldInfo fi in t.GetFields (DefaultFlags)) {
206                         
207                         if (! ShowMember (fi))
208                                 continue;
209                         
210                         if (first)
211                                 o.WriteLine ();
212                         first = false;
213                         
214                         OutlineField (fi);
215                         
216                         o.WriteLine ();
217                 }
218
219                 first = true;
220                 
221                 foreach (EventInfo ei in Comparer.Sort (t.GetEvents (DefaultFlags))) {
222                         
223                         if (! ShowMember (ei.GetAddMethod ()))
224                                 continue;
225                         
226                         if (first)
227                                 o.WriteLine ();
228                         first = false;
229                         
230                         OutlineEvent (ei);
231                         
232                         o.WriteLine ();
233                 }
234
235                 first = true;
236
237                 foreach (Type ntype in Comparer.Sort (t.GetNestedTypes (DefaultFlags))) {
238                         
239                         if (! ShowMember (ntype))
240                                 continue;
241                         
242                         if (first)
243                                 o.WriteLine ();
244                         first = false;
245                         
246                         new Outline (ntype, o, options).OutlineType ();
247                 }
248                 
249                 o.Indent--; o.WriteLine ("}");
250         }
251         
252         BindingFlags DefaultFlags {
253                 get {
254                         BindingFlags f = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
255                         
256                         if (options.DeclaredOnly)
257                                 f |= BindingFlags.DeclaredOnly;
258                         
259                         return f;
260                 }
261         }
262
263         // FIXME: add other interesting attributes?
264         void OutlineAttributes ()
265         {
266                 if (t.IsSerializable)
267                         o.WriteLine ("[Serializable]");
268
269                 if (t.IsDefined (typeof (System.FlagsAttribute), true))
270                         o.WriteLine ("[Flags]");
271
272                 if (t.IsDefined (typeof (System.ObsoleteAttribute), true))
273                         o.WriteLine ("[Obsolete]");
274         }
275
276         void OutlineEvent (EventInfo ei)
277         {
278                 MethodBase accessor = ei.GetAddMethod ();
279                 
280                 o.Write (GetMethodVisibility (accessor));
281                 o.Write ("event ");
282                 o.Write (FormatType (ei.EventHandlerType));
283                 o.Write (" ");
284                 o.Write (ei.Name);
285                 o.Write (";");
286         }
287         
288         void OutlineConstructor (ConstructorInfo ci)
289         {
290                 o.Write (GetMethodVisibility (ci));
291                 o.Write (RemoveGenericArity (t.Name));
292                 o.Write (" (");
293                 OutlineParams (ci.GetParameters ());
294                 o.Write (");");
295         }
296         
297         
298         void OutlineProperty (PropertyInfo pi)
299         {
300                 ParameterInfo [] idxp = pi.GetIndexParameters ();
301                 MethodBase g = pi.GetGetMethod (true);
302                 MethodBase s = pi.GetSetMethod (true);
303                 MethodBase accessor = g != null ? g : s;
304                 
305                 if (pi.CanRead && pi.CanWrite) {
306
307                         
308                         // Get the more accessible accessor
309                         if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
310                             (s.Attributes & MethodAttributes.MemberAccessMask)) {
311                                 
312                                 if (g.IsPublic) accessor = g;
313                                 else if (s.IsPublic) accessor = s;
314                                 else if (g.IsFamilyOrAssembly) accessor = g;
315                                 else if (s.IsFamilyOrAssembly) accessor = s;
316                                 else if (g.IsAssembly || g.IsFamily) accessor = g;
317                                 else if (s.IsAssembly || s.IsFamily) accessor = s;
318                         }
319                 }
320                 
321                 o.Write (GetMethodVisibility (accessor));
322                 o.Write (GetMethodModifiers  (accessor));
323                 o.Write (FormatType (pi.PropertyType));
324                 o.Write (" ");
325                 
326                 if (idxp.Length == 0)
327                         o.Write (pi.Name);
328                 else {
329                         o.Write ("this [");
330                         OutlineParams (idxp);
331                         o.Write ("]");
332                 }
333                 
334                 o.WriteLine (" {");
335                 o.Indent ++;
336                 
337                 if (g != null && ShowMember (g)) {
338                         if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
339                             (accessor.Attributes & MethodAttributes.MemberAccessMask))
340                                 o.Write (GetMethodVisibility (g));
341                         o.WriteLine ("get;");
342                 }
343                 
344                 if (s != null && ShowMember (s)) {
345                         if ((s.Attributes & MethodAttributes.MemberAccessMask) !=
346                             (accessor.Attributes & MethodAttributes.MemberAccessMask))
347                                 o.Write (GetMethodVisibility (s));
348                         o.WriteLine ("set;");
349                 }
350                 
351                 o.Indent --;
352                 o.Write ("}");
353         }
354         
355         void OutlineMethod (MethodInfo mi)
356         {
357                 o.Write (GetMethodVisibility (mi));
358                 o.Write (GetMethodModifiers  (mi));
359                 o.Write (FormatType (mi.ReturnType));
360                 o.Write (" ");
361                 o.Write (mi.Name);
362 #if NET_2_0
363                 o.Write (FormatGenericParams (mi.GetGenericArguments ()));
364 #endif
365                 o.Write (" (");
366                 OutlineParams (mi.GetParameters ());
367                 o.Write (");");
368         }
369         
370         void OutlineOperator (MethodInfo mi)
371         {
372                 o.Write (GetMethodVisibility (mi));
373                 o.Write (GetMethodModifiers  (mi));
374                 if (mi.Name == "op_Explicit" || mi.Name == "op_Implicit") {
375                         o.Write (mi.Name.Substring (3).ToLower ());
376                         o.Write (" operator ");
377                         o.Write (FormatType (mi.ReturnType));
378                 } else {
379                         o.Write (FormatType (mi.ReturnType));
380                         o.Write (" operator ");
381                         o.Write (OperatorFromName (mi.Name));
382                 }
383                 o.Write (" (");
384                 OutlineParams (mi.GetParameters ());
385                 o.Write (");");
386         }
387         
388         void OutlineParams (ParameterInfo [] pi)
389         {
390                 int i = 0;
391                 foreach (ParameterInfo p in pi) {
392                         if (p.ParameterType.IsByRef) {
393                                 o.Write (p.IsOut ? "out " : "ref ");
394                                 o.Write (FormatType (p.ParameterType.GetElementType ()));
395                         } else if (p.IsDefined (typeof (ParamArrayAttribute), false)) {
396                                 o.Write ("params ");
397                                 o.Write (FormatType (p.ParameterType));
398                         } else {
399                                 o.Write (FormatType (p.ParameterType));
400                         }
401                         
402                         o.Write (" ");
403                         o.Write (p.Name);
404                         if (i + 1 < pi.Length)
405                                 o.Write (", ");
406                         i++;
407                 }
408         }
409
410         void OutlineField (FieldInfo fi)
411         {
412                 if (fi.IsPublic)   o.Write ("public ");
413                 if (fi.IsFamily)   o.Write ("protected ");
414                 if (fi.IsPrivate)  o.Write ("private ");
415                 if (fi.IsAssembly) o.Write ("internal ");
416                 if (fi.IsLiteral)  o.Write ("const ");
417                 if (fi.IsInitOnly) o.Write ("readonly ");
418
419                 o.Write (FormatType (fi.FieldType));
420                 o.Write (" ");
421                 o.Write (fi.Name);
422                 if (fi.IsLiteral)
423                 {
424                         o.Write (" = ");
425                         o.Write (fi.GetValue (this));
426                 }
427                 o.Write (";");
428         }
429
430         static string GetMethodVisibility (MethodBase m)
431         {
432                 // itnerfaces have no modifiers here
433                 if (m.DeclaringType.IsInterface)
434                         return "";
435                 
436                 if (m.IsPublic)   return "public ";
437                 if (m.IsFamily)   return "protected ";
438                 if (m.IsPrivate)  return "private ";
439                 if (m.IsAssembly) return "internal ";
440                         
441                 return null;
442         }
443         
444         static string GetMethodModifiers (MethodBase method)
445         {
446                 if (method.IsStatic)
447                         return "static ";
448         
449                 // all interface methods are "virtual" but we don't say that in c#
450                 if (method.IsVirtual && !method.DeclaringType.IsInterface)
451                         return ((method.Attributes & MethodAttributes.NewSlot) != 0) ?
452                                 "virtual " :
453                                 "override ";
454                 
455                 return null;
456         }
457
458         static string GetTypeKind (Type t)
459         {
460                 if (t.IsEnum)
461                         return "enum";
462                 if (t.IsClass) {
463                         if (t.IsSubclassOf (typeof (System.MulticastDelegate)))
464                                 return "delegate";
465                         else
466                                 return "class";
467                 }
468                 if (t.IsInterface)
469                         return "interface";
470                 if (t.IsValueType)
471                         return "struct";
472                 return "class";
473         }
474         
475         static string GetTypeVisibility (Type t)
476         {
477                 switch (t.Attributes & TypeAttributes.VisibilityMask){
478                 case TypeAttributes.Public:
479                 case TypeAttributes.NestedPublic:
480                         return "public";
481
482                 case TypeAttributes.NestedFamily:
483                 case TypeAttributes.NestedFamANDAssem:
484                 case TypeAttributes.NestedFamORAssem:
485                         return "protected";
486
487                 default:
488                         return "internal";
489                 }
490         }
491
492         string FormatGenericParams (Type [] args)
493         {
494                 StringBuilder sb = new StringBuilder ();
495                 if (args.Length == 0)
496                         return "";
497                 
498                 sb.Append ("<");
499                 for (int i = 0; i < args.Length; i++) {
500                         if (i > 0)
501                                 sb.Append (",");
502                         sb.Append (FormatType (args [i]));
503                 }
504                 sb.Append (">");
505                 return sb.ToString ();
506         }
507         
508         string FormatType (Type t)
509         {
510                 string type = GetFullName (t);
511                 
512                 if (!type.StartsWith ("System.")) {
513                         if (t.Namespace == this.t.Namespace)
514                                 return t.Name;
515                         return type;
516                 }
517                 
518                 if (t.HasElementType) {
519                         Type et = t.GetElementType ();
520                         if (t.IsArray)
521                                 return FormatType (et) + " []";
522                         if (t.IsPointer)
523                                 return FormatType (et) + " *";
524                         if (t.IsByRef)
525                                 return "ref " + FormatType (et);
526                 }
527         
528                 switch (type) {
529                 case "System.Byte": return "byte";
530                 case "System.SByte": return "sbyte";
531                 case "System.Int16": return "short";
532                 case "System.Int32": return "int";
533                 case "System.Int64": return "long";
534                         
535                 case "System.UInt16": return "ushort";
536                 case "System.UInt32": return "uint";
537                 case "System.UInt64": return "ulong";
538                         
539                 case "System.Single":  return "float";
540                 case "System.Double":  return "double";
541                 case "System.Decimal": return "decimal";
542                 case "System.Boolean": return "bool";
543                 case "System.Char":    return "char";
544                 case "System.String":  return "string";
545                         
546                 case "System.Object":  return "object";
547                 case "System.Void":  return "void";
548                 }
549         
550                 if (type.LastIndexOf(".") == 6)
551                         return type.Substring(7);
552                 
553                 return type;
554         }
555
556         public static string RemoveGenericArity (string name)
557         {
558                 int start = 0;
559                 StringBuilder sb = new StringBuilder ();
560                 while (start < name.Length) {
561                         int pos = name.IndexOf ('`', start);
562                         if (pos < 0) {
563                                 sb.Append (name.Substring (start));
564                                 break;
565                         }
566                         sb.Append (name.Substring (start, pos-start));
567
568                         pos++;
569
570                         while ((pos < name.Length) && Char.IsNumber (name [pos]))
571                                 pos++;
572
573                         start = pos;
574                 }
575
576                 return sb.ToString ();
577         }
578
579         string GetTypeName (Type t)
580         {
581                 StringBuilder sb = new StringBuilder ();
582                 GetTypeName (sb, t);
583                 return sb.ToString ();
584         }
585
586         void GetTypeName (StringBuilder sb, Type t)
587         {
588                 sb.Append (RemoveGenericArity (t.Name));
589 #if NET_2_0
590                 sb.Append (FormatGenericParams (t.GetGenericArguments ()));
591 #endif
592         }
593
594         string GetFullName (Type t)
595         {
596                 StringBuilder sb = new StringBuilder ();
597                 GetFullName_recursed (sb, t, false);
598                 return sb.ToString ();
599         }
600
601         void GetFullName_recursed (StringBuilder sb, Type t, bool recursed)
602         {
603 #if NET_2_0
604                 if (t.IsGenericParameter) {
605                         sb.Append (t.Name);
606                         return;
607                 }
608 #endif
609
610                 if (t.DeclaringType != null) {
611                         GetFullName_recursed (sb, t.DeclaringType, true);
612                         sb.Append (".");
613                 }
614
615                 if (!recursed) {
616                         string ns = t.Namespace;
617                         if ((ns != null) && (ns != "")) {
618                                 sb.Append (ns);
619                                 sb.Append (".");
620                         }
621                 }
622
623                 GetTypeName (sb, t);
624         }
625
626         string OperatorFromName (string name)
627         {
628                 switch (name) {
629                 case "op_UnaryPlus": return "+";
630                 case "op_UnaryNegation": return "-";
631                 case "op_LogicalNot": return "!";
632                 case "op_OnesComplement": return "~";
633                 case "op_Increment": return "++";
634                 case "op_Decrement": return "--";
635                 case "op_True": return "true";
636                 case "op_False": return "false";
637                 case "op_Addition": return "+";
638                 case "op_Subtraction": return "-";
639                 case "op_Multiply": return "*";
640                 case "op_Division": return "/";
641                 case "op_Modulus": return "%";
642                 case "op_BitwiseAnd": return "&";
643                 case "op_BitwiseOr": return "|";
644                 case "op_ExclusiveOr": return "^";
645                 case "op_LeftShift": return "<<";
646                 case "op_RightShift": return ">>";
647                 case "op_Equality": return "==";
648                 case "op_Inequality": return "!=";
649                 case "op_GreaterThan": return ">";
650                 case "op_LessThan": return "<";
651                 case "op_GreaterThanOrEqual": return ">=";
652                 case "op_LessThanOrEqual": return "<=";
653                 default: return name;
654                 }
655         }
656         
657         bool ShowMember (MemberInfo mi)
658         {
659                 if (mi.MemberType == MemberTypes.Constructor && ((MethodBase) mi).IsStatic)
660                         return false;
661                 
662                 if (options.ShowPrivate)
663                         return true;
664                 
665                 switch (mi.MemberType) {
666                 case MemberTypes.Constructor:
667                 case MemberTypes.Method:
668                         MethodBase mb = mi as MethodBase;
669                 
670                         if (mb.IsFamily || mb.IsPublic || mb.IsFamilyOrAssembly)
671                                 return true;
672                         
673                         return false;
674                 
675                 
676                 case MemberTypes.Field:
677                         FieldInfo fi = mi as FieldInfo;
678                 
679                         if (fi.IsFamily || fi.IsPublic || fi.IsFamilyOrAssembly)
680                                 return true;
681                         
682                         return false;
683                 
684                 
685                 case MemberTypes.NestedType:
686                 case MemberTypes.TypeInfo:
687                         Type t = mi as Type;
688                 
689                         switch (t.Attributes & TypeAttributes.VisibilityMask){
690                         case TypeAttributes.Public:
691                         case TypeAttributes.NestedPublic:
692                         case TypeAttributes.NestedFamily:
693                         case TypeAttributes.NestedFamORAssem:
694                                 return true;
695                         }
696                         
697                         return false;
698                 }
699                 
700                 // What am I !!!
701                 return true;
702         }
703 }
704
705 public class Comparer : IComparer  {
706         delegate int ComparerFunc (object a, object b);
707         
708         ComparerFunc cmp;
709         
710         Comparer (ComparerFunc f)
711         {
712                 this.cmp = f;
713         }
714         
715         public int Compare (object a, object b)
716         {
717                 return cmp (a, b);
718         }
719
720         static int CompareType (object a, object b)
721         {
722                 Type type1 = (Type) a;
723                 Type type2 = (Type) b;
724
725                 if (type1.IsSubclassOf (typeof (System.MulticastDelegate)) != type2.IsSubclassOf (typeof (System.MulticastDelegate)))
726                                 return (type1.IsSubclassOf (typeof (System.MulticastDelegate)))? -1:1;
727                 return string.Compare (type1.Name, type2.Name);
728                         
729         }
730
731         static Comparer TypeComparer = new Comparer (new ComparerFunc (CompareType));
732
733         static Type [] Sort (Type [] types)
734         {
735                 Array.Sort (types, TypeComparer);
736                 return types;
737         }
738         
739         static int CompareMemberInfo (object a, object b)
740         {
741                 return string.Compare (((MemberInfo) a).Name, ((MemberInfo) b).Name);
742         }
743         
744         static Comparer MemberInfoComparer = new Comparer (new ComparerFunc (CompareMemberInfo));
745         
746         public static MemberInfo [] Sort (MemberInfo [] inf)
747         {
748                 Array.Sort (inf, MemberInfoComparer);
749                 return inf;
750         }
751         
752         static int CompareMethodBase (object a, object b)
753         {
754                 MethodBase aa = (MethodBase) a, bb = (MethodBase) b;
755                 
756                 if (aa.IsStatic == bb.IsStatic)
757                         return CompareMemberInfo (a, b);
758                 
759                 if (aa.IsStatic)
760                         return -1;
761                 
762                 return 1;
763         }
764         
765         static Comparer MethodBaseComparer = new Comparer (new ComparerFunc (CompareMethodBase));
766         
767         public static MethodBase [] Sort (MethodBase [] inf)
768         {
769                 Array.Sort (inf, MethodBaseComparer);
770                 return inf;
771         }
772         
773         static int ComparePropertyInfo (object a, object b)
774         {
775                 PropertyInfo aa = (PropertyInfo) a, bb = (PropertyInfo) b;
776                 
777                 bool astatic = (aa.CanRead ? aa.GetGetMethod (true) : aa.GetSetMethod (true)).IsStatic;
778                 bool bstatic = (bb.CanRead ? bb.GetGetMethod (true) : bb.GetSetMethod (true)).IsStatic;
779                 
780                 if (astatic == bstatic)
781                         return CompareMemberInfo (a, b);
782                 
783                 if (astatic)
784                         return -1;
785                 
786                 return 1;
787         }
788         
789         static Comparer PropertyInfoComparer = new Comparer (new ComparerFunc (ComparePropertyInfo));
790         
791         public static PropertyInfo [] Sort (PropertyInfo [] inf)
792         {
793                 Array.Sort (inf, PropertyInfoComparer);
794                 return inf;
795         }
796         
797         static int CompareEventInfo (object a, object b)
798         {
799                 EventInfo aa = (EventInfo) a, bb = (EventInfo) b;
800                 
801                 bool astatic = aa.GetAddMethod (true).IsStatic;
802                 bool bstatic = bb.GetAddMethod (true).IsStatic;
803                 
804                 if (astatic == bstatic)
805                         return CompareMemberInfo (a, b);
806                 
807                 if (astatic)
808                         return -1;
809                 
810                 return 1;
811         }
812         
813         static Comparer EventInfoComparer = new Comparer (new ComparerFunc (CompareEventInfo));
814         
815         public static EventInfo [] Sort (EventInfo [] inf)
816         {
817                 Array.Sort (inf, EventInfoComparer);
818                 return inf;
819         }
820 }