2 // outline -- support for rendering in monop
3 // Some code stolen from updater.cs in monodoc.
6 // Ben Maurer (bmaurer@users.sourceforge.net)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System.Reflection;
34 using System.Collections;
35 using System.CodeDom.Compiler;
39 public class Outline {
45 public Outline (Type t, TextWriter output, Options options)
48 this.o = new IndentedTextWriter (output, " ");
49 this.options = options;
52 public void OutlineType ()
57 o.Write (GetTypeVisibility (t));
59 if (t.IsClass && !t.IsSubclassOf (typeof (System.MulticastDelegate))) {
61 o.Write (t.IsAbstract ? " static" : " sealed");
62 else if (t.IsAbstract)
63 o.Write (" abstract");
67 o.Write (GetTypeKind (t));
70 Type [] interfaces = (Type []) Comparer.Sort (t.GetInterfaces ());
71 Type parent = t.BaseType;
73 if (t.IsSubclassOf (typeof (System.MulticastDelegate))) {
76 method = t.GetMethod ("Invoke");
78 o.Write (FormatType (method.ReturnType));
80 o.Write (GetTypeName (t));
82 OutlineParams (method.GetParameters ());
88 o.Write (GetTypeName (t));
89 if (((parent != null && parent != typeof (object) && parent != typeof (ValueType)) || interfaces.Length != 0) && ! t.IsEnum) {
93 if (parent != null && parent != typeof (object) && parent != typeof (ValueType)) {
94 o.Write (FormatType (parent));
98 foreach (Type intf in interfaces) {
99 if (!first) o.Write (", ");
102 o.Write (FormatType (intf));
107 Type underlyingType = Enum.GetUnderlyingType (t);
108 if (underlyingType != typeof (int))
109 o.Write (" : {0}", FormatType (underlyingType));
116 bool is_first = true;
117 foreach (FieldInfo fi in t.GetFields (BindingFlags.Public | BindingFlags.Static)) {
125 o.Indent--; o.WriteLine ("}");
131 foreach (ConstructorInfo ci in t.GetConstructors (DefaultFlags)) {
133 if (! ShowMember (ci))
140 OutlineConstructor (ci);
148 foreach (MethodInfo m in Comparer.Sort (t.GetMethods (DefaultFlags))) {
150 if (! ShowMember (m))
153 if ((m.Attributes & MethodAttributes.SpecialName) != 0)
167 foreach (MethodInfo m in t.GetMethods (DefaultFlags)) {
169 if (! ShowMember (m))
172 if ((m.Attributes & MethodAttributes.SpecialName) == 0)
174 if (!(m.Name.StartsWith ("op_")))
188 foreach (PropertyInfo pi in Comparer.Sort (t.GetProperties (DefaultFlags))) {
190 if (! ((pi.CanRead && ShowMember (pi.GetGetMethod (true))) ||
191 (pi.CanWrite && ShowMember (pi.GetSetMethod (true)))))
198 OutlineProperty (pi);
205 foreach (FieldInfo fi in t.GetFields (DefaultFlags)) {
207 if (! ShowMember (fi))
221 foreach (EventInfo ei in Comparer.Sort (t.GetEvents (DefaultFlags))) {
223 if (! ShowMember (ei.GetAddMethod ()))
237 foreach (Type ntype in Comparer.Sort (t.GetNestedTypes (DefaultFlags))) {
239 if (! ShowMember (ntype))
246 new Outline (ntype, o, options).OutlineType ();
249 o.Indent--; o.WriteLine ("}");
252 BindingFlags DefaultFlags {
254 BindingFlags f = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
256 if (options.DeclaredOnly)
257 f |= BindingFlags.DeclaredOnly;
263 // FIXME: add other interesting attributes?
264 void OutlineAttributes ()
266 if (t.IsSerializable)
267 o.WriteLine ("[Serializable]");
269 if (t.IsDefined (typeof (System.FlagsAttribute), true))
270 o.WriteLine ("[Flags]");
272 if (t.IsDefined (typeof (System.ObsoleteAttribute), true))
273 o.WriteLine ("[Obsolete]");
276 void OutlineEvent (EventInfo ei)
278 MethodBase accessor = ei.GetAddMethod ();
280 o.Write (GetMethodVisibility (accessor));
282 o.Write (FormatType (ei.EventHandlerType));
288 void OutlineConstructor (ConstructorInfo ci)
290 o.Write (GetMethodVisibility (ci));
291 o.Write (RemoveGenericArity (t.Name));
293 OutlineParams (ci.GetParameters ());
298 void OutlineProperty (PropertyInfo pi)
300 ParameterInfo [] idxp = pi.GetIndexParameters ();
301 MethodBase g = pi.GetGetMethod (true);
302 MethodBase s = pi.GetSetMethod (true);
303 MethodBase accessor = g != null ? g : s;
305 if (pi.CanRead && pi.CanWrite) {
308 // Get the more accessible accessor
309 if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
310 (s.Attributes & MethodAttributes.MemberAccessMask)) {
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;
321 o.Write (GetMethodVisibility (accessor));
322 o.Write (GetMethodModifiers (accessor));
323 o.Write (FormatType (pi.PropertyType));
326 if (idxp.Length == 0)
330 OutlineParams (idxp);
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;");
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;");
355 void OutlineMethod (MethodInfo mi)
357 o.Write (GetMethodVisibility (mi));
358 o.Write (GetMethodModifiers (mi));
359 o.Write (FormatType (mi.ReturnType));
363 o.Write (FormatGenericParams (mi.GetGenericArguments ()));
366 OutlineParams (mi.GetParameters ());
370 void OutlineOperator (MethodInfo mi)
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));
379 o.Write (FormatType (mi.ReturnType));
380 o.Write (" operator ");
381 o.Write (OperatorFromName (mi.Name));
384 OutlineParams (mi.GetParameters ());
388 void OutlineParams (ParameterInfo [] pi)
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)) {
397 o.Write (FormatType (p.ParameterType));
399 o.Write (FormatType (p.ParameterType));
404 if (i + 1 < pi.Length)
410 void OutlineField (FieldInfo fi)
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 ");
419 o.Write (FormatType (fi.FieldType));
425 o.Write (fi.GetValue (this));
430 static string GetMethodVisibility (MethodBase m)
432 // itnerfaces have no modifiers here
433 if (m.DeclaringType.IsInterface)
436 if (m.IsPublic) return "public ";
437 if (m.IsFamily) return "protected ";
438 if (m.IsPrivate) return "private ";
439 if (m.IsAssembly) return "internal ";
444 static string GetMethodModifiers (MethodBase method)
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) ?
458 static string GetTypeKind (Type t)
463 if (t.IsSubclassOf (typeof (System.MulticastDelegate)))
475 static string GetTypeVisibility (Type t)
477 switch (t.Attributes & TypeAttributes.VisibilityMask){
478 case TypeAttributes.Public:
479 case TypeAttributes.NestedPublic:
482 case TypeAttributes.NestedFamily:
483 case TypeAttributes.NestedFamANDAssem:
484 case TypeAttributes.NestedFamORAssem:
492 string FormatGenericParams (Type [] args)
494 StringBuilder sb = new StringBuilder ();
495 if (args.Length == 0)
499 for (int i = 0; i < args.Length; i++) {
502 sb.Append (FormatType (args [i]));
505 return sb.ToString ();
508 string FormatType (Type t)
510 string type = GetFullName (t);
512 if (!type.StartsWith ("System.")) {
513 if (t.Namespace == this.t.Namespace)
518 if (t.HasElementType) {
519 Type et = t.GetElementType ();
521 return FormatType (et) + " []";
523 return FormatType (et) + " *";
525 return "ref " + FormatType (et);
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";
535 case "System.UInt16": return "ushort";
536 case "System.UInt32": return "uint";
537 case "System.UInt64": return "ulong";
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";
546 case "System.Object": return "object";
547 case "System.Void": return "void";
550 if (type.LastIndexOf(".") == 6)
551 return type.Substring(7);
556 public static string RemoveGenericArity (string name)
559 StringBuilder sb = new StringBuilder ();
560 while (start < name.Length) {
561 int pos = name.IndexOf ('`', start);
563 sb.Append (name.Substring (start));
566 sb.Append (name.Substring (start, pos-start));
570 while ((pos < name.Length) && Char.IsNumber (name [pos]))
576 return sb.ToString ();
579 string GetTypeName (Type t)
581 StringBuilder sb = new StringBuilder ();
583 return sb.ToString ();
586 void GetTypeName (StringBuilder sb, Type t)
588 sb.Append (RemoveGenericArity (t.Name));
590 sb.Append (FormatGenericParams (t.GetGenericArguments ()));
594 string GetFullName (Type t)
596 StringBuilder sb = new StringBuilder ();
597 GetFullName_recursed (sb, t, false);
598 return sb.ToString ();
601 void GetFullName_recursed (StringBuilder sb, Type t, bool recursed)
604 if (t.IsGenericParameter) {
610 if (t.DeclaringType != null) {
611 GetFullName_recursed (sb, t.DeclaringType, true);
616 string ns = t.Namespace;
617 if ((ns != null) && (ns != "")) {
626 string OperatorFromName (string 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;
657 bool ShowMember (MemberInfo mi)
659 if (mi.MemberType == MemberTypes.Constructor && ((MethodBase) mi).IsStatic)
662 if (options.ShowPrivate)
665 switch (mi.MemberType) {
666 case MemberTypes.Constructor:
667 case MemberTypes.Method:
668 MethodBase mb = mi as MethodBase;
670 if (mb.IsFamily || mb.IsPublic || mb.IsFamilyOrAssembly)
676 case MemberTypes.Field:
677 FieldInfo fi = mi as FieldInfo;
679 if (fi.IsFamily || fi.IsPublic || fi.IsFamilyOrAssembly)
685 case MemberTypes.NestedType:
686 case MemberTypes.TypeInfo:
689 switch (t.Attributes & TypeAttributes.VisibilityMask){
690 case TypeAttributes.Public:
691 case TypeAttributes.NestedPublic:
692 case TypeAttributes.NestedFamily:
693 case TypeAttributes.NestedFamORAssem:
705 public class Comparer : IComparer {
706 delegate int ComparerFunc (object a, object b);
710 Comparer (ComparerFunc f)
715 public int Compare (object a, object b)
720 static int CompareType (object a, object b)
722 Type type1 = (Type) a;
723 Type type2 = (Type) b;
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);
731 static Comparer TypeComparer = new Comparer (new ComparerFunc (CompareType));
733 static Type [] Sort (Type [] types)
735 Array.Sort (types, TypeComparer);
739 static int CompareMemberInfo (object a, object b)
741 return string.Compare (((MemberInfo) a).Name, ((MemberInfo) b).Name);
744 static Comparer MemberInfoComparer = new Comparer (new ComparerFunc (CompareMemberInfo));
746 public static MemberInfo [] Sort (MemberInfo [] inf)
748 Array.Sort (inf, MemberInfoComparer);
752 static int CompareMethodBase (object a, object b)
754 MethodBase aa = (MethodBase) a, bb = (MethodBase) b;
756 if (aa.IsStatic == bb.IsStatic)
757 return CompareMemberInfo (a, b);
765 static Comparer MethodBaseComparer = new Comparer (new ComparerFunc (CompareMethodBase));
767 public static MethodBase [] Sort (MethodBase [] inf)
769 Array.Sort (inf, MethodBaseComparer);
773 static int ComparePropertyInfo (object a, object b)
775 PropertyInfo aa = (PropertyInfo) a, bb = (PropertyInfo) b;
777 bool astatic = (aa.CanRead ? aa.GetGetMethod (true) : aa.GetSetMethod (true)).IsStatic;
778 bool bstatic = (bb.CanRead ? bb.GetGetMethod (true) : bb.GetSetMethod (true)).IsStatic;
780 if (astatic == bstatic)
781 return CompareMemberInfo (a, b);
789 static Comparer PropertyInfoComparer = new Comparer (new ComparerFunc (ComparePropertyInfo));
791 public static PropertyInfo [] Sort (PropertyInfo [] inf)
793 Array.Sort (inf, PropertyInfoComparer);
797 static int CompareEventInfo (object a, object b)
799 EventInfo aa = (EventInfo) a, bb = (EventInfo) b;
801 bool astatic = aa.GetAddMethod (true).IsStatic;
802 bool bstatic = bb.GetAddMethod (true).IsStatic;
804 if (astatic == bstatic)
805 return CompareMemberInfo (a, b);
813 static Comparer EventInfoComparer = new Comparer (new ComparerFunc (CompareEventInfo));
815 public static EventInfo [] Sort (EventInfo [] inf)
817 Array.Sort (inf, EventInfoComparer);