Merge pull request #5486 from kumpera/fix_array_dispatch_perf
[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.Collections;
34 using System.CodeDom.Compiler;
35 using System.IO;
36 using System.Text;
37 #if STATIC
38 using IKVM.Reflection;
39 using Type=IKVM.Reflection.Type;
40 #else
41 using System.Reflection;
42 #endif
43
44 namespace Mono.CSharp {
45
46 public static class TypeExtensions {
47         public static string GetNamespace (this Type t)
48         {
49                 // IKVM crashes here with a null ref sometimes
50                 try {
51                         return t.Namespace;
52                 } catch {
53                         return null;
54                 }
55         }
56 }
57         
58 public class Outline {
59         bool declared_only;
60         bool show_private;
61         bool filter_obsolete;
62         
63         IndentedTextWriter o;
64         Type t;
65         Type type_multicast_delegate, type_object, type_value_type, type_int, type_flags_attribute, type_obsolete_attribute, type_param_array_attribute;
66         
67 #if STATIC
68         Universe universe;
69         Assembly mscorlib;
70
71         public Outline (System.Type t, TextWriter output, bool declared_only, bool show_private, bool filter_obsolete)
72         {
73                 throw new NotImplementedException ();
74         }
75         
76         public Outline (Universe universe, Assembly mscorlib, Type t, TextWriter output, bool declared_only, bool show_private, bool filter_obsolete)
77         {
78                 if (universe == null)
79                         throw new ArgumentNullException ("universe");
80                 if (mscorlib == null)
81                         throw new ArgumentNullException ("mscorlib");
82                 this.universe = universe;
83                 this.mscorlib = mscorlib;
84                 this.t = t;
85                 this.o = new IndentedTextWriter (output, "\t");
86                 this.declared_only = declared_only;
87                 this.show_private = show_private;
88                 this.filter_obsolete = filter_obsolete;
89
90                 type_multicast_delegate = mscorlib.GetType("System.MulticastDelegate");
91                 type_object = mscorlib.GetType ("System.Object");
92                 type_value_type = mscorlib.GetType ("System.ValueType");
93                 type_int = mscorlib.GetType ("System.Int32");
94                 type_flags_attribute = mscorlib.GetType ("System.FlagsAttribute");
95                 type_obsolete_attribute = mscorlib.GetType ("System.ObsoleteAttribute");
96                 type_param_array_attribute = mscorlib.GetType ("System.ParamArrayAttribute");
97         }
98 #else
99         public Outline (Type t, TextWriter output, bool declared_only, bool show_private, bool filter_obsolete)
100         {
101                 this.t = t;
102                 this.o = new IndentedTextWriter (output, "\t");
103                 this.declared_only = declared_only;
104                 this.show_private = show_private;
105                 this.filter_obsolete = filter_obsolete;
106
107                 type_multicast_delegate = typeof (System.MulticastDelegate);
108                 type_object = typeof (object);
109                 type_value_type = typeof (ValueType);
110                 type_int = typeof (int);
111                 type_flags_attribute = typeof (FlagsAttribute);
112                 type_obsolete_attribute = typeof (ObsoleteAttribute);
113                 type_param_array_attribute = typeof (ParamArrayAttribute);
114         }
115 #endif
116
117         public void OutlineType ()
118         {
119                 bool first;
120                 
121                 OutlineAttributes ();
122                 o.Write (GetTypeVisibility (t));
123                 
124                 if (t.IsClass && !t.IsSubclassOf (type_multicast_delegate)) {
125                         if (t.IsSealed)
126                                 o.Write (t.IsAbstract ? " static" : " sealed");
127                         else if (t.IsAbstract)
128                                 o.Write (" abstract");
129                 }
130                 
131                 o.Write (" ");
132                 o.Write (GetTypeKind (t));
133                 o.Write (" ");
134                 
135                 Type [] interfaces = (Type []) Comparer.Sort (TypeGetInterfaces (t, declared_only));
136                 Type parent = t.BaseType;
137
138                 if (t.IsSubclassOf (type_multicast_delegate)) {
139                         MethodInfo method;
140
141                         method = t.GetMethod ("Invoke");
142
143                         o.Write (FormatType (method.ReturnType));
144                         o.Write (" ");
145                         o.Write (GetTypeName (t));
146                         o.Write (" (");
147                         OutlineParams (method.GetParameters ());
148                         o.Write (")");
149
150                         WriteGenericConstraints (t.GetGenericArguments ());
151         
152                         o.WriteLine (";"); 
153                         return;
154                 }
155                 
156                 o.Write (GetTypeName (t));
157                 if (((parent != null && parent != type_object && parent != type_value_type) || interfaces.Length != 0) && ! t.IsEnum) {
158                         first = true;
159                         o.Write (" : ");
160                         
161                         if (parent != null && parent != type_object && parent != type_value_type) {
162                                 o.Write (FormatType (parent));
163                                 first = false;
164                         }
165                         
166                         foreach (Type intf in interfaces) {
167                                 if (!first) o.Write (", ");
168                                 first = false;
169                                 
170                                 o.Write (FormatType (intf));
171                         }
172                 }
173
174                 if (t.IsEnum) {
175                         Type underlyingType = t.GetEnumUnderlyingType ();
176                         if (underlyingType != type_int)
177                                 o.Write (" : {0}", FormatType (underlyingType));
178                 }
179                 WriteGenericConstraints (t.GetGenericArguments ());
180                 o.WriteLine (" {");
181                 o.Indent++;
182
183                 if (t.IsEnum) {
184                         bool is_first = true;
185                         foreach (FieldInfo fi in t.GetFields (BindingFlags.Public | BindingFlags.Static)) {
186                                 
187                                 if (! is_first)
188                                         o.WriteLine (",");
189                                 is_first = false;
190                                 o.Write (fi.Name);
191                         }
192                         o.WriteLine ();
193                         o.Indent--; o.WriteLine ("}");
194                         return;
195                 }
196                 
197                 first = true;
198                 
199                 foreach (ConstructorInfo ci in t.GetConstructors (DefaultFlags)) {
200                         if (! ShowMember (ci))
201                                 continue;
202                         
203                         if (first)
204                                 o.WriteLine ();
205                         first = false;
206                         
207                         OutlineMemberAttribute (ci);
208                         OutlineConstructor (ci);
209                         
210                         o.WriteLine ();
211                 }
212                 
213
214                 first = true;
215                 
216                 foreach (MethodInfo m in Comparer.Sort (t.GetMethods (DefaultFlags))) {
217                         
218                         if (! ShowMember (m))
219                                 continue;               
220                         
221                         if ((m.Attributes & MethodAttributes.SpecialName) != 0)
222                                 continue;
223                         
224                         if (first)
225                                 o.WriteLine ();
226                         first = false;
227
228                         OutlineMemberAttribute (m);
229                         OutlineMethod (m);
230                         
231                         o.WriteLine ();
232                 }
233                 
234                 first = true;
235                 
236                 foreach (MethodInfo m in t.GetMethods (DefaultFlags)) {
237                         
238                         if (! ShowMember (m))
239                                 continue;
240                         
241                         if ((m.Attributes & MethodAttributes.SpecialName) == 0)
242                                 continue;
243                         if (!(m.Name.StartsWith ("op_")))
244                                 continue;
245
246                         if (first)
247                                 o.WriteLine ();
248                         first = false;
249                         
250                         OutlineMemberAttribute (m);
251                         OutlineOperator (m);
252                         
253                         o.WriteLine ();
254                 }
255
256                 first = true;
257                 
258                 foreach (PropertyInfo pi in Comparer.Sort (t.GetProperties (DefaultFlags))) {
259                         
260                         if (! ((pi.CanRead  && ShowMember (pi.GetGetMethod (true))) ||
261                                (pi.CanWrite && ShowMember (pi.GetSetMethod (true)))))
262                                 continue;
263                         
264                         if (first)
265                                 o.WriteLine ();
266                         first = false;
267                         
268                         OutlineMemberAttribute (pi);
269                         OutlineProperty (pi);
270                         
271                         o.WriteLine ();
272                 }
273                 
274                 first = true;
275
276                 foreach (FieldInfo fi in t.GetFields (DefaultFlags)) {
277                         
278                         if (! ShowMember (fi))
279                                 continue;
280                         
281                         if (first)
282                                 o.WriteLine ();
283                         first = false;
284                         
285                         OutlineMemberAttribute (fi);
286                         OutlineField (fi);
287                         
288                         o.WriteLine ();
289                 }
290
291                 first = true;
292                 
293                 foreach (EventInfo ei in Comparer.Sort (t.GetEvents (DefaultFlags))) {
294                         
295                         if (! ShowMember (ei.GetAddMethod (true)))
296                                 continue;
297                         
298                         if (first)
299                                 o.WriteLine ();
300                         first = false;
301                         
302                         OutlineMemberAttribute (ei);
303                         OutlineEvent (ei);
304                         
305                         o.WriteLine ();
306                 }
307
308                 first = true;
309
310                 foreach (Type ntype in Comparer.Sort (t.GetNestedTypes (DefaultFlags))) {
311                         
312                         if (! ShowMember (ntype))
313                                 continue;
314                         
315                         if (first)
316                                 o.WriteLine ();
317                         first = false;
318
319 #if STATIC
320                         new Outline (universe, mscorlib, ntype, o, declared_only, show_private, filter_obsolete).OutlineType ();
321 #else
322                         new Outline (ntype, o, declared_only, show_private, filter_obsolete).OutlineType ();
323 #endif
324                 }
325                 
326                 o.Indent--; o.WriteLine ("}");
327         }
328         
329         BindingFlags DefaultFlags {
330                 get {
331                         BindingFlags f = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
332                         
333                         if (declared_only)
334                                 f |= BindingFlags.DeclaredOnly;
335                         
336                         return f;
337                 }
338         }
339
340         // FIXME: add other interesting attributes?
341         void OutlineAttributes ()
342         {
343                 if (t.IsSerializable)
344                         o.WriteLine ("[Serializable]");
345
346                 if (t.IsDefined (type_flags_attribute, true))
347                         o.WriteLine ("[Flags]");
348
349                 if (t.IsDefined (type_obsolete_attribute, true))
350                         o.WriteLine ("[Obsolete]");
351         }
352
353         void OutlineMemberAttribute (MemberInfo mi)
354         {
355                 var attrs = mi.GetCustomAttributesData ();
356                 if (attrs.Count > 0)
357                         o.WriteLine ("");
358                 
359                 foreach (var attr in attrs)
360                         o.WriteLine (attr);
361         }
362         
363         void OutlineEvent (EventInfo ei)
364         {
365                 MethodBase accessor = ei.GetAddMethod (true);
366                 
367                 o.Write (GetMethodVisibility (accessor));
368                 o.Write ("event ");
369                 o.Write (FormatType (ei.EventHandlerType));
370                 o.Write (" ");
371                 o.Write (ei.Name);
372                 o.Write (";");
373         }
374         
375         void OutlineConstructor (ConstructorInfo ci)
376         {
377                 o.Write (GetMethodVisibility (ci));
378                 o.Write (RemoveGenericArity (t.Name));
379                 o.Write (" (");
380                 OutlineParams (ci.GetParameters ());
381                 o.Write (");");
382         }
383         
384         
385         void OutlineProperty (PropertyInfo pi)
386         {
387                 ParameterInfo [] idxp = pi.GetIndexParameters ();
388                 MethodBase g = pi.GetGetMethod (true);
389                 MethodBase s = pi.GetSetMethod (true);
390                 MethodBase accessor = g != null ? g : s;
391                 
392                 if (pi.CanRead && pi.CanWrite) {
393
394                         
395                         // Get the more accessible accessor
396                         if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
397                             (s.Attributes & MethodAttributes.MemberAccessMask)) {
398                                 
399                                 if (g.IsPublic) accessor = g;
400                                 else if (s.IsPublic) accessor = s;
401                                 else if (g.IsFamilyOrAssembly) accessor = g;
402                                 else if (s.IsFamilyOrAssembly) accessor = s;
403                                 else if (g.IsAssembly || g.IsFamily) accessor = g;
404                                 else if (s.IsAssembly || s.IsFamily) accessor = s;
405                         }
406                 }
407                 
408                 o.Write (GetMethodVisibility (accessor));
409                 o.Write (GetMethodModifiers  (accessor));
410                 o.Write (FormatType (pi.PropertyType));
411                 o.Write (" ");
412                 
413                 if (idxp.Length == 0)
414                         o.Write (pi.Name);
415                 else {
416                         o.Write ("this [");
417                         OutlineParams (idxp);
418                         o.Write ("]");
419                 }
420                 
421                 o.WriteLine (" {");
422                 o.Indent ++;
423                 
424                 if (g != null && ShowMember (g)) {
425                         if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
426                             (accessor.Attributes & MethodAttributes.MemberAccessMask))
427                                 o.Write (GetMethodVisibility (g));
428                         o.WriteLine ("get;");
429                 }
430                 
431                 if (s != null && ShowMember (s)) {
432                         if ((s.Attributes & MethodAttributes.MemberAccessMask) !=
433                             (accessor.Attributes & MethodAttributes.MemberAccessMask))
434                                 o.Write (GetMethodVisibility (s));
435                         o.WriteLine ("set;");
436                 }
437                 
438                 o.Indent --;
439                 o.Write ("}");
440         }
441         
442         void OutlineMethod (MethodInfo mi)
443         {
444                 if (MethodIsExplicitIfaceImpl (mi)) {
445                         o.Write (FormatType (mi.ReturnType));
446                         o.Write (" ");
447                         // MSFT has no way to get the method that we are overriding
448                         // from the interface. this would allow us to pretty print
449                         // the type name (and be more correct if there compiler
450                         // were to do some strange naming thing).
451                 } else {
452                         o.Write (GetMethodVisibility (mi));
453                         o.Write (GetMethodModifiers  (mi));
454                         o.Write (FormatType (mi.ReturnType));
455                         o.Write (" ");
456                 }
457
458                 o.Write (mi.Name);
459                 o.Write (FormatGenericParams (mi.GetGenericArguments ()));
460                 o.Write (" (");
461                 OutlineParams (mi.GetParameters ());
462                 o.Write (")");
463                 WriteGenericConstraints (mi.GetGenericArguments ());
464                 o.Write (";");
465         }
466         
467         void OutlineOperator (MethodInfo mi)
468         {
469                 o.Write (GetMethodVisibility (mi));
470                 o.Write (GetMethodModifiers  (mi));
471                 if (mi.Name == "op_Explicit" || mi.Name == "op_Implicit") {
472                         o.Write (mi.Name.Substring (3).ToLower ());
473                         o.Write (" operator ");
474                         o.Write (FormatType (mi.ReturnType));
475                 } else {
476                         o.Write (FormatType (mi.ReturnType));
477                         o.Write (" operator ");
478                         o.Write (OperatorFromName (mi.Name));
479                 }
480                 o.Write (" (");
481                 OutlineParams (mi.GetParameters ());
482                 o.Write (");");
483         }
484         
485         void OutlineParams (ParameterInfo [] pi)
486         {
487                 int i = 0;
488                 foreach (ParameterInfo p in pi) {
489                         if (p.ParameterType.IsByRef) {
490                                 o.Write (p.IsOut ? "out " : "ref ");
491                                 o.Write (FormatType (p.ParameterType.GetElementType ()));
492                         } else if (p.IsDefined (type_param_array_attribute, false)) {
493                                 o.Write ("params ");
494                                 o.Write (FormatType (p.ParameterType));
495                         } else {
496                                 o.Write (FormatType (p.ParameterType));
497                         }
498                         
499                         o.Write (" ");
500                         o.Write (p.Name);
501                         if (i + 1 < pi.Length)
502                                 o.Write (", ");
503                         i++;
504                 }
505         }
506
507         void OutlineField (FieldInfo fi)
508         {
509                 if (fi.IsPublic)   o.Write ("public ");
510                 if (fi.IsFamily)   o.Write ("protected ");
511                 if (fi.IsPrivate)  o.Write ("private ");
512                 if (fi.IsAssembly) o.Write ("internal ");
513                 if (fi.IsLiteral)  o.Write ("const ");
514                 else if (fi.IsStatic) o.Write ("static ");
515                 if (fi.IsInitOnly) o.Write ("readonly ");
516
517                 o.Write (FormatType (fi.FieldType));
518                 o.Write (" ");
519                 o.Write (fi.Name);
520                 if (fi.IsLiteral) { 
521                         object v = fi.GetRawConstantValue ();
522
523                         // TODO: Escape values here
524                         o.Write (" = ");
525                         if (v is char)
526                                 o.Write ("'{0}'", v);
527                         else if (v is string)
528                                 o.Write ("\"{0}\"", v);
529                         else
530                                 o.Write (fi.GetRawConstantValue ());
531                 }
532                 o.Write (";");
533         }
534
535         static string GetMethodVisibility (MethodBase m)
536         {
537                 // itnerfaces have no modifiers here
538                 if (m.DeclaringType.IsInterface)
539                         return "";
540                 
541                 if (m.IsPublic)   return "public ";
542                 if (m.IsFamily)   return "protected ";
543                 if (m.IsPrivate)  return "private ";
544                 if (m.IsAssembly) return "internal ";
545                         
546                 return null;
547         }
548         
549         static string GetMethodModifiers (MethodBase method)
550         {
551                 if (method.IsStatic)
552                         return "static ";
553
554                 if (method.IsFinal) {
555                         // This will happen if you have
556                         // class X : IA {
557                         //   public void A () {}
558                         //   static void Main () {}
559                         // }
560                         // interface IA {
561                         //   void A ();
562                         // }
563                         //
564                         // A needs to be virtual (the CLR requires
565                         // methods implementing an iface be virtual),
566                         // but can not be inherited. It also can not
567                         // be inherited. In C# this is represented
568                         // with no special modifiers
569
570                         if (method.IsVirtual)
571                                 return null;
572                         return "sealed ";
573                 }
574                 
575                 // all interface methods are "virtual" but we don't say that in c#
576                 if (method.IsVirtual && !method.DeclaringType.IsInterface) {
577                         if (method.IsAbstract)
578                                 return "abstract ";
579
580                         return ((method.Attributes & MethodAttributes.NewSlot) != 0) ?
581                                 "virtual " :
582                                 "override ";    
583                 }
584                                 
585                 return null;
586         }
587
588         string GetTypeKind (Type t)
589         {
590                 if (t.IsEnum)
591                         return "enum";
592                 if (t.IsClass) {
593                         if (t.IsSubclassOf (type_multicast_delegate))
594                                 return "delegate";
595                         else
596                                 return "class";
597                 }
598                 if (t.IsInterface)
599                         return "interface";
600                 if (t.IsValueType)
601                         return "struct";
602                 return "class";
603         }
604         
605         static string GetTypeVisibility (Type t)
606         {
607                 switch (t.Attributes & TypeAttributes.VisibilityMask){
608                 case TypeAttributes.Public:
609                 case TypeAttributes.NestedPublic:
610                         return "public";
611
612                 case TypeAttributes.NestedFamily:
613                 case TypeAttributes.NestedFamANDAssem:
614                 case TypeAttributes.NestedFamORAssem:
615                         return "protected";
616
617                 default:
618                         return "internal";
619                 }
620         }
621
622         string FormatGenericParams (Type [] args)
623         {
624                 StringBuilder sb = new StringBuilder ();
625                 if (args.Length == 0)
626                         return "";
627                 
628                 sb.Append ("<");
629                 for (int i = 0; i < args.Length; i++) {
630                         if (i > 0)
631                                 sb.Append (",");
632                         sb.Append (FormatType (args [i]));
633                 }
634                 sb.Append (">");
635                 return sb.ToString ();
636         }
637
638         // TODO: fine tune this so that our output is less verbose. We need to figure
639         // out a way to do this while not making things confusing.
640         string FormatType (Type t)
641         {
642                 if (t == null)
643                         return "";
644
645                 string type = GetFullName (t);
646                 if (type == null)
647                         return t.ToString ();
648                 
649                 if (!type.StartsWith ("System.")) {
650                         if (type.IndexOf (".") == -1)
651                                 return type;
652                         if (t.GetNamespace () == this.t.GetNamespace ())
653                                 return t.Name;
654                         return type;
655                 }
656                 
657                 if (t.HasElementType) {
658                         Type et = t.GetElementType ();
659                         if (t.IsArray)
660                                 return FormatType (et) + " []";
661                         if (t.IsPointer)
662                                 return FormatType (et) + " *";
663                         if (t.IsByRef)
664                                 return "ref " + FormatType (et);
665                 }
666         
667                 switch (type) {
668                 case "System.Byte": return "byte";
669                 case "System.SByte": return "sbyte";
670                 case "System.Int16": return "short";
671                 case "System.Int32": return "int";
672                 case "System.Int64": return "long";
673                         
674                 case "System.UInt16": return "ushort";
675                 case "System.UInt32": return "uint";
676                 case "System.UInt64": return "ulong";
677                         
678                 case "System.Single":  return "float";
679                 case "System.Double":  return "double";
680                 case "System.Decimal": return "decimal";
681                 case "System.Boolean": return "bool";
682                 case "System.Char":    return "char";
683                 case "System.String":  return "string";
684                         
685                 case "System.Object":  return "object";
686                 case "System.Void":  return "void";
687                 }
688         
689                 if (type.LastIndexOf(".") == 6)
690                         return type.Substring(7);
691
692                 //
693                 // If the namespace of the type is the namespace of what
694                 // we are printing (or is a member of one if its children
695                 // don't print it. This basically means that in C# we would
696                 // automatically get the namespace imported by virtue of the
697                 // namespace {} block.
698                 //      
699                 if (this.t.Namespace != null && (this.t.Namespace.StartsWith (t.Namespace + ".") || t.Namespace == this.t.Namespace))
700                         return type.Substring (t.Namespace.Length + 1);
701         
702                 return type;
703         }
704
705         public static string RemoveGenericArity (string name)
706         {
707                 int start = 0;
708                 StringBuilder sb = new StringBuilder ();
709                 while (start < name.Length) {
710                         int pos = name.IndexOf ('`', start);
711                         if (pos < 0) {
712                                 sb.Append (name.Substring (start));
713                                 break;
714                         }
715                         sb.Append (name.Substring (start, pos-start));
716
717                         pos++;
718
719                         while ((pos < name.Length) && Char.IsNumber (name [pos]))
720                                 pos++;
721
722                         start = pos;
723                 }
724
725                 return sb.ToString ();
726         }
727
728         string GetTypeName (Type t)
729         {
730                 StringBuilder sb = new StringBuilder ();
731                 GetTypeName (sb, t);
732                 return sb.ToString ();
733         }
734
735         void GetTypeName (StringBuilder sb, Type t)
736         {
737                 sb.Append (RemoveGenericArity (t.Name));
738                 sb.Append (FormatGenericParams (t.GetGenericArguments ()));
739         }
740
741         string GetFullName (Type t)
742         {
743                 StringBuilder sb = new StringBuilder ();
744                 GetFullName_recursed (sb, t, false);
745                 return sb.ToString ();
746         }
747
748         void GetFullName_recursed (StringBuilder sb, Type t, bool recursed)
749         {
750                 if (t.IsGenericParameter) {
751                         sb.Append (t.Name);
752                         return;
753                 }
754
755                 if (t.DeclaringType != null) {
756                         GetFullName_recursed (sb, t.DeclaringType, true);
757                         sb.Append (".");
758                 }
759
760                 if (!recursed) {
761                         string ns;
762                         ns = t.GetNamespace ();
763                         if ((ns != null) && (ns != "")) {
764                                 sb.Append (ns);
765                                 sb.Append (".");
766                         }
767                 }
768
769                 GetTypeName (sb, t);
770         }
771
772         void WriteGenericConstraints (Type [] args)
773         {
774
775                 foreach (Type t in args) {
776                         bool first = true;
777                         Type[] ifaces = TypeGetInterfaces (t, true);
778                         
779                         GenericParameterAttributes attrs = t.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
780                         GenericParameterAttributes [] interesting = {
781                                 GenericParameterAttributes.ReferenceTypeConstraint,
782                                 GenericParameterAttributes.NotNullableValueTypeConstraint,
783                                 GenericParameterAttributes.DefaultConstructorConstraint
784                         };
785                         
786                         if (t.BaseType != type_object || ifaces.Length != 0 || attrs != 0) {
787                                 o.Write (" where ");
788                                 o.Write (FormatType (t));
789                                 o.Write (" : ");
790                         }
791
792                         if (t.BaseType != type_object) {
793                                 o.Write (FormatType (t.BaseType));
794                                 first = false;
795                         }
796
797                         foreach (Type iface in ifaces) {
798                                 if (!first)
799                                         o.Write (", ");
800                                 first = false;
801                                 
802                                 o.Write (FormatType (iface));
803                         }
804
805                         foreach (GenericParameterAttributes a in interesting) {
806                                 if ((attrs & a) == 0)
807                                         continue;
808                                 
809                                 if (!first)
810                                         o.Write (", ");
811                                 first = false;
812                                 
813                                 switch (a) {
814                                 case GenericParameterAttributes.ReferenceTypeConstraint:
815                                         o.Write ("class");
816                                         break;
817                                 case GenericParameterAttributes.NotNullableValueTypeConstraint:
818                                         o.Write ("struct");
819                                         break;
820                                 case GenericParameterAttributes.DefaultConstructorConstraint:
821                                         o.Write ("new ()");
822                                         break;
823                                 }
824                         }
825                 }
826         }
827  
828         string OperatorFromName (string name)
829         {
830                 switch (name) {
831                 case "op_UnaryPlus": return "+";
832                 case "op_UnaryNegation": return "-";
833                 case "op_LogicalNot": return "!";
834                 case "op_OnesComplement": return "~";
835                 case "op_Increment": return "++";
836                 case "op_Decrement": return "--";
837                 case "op_True": return "true";
838                 case "op_False": return "false";
839                 case "op_Addition": return "+";
840                 case "op_Subtraction": return "-";
841                 case "op_Multiply": return "*";
842                 case "op_Division": return "/";
843                 case "op_Modulus": return "%";
844                 case "op_BitwiseAnd": return "&";
845                 case "op_BitwiseOr": return "|";
846                 case "op_ExclusiveOr": return "^";
847                 case "op_LeftShift": return "<<";
848                 case "op_RightShift": return ">>";
849                 case "op_Equality": return "==";
850                 case "op_Inequality": return "!=";
851                 case "op_GreaterThan": return ">";
852                 case "op_LessThan": return "<";
853                 case "op_GreaterThanOrEqual": return ">=";
854                 case "op_LessThanOrEqual": return "<=";
855                 default: return name;
856                 }
857         }
858
859         bool MethodIsExplicitIfaceImpl (MethodBase mb)
860         {
861                 if (!(mb.IsFinal && mb.IsVirtual && mb.IsPrivate))
862                         return false;
863                 
864                 // UGH msft has no way to get the info about what method is
865                 // getting overriden. Another reason to use cecil :-)
866                 //
867                 //MethodInfo mi = mb as MethodInfo;
868                 //if (mi == null)
869                 //      return false;
870                 //
871                 //Console.WriteLine (mi.GetBaseDefinition ().DeclaringType);
872                 //return mi.GetBaseDefinition ().DeclaringType.IsInterface;
873                 
874                 // So, we guess that virtual final private methods only come
875                 // from ifaces :-)
876                 return true;
877         }
878         
879         bool ShowMember (MemberInfo mi)
880         {
881                 if (mi.MemberType == MemberTypes.Constructor && ((MethodBase) mi).IsStatic)
882                         return false;
883                 
884                 if (show_private)
885                         return true;
886
887                 if (filter_obsolete && mi.IsDefined (type_obsolete_attribute, false))
888                         return false;
889                 
890                 switch (mi.MemberType) {
891                 case MemberTypes.Constructor:
892                 case MemberTypes.Method:
893                         MethodBase mb = mi as MethodBase;
894                 
895                         if (mb.IsFamily || mb.IsPublic || mb.IsFamilyOrAssembly)
896                                 return true;
897                         
898                         if (MethodIsExplicitIfaceImpl (mb))
899                                 return true;
900                                         
901                         return false;
902                 
903                 
904                 case MemberTypes.Field:
905                         FieldInfo fi = mi as FieldInfo;
906                 
907                         if (fi.IsFamily || fi.IsPublic || fi.IsFamilyOrAssembly)
908                                 return true;
909                         
910                         return false;
911                 
912                 
913                 case MemberTypes.NestedType:
914                 case MemberTypes.TypeInfo:
915                         Type t = mi as Type;
916                 
917                         switch (t.Attributes & TypeAttributes.VisibilityMask){
918                         case TypeAttributes.Public:
919                         case TypeAttributes.NestedPublic:
920                         case TypeAttributes.NestedFamily:
921                         case TypeAttributes.NestedFamORAssem:
922                                 return true;
923                         }
924                         
925                         return false;
926                 }
927                 
928                 // What am I !!!
929                 return true;
930         }
931
932         static Type [] TypeGetInterfaces (Type t, bool declonly)
933         {
934                 if (t.IsGenericParameter)
935                         return new Type [0];
936
937                 Type [] ifaces = t.GetInterfaces ();
938                 if (! declonly)
939                         return ifaces;
940
941                 // Handle Object. Also, optimize for no interfaces
942                 if (t.BaseType == null || ifaces.Length == 0)
943                         return ifaces;
944
945                 ArrayList ar = new ArrayList ();
946
947                 foreach (Type i in ifaces)
948                         if (! i.IsAssignableFrom (t.BaseType))
949                                 ar.Add (i);
950
951                 return (Type []) ar.ToArray (typeof (Type));
952         }
953 }
954
955 public class Comparer : IComparer  {
956         delegate int ComparerFunc (object a, object b);
957         
958         ComparerFunc cmp;
959         
960         Comparer (ComparerFunc f)
961         {
962                 this.cmp = f;
963         }
964         
965         public int Compare (object a, object b)
966         {
967                 return cmp (a, b);
968         }
969
970         static int CompareType (object a, object b)
971         {
972                 Type type1 = (Type) a;
973                 Type type2 = (Type) b;
974
975                 return string.Compare (type1.Name, type2.Name);
976                         
977         }
978
979 //      static Comparer TypeComparer = new Comparer (new ComparerFunc (CompareType));
980
981 //      static Type [] Sort (Type [] types)
982 //      {
983 //              Array.Sort (types, TypeComparer);
984 //              return types;
985 //      }
986         
987         static int CompareMemberInfo (object a, object b)
988         {
989                 return string.Compare (((MemberInfo) a).Name, ((MemberInfo) b).Name);
990         }
991         
992         static Comparer MemberInfoComparer = new Comparer (new ComparerFunc (CompareMemberInfo));
993         
994         public static MemberInfo [] Sort (MemberInfo [] inf)
995         {
996                 Array.Sort (inf, MemberInfoComparer);
997                 return inf;
998         }
999         
1000         static int CompareMethodBase (object a, object b)
1001         {
1002                 MethodBase aa = (MethodBase) a, bb = (MethodBase) b;
1003                 
1004                 if (aa.IsStatic == bb.IsStatic) {
1005                         int c = CompareMemberInfo (a, b);
1006                         if (c != 0)
1007                                 return c;
1008                         ParameterInfo [] ap, bp;
1009
1010                         //
1011                         // Sort overloads by the names of their types
1012                         // put methods with fewer params first.
1013                         //
1014                         
1015                         ap = aa.GetParameters ();
1016                         bp = bb.GetParameters ();
1017                         int n = System.Math.Min (ap.Length, bp.Length);
1018
1019                         for (int i = 0; i < n; i ++)
1020                                 if ((c = CompareType (ap [i].ParameterType, bp [i].ParameterType)) != 0)
1021                                         return c;
1022
1023                         return ap.Length.CompareTo (bp.Length);
1024                 }
1025                 if (aa.IsStatic)
1026                         return -1;
1027                 
1028                 return 1;
1029         }
1030         
1031         static Comparer MethodBaseComparer = new Comparer (new ComparerFunc (CompareMethodBase));
1032         
1033         public static MethodBase [] Sort (MethodBase [] inf)
1034         {
1035                 Array.Sort (inf, MethodBaseComparer);
1036                 return inf;
1037         }
1038         
1039         static int ComparePropertyInfo (object a, object b)
1040         {
1041                 PropertyInfo aa = (PropertyInfo) a, bb = (PropertyInfo) b;
1042                 
1043                 bool astatic = (aa.CanRead ? aa.GetGetMethod (true) : aa.GetSetMethod (true)).IsStatic;
1044                 bool bstatic = (bb.CanRead ? bb.GetGetMethod (true) : bb.GetSetMethod (true)).IsStatic;
1045                 
1046                 if (astatic == bstatic)
1047                         return CompareMemberInfo (a, b);
1048                 
1049                 if (astatic)
1050                         return -1;
1051                 
1052                 return 1;
1053         }
1054         
1055         static Comparer PropertyInfoComparer = new Comparer (new ComparerFunc (ComparePropertyInfo));
1056         
1057         public static PropertyInfo [] Sort (PropertyInfo [] inf)
1058         {
1059                 Array.Sort (inf, PropertyInfoComparer);
1060                 return inf;
1061         }
1062         
1063         static int CompareEventInfo (object a, object b)
1064         {
1065                 EventInfo aa = (EventInfo) a, bb = (EventInfo) b;
1066                 
1067                 bool astatic = aa.GetAddMethod (true).IsStatic;
1068                 bool bstatic = bb.GetAddMethod (true).IsStatic;
1069                 
1070                 if (astatic == bstatic)
1071                         return CompareMemberInfo (a, b);
1072                 
1073                 if (astatic)
1074                         return -1;
1075                 
1076                 return 1;
1077         }
1078         
1079         static Comparer EventInfoComparer = new Comparer (new ComparerFunc (CompareEventInfo));
1080         
1081         public static EventInfo [] Sort (EventInfo [] inf)
1082         {
1083                 Array.Sort (inf, EventInfoComparer);
1084                 return inf;
1085         }
1086 }
1087 }