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