2007-02-23 Nagappan A <anagappan@novell.com>
[mono.git] / mcs / tools / monop / outline.cs
index 3ba0ab110088ff930265cc24c065737b2bc694a6..35f1e4fb99cd3079c853e593c2ab50486c7607e3 100644 (file)
@@ -8,24 +8,48 @@
 // (C) 2004 Ben Maurer
 //
 
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using System;
 using System.Reflection;
 using System.Collections;
 using System.CodeDom.Compiler;
 using System.IO;
+using System.Text;
        
 public class Outline {
        
+       Options options;
        IndentedTextWriter o;
        Type t;
        
-       public Outline (Type t, TextWriter output)
+       public Outline (Type t, TextWriter output, Options options)
        {
                this.t = t;
-               this.o = new IndentedTextWriter (output, "    ");
+               this.o = new IndentedTextWriter (output, "\t");
+               this.options = options;
        }
 
-       public void OutlineType (BindingFlags flags)
+       public void OutlineType ()
         {
                bool first;
                
@@ -43,7 +67,7 @@ public class Outline {
                o.Write (GetTypeKind (t));
                o.Write (" ");
                
-               Type [] interfaces = (Type []) Comparer.Sort (t.GetInterfaces ());
+               Type [] interfaces = (Type []) Comparer.Sort (TypeGetInterfaces (t, options.DeclaredOnly));
                Type parent = t.BaseType;
 
                if (t.IsSubclassOf (typeof (System.MulticastDelegate))) {
@@ -53,15 +77,20 @@ public class Outline {
 
                        o.Write (FormatType (method.ReturnType));
                        o.Write (" ");
-                       o.Write (t.Name);
+                       o.Write (GetTypeName (t));
                        o.Write (" (");
                        OutlineParams (method.GetParameters ());
-                       o.WriteLine (");");
+                       o.Write (")");
 
+#if NET_2_0
+                       WriteGenericConstraints (t.GetGenericArguments ());
+#endif                 
+       
+                       o.WriteLine (";"); 
                        return;
                }
                
-               o.Write (t.Name);
+               o.Write (GetTypeName (t));
                if (((parent != null && parent != typeof (object) && parent != typeof (ValueType)) || interfaces.Length != 0) && ! t.IsEnum) {
                        first = true;
                        o.Write (" : ");
@@ -78,7 +107,15 @@ public class Outline {
                                o.Write (FormatType (intf));
                        }
                }
-               
+
+               if (t.IsEnum) {
+                       Type underlyingType = Enum.GetUnderlyingType (t);
+                       if (underlyingType != typeof (int))
+                               o.Write (" : {0}", FormatType (underlyingType));
+               }
+#if NET_2_0
+               WriteGenericConstraints (t.GetGenericArguments ());
+#endif         
                o.WriteLine (" {");
                o.Indent++;
 
@@ -98,7 +135,11 @@ public class Outline {
                
                first = true;
                
-               foreach (ConstructorInfo ci in t.GetConstructors (flags)) {
+               foreach (ConstructorInfo ci in t.GetConstructors (DefaultFlags)) {
+                       
+                       if (! ShowMember (ci))
+                               continue;
+                       
                        if (first)
                                o.WriteLine ();
                        first = false;
@@ -111,7 +152,11 @@ public class Outline {
 
                first = true;
                
-               foreach (MethodInfo m in Comparer.Sort (t.GetMethods (flags))) {
+               foreach (MethodInfo m in Comparer.Sort (t.GetMethods (DefaultFlags))) {
+                       
+                       if (! ShowMember (m))
+                               continue;               
+                       
                        if ((m.Attributes & MethodAttributes.SpecialName) != 0)
                                continue;
                        
@@ -126,7 +171,11 @@ public class Outline {
                
                first = true;
                
-               foreach (MethodInfo m in t.GetMethods (flags)) {
+               foreach (MethodInfo m in t.GetMethods (DefaultFlags)) {
+                       
+                       if (! ShowMember (m))
+                               continue;
+                       
                        if ((m.Attributes & MethodAttributes.SpecialName) == 0)
                                continue;
                        if (!(m.Name.StartsWith ("op_")))
@@ -143,7 +192,11 @@ public class Outline {
 
                first = true;
                
-               foreach (PropertyInfo pi in Comparer.Sort (t.GetProperties (flags))) {
+               foreach (PropertyInfo pi in Comparer.Sort (t.GetProperties (DefaultFlags))) {
+                       
+                       if (! ((pi.CanRead  && ShowMember (pi.GetGetMethod (true))) ||
+                              (pi.CanWrite && ShowMember (pi.GetSetMethod (true)))))
+                               continue;
                        
                        if (first)
                                o.WriteLine ();
@@ -156,7 +209,10 @@ public class Outline {
                
                first = true;
 
-               foreach (FieldInfo fi in t.GetFields (flags)) {
+               foreach (FieldInfo fi in t.GetFields (DefaultFlags)) {
+                       
+                       if (! ShowMember (fi))
+                               continue;
                        
                        if (first)
                                o.WriteLine ();
@@ -169,7 +225,10 @@ public class Outline {
 
                first = true;
                
-               foreach (EventInfo ei in Comparer.Sort (t.GetEvents (flags))) {
+               foreach (EventInfo ei in Comparer.Sort (t.GetEvents (DefaultFlags))) {
+                       
+                       if (! ShowMember (ei.GetAddMethod (true)))
+                               continue;
                        
                        if (first)
                                o.WriteLine ();
@@ -182,17 +241,31 @@ public class Outline {
 
                first = true;
 
-               foreach (Type ntype in Comparer.Sort (t.GetNestedTypes (flags))) {
+               foreach (Type ntype in Comparer.Sort (t.GetNestedTypes (DefaultFlags))) {
+                       
+                       if (! ShowMember (ntype))
+                               continue;
                        
                        if (first)
                                o.WriteLine ();
                        first = false;
                        
-                       new Outline (ntype, o).OutlineType (flags);
+                       new Outline (ntype, o, options).OutlineType ();
                }
                
                o.Indent--; o.WriteLine ("}");
        }
+       
+       BindingFlags DefaultFlags {
+               get {
+                       BindingFlags f = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
+                       
+                       if (options.DeclaredOnly)
+                               f |= BindingFlags.DeclaredOnly;
+                       
+                       return f;
+               }
+       }
 
        // FIXME: add other interesting attributes?
        void OutlineAttributes ()
@@ -209,7 +282,7 @@ public class Outline {
 
        void OutlineEvent (EventInfo ei)
        {
-               MethodBase accessor = ei.GetAddMethod ();
+               MethodBase accessor = ei.GetAddMethod (true);
                
                o.Write (GetMethodVisibility (accessor));
                o.Write ("event ");
@@ -222,7 +295,7 @@ public class Outline {
        void OutlineConstructor (ConstructorInfo ci)
        {
                o.Write (GetMethodVisibility (ci));
-               o.Write (t.Name);
+               o.Write (RemoveGenericArity (t.Name));
                o.Write (" (");
                OutlineParams (ci.GetParameters ());
                o.Write (");");
@@ -232,7 +305,25 @@ public class Outline {
        void OutlineProperty (PropertyInfo pi)
        {
                ParameterInfo [] idxp = pi.GetIndexParameters ();
-               MethodBase accessor = pi.CanRead ? pi.GetGetMethod (true) : pi.GetSetMethod (true);
+               MethodBase g = pi.GetGetMethod (true);
+               MethodBase s = pi.GetSetMethod (true);
+               MethodBase accessor = g != null ? g : s;
+               
+               if (pi.CanRead && pi.CanWrite) {
+
+                       
+                       // Get the more accessible accessor
+                       if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
+                           (s.Attributes & MethodAttributes.MemberAccessMask)) {
+                               
+                               if (g.IsPublic) accessor = g;
+                               else if (s.IsPublic) accessor = s;
+                               else if (g.IsFamilyOrAssembly) accessor = g;
+                               else if (s.IsFamilyOrAssembly) accessor = s;
+                               else if (g.IsAssembly || g.IsFamily) accessor = g;
+                               else if (s.IsAssembly || s.IsFamily) accessor = s;
+                       }
+               }
                
                o.Write (GetMethodVisibility (accessor));
                o.Write (GetMethodModifiers  (accessor));
@@ -250,8 +341,19 @@ public class Outline {
                o.WriteLine (" {");
                o.Indent ++;
                
-               if (pi.CanRead)  o.WriteLine ("get;");
-               if (pi.CanWrite) o.WriteLine ("set;");
+               if (g != null && ShowMember (g)) {
+                       if ((g.Attributes & MethodAttributes.MemberAccessMask) !=
+                           (accessor.Attributes & MethodAttributes.MemberAccessMask))
+                               o.Write (GetMethodVisibility (g));
+                       o.WriteLine ("get;");
+               }
+               
+               if (s != null && ShowMember (s)) {
+                       if ((s.Attributes & MethodAttributes.MemberAccessMask) !=
+                           (accessor.Attributes & MethodAttributes.MemberAccessMask))
+                               o.Write (GetMethodVisibility (s));
+                       o.WriteLine ("set;");
+               }
                
                o.Indent --;
                o.Write ("}");
@@ -259,14 +361,31 @@ public class Outline {
        
        void OutlineMethod (MethodInfo mi)
        {
-               o.Write (GetMethodVisibility (mi));
-               o.Write (GetMethodModifiers  (mi));
-               o.Write (FormatType (mi.ReturnType));
-               o.Write (" ");
+               if (MethodIsExplicitIfaceImpl (mi)) {
+                       o.Write (FormatType (mi.ReturnType));
+                       o.Write (" ");
+                       // MSFT has no way to get the method that we are overriding
+                       // from the interface. this would allow us to pretty print
+                       // the type name (and be more correct if there compiler
+                       // were to do some strange naming thing).
+               } else {
+                       o.Write (GetMethodVisibility (mi));
+                       o.Write (GetMethodModifiers  (mi));
+                       o.Write (FormatType (mi.ReturnType));
+                       o.Write (" ");
+               }
+
                o.Write (mi.Name);
+#if NET_2_0
+               o.Write (FormatGenericParams (mi.GetGenericArguments ()));
+#endif
                o.Write (" (");
                OutlineParams (mi.GetParameters ());
-               o.Write (");");
+               o.Write (")");
+#if NET_2_0
+               WriteGenericConstraints (mi.GetGenericArguments ());
+#endif
+               o.Write (";");
        }
        
        void OutlineOperator (MethodInfo mi)
@@ -315,14 +434,24 @@ public class Outline {
                if (fi.IsFamily)   o.Write ("protected ");
                if (fi.IsPrivate)  o.Write ("private ");
                if (fi.IsAssembly) o.Write ("internal ");
-               if (fi.IsLiteral) o.Write ("const ");
+               if (fi.IsLiteral)  o.Write ("const ");
+               else if (fi.IsStatic) o.Write ("static ");
+               if (fi.IsInitOnly) o.Write ("readonly ");
+
                o.Write (FormatType (fi.FieldType));
                o.Write (" ");
                o.Write (fi.Name);
-               if (fi.IsLiteral)
-               {
+               if (fi.IsLiteral) { 
+                       object v = fi.GetValue (this);
+
+                       // TODO: Escape values here
                        o.Write (" = ");
-                       o.Write (fi.GetValue (this));
+                       if (v is char)
+                               o.Write ("'{0}'", v);
+                       else if (v is string)
+                               o.Write ("\"{0}\"", v);
+                       else
+                               o.Write (fi.GetValue (this));
                }
                o.Write (";");
        }
@@ -345,13 +474,38 @@ public class Outline {
        {
                if (method.IsStatic)
                        return "static ";
-       
+
+               if (method.IsFinal) {
+                       // This will happen if you have
+                       // class X : IA {
+                       //   public void A () {}
+                       //   static void Main () {}
+                       // }
+                       // interface IA {
+                       //   void A ();
+                       // }
+                       //
+                       // A needs to be virtual (the CLR requires
+                       // methods implementing an iface be virtual),
+                       // but can not be inherited. It also can not
+                       // be inherited. In C# this is represented
+                       // with no special modifiers
+
+                       if (method.IsVirtual)
+                               return null;
+                       return "sealed ";
+               }
+               
                // all interface methods are "virtual" but we don't say that in c#
-               if (method.IsVirtual && !method.DeclaringType.IsInterface)
+               if (method.IsVirtual && !method.DeclaringType.IsInterface) {
+                       if (method.IsAbstract)
+                               return "abstract ";
+
                        return ((method.Attributes & MethodAttributes.NewSlot) != 0) ?
                                "virtual " :
-                               "override ";
-               
+                               "override ";    
+               }
+                               
                return null;
        }
 
@@ -388,10 +542,28 @@ public class Outline {
                         return "internal";
                 }
        }
+
+       string FormatGenericParams (Type [] args)
+       {
+               StringBuilder sb = new StringBuilder ();
+               if (args.Length == 0)
+                       return "";
+               
+               sb.Append ("<");
+               for (int i = 0; i < args.Length; i++) {
+                       if (i > 0)
+                               sb.Append (",");
+                       sb.Append (FormatType (args [i]));
+               }
+               sb.Append (">");
+               return sb.ToString ();
+       }
        
+       // TODO: fine tune this so that our output is less verbose. We need to figure
+       // out a way to do this while not making things confusing.
        string FormatType (Type t)
        {
-               string type = t.FullName;
+               string type = GetFullName (t);
                
                if (!type.StartsWith ("System.")) {
                        if (t.Namespace == this.t.Namespace)
@@ -433,10 +605,148 @@ public class Outline {
        
                if (type.LastIndexOf(".") == 6)
                        return type.Substring(7);
-               
+
+               //
+               // If the namespace of the type is the namespace of what
+               // we are printing (or is a member of one if its children
+               // don't print it. This basically means that in C# we would
+               // automatically get the namespace imported by virtue of the
+               // namespace {} block.
+               //      
+               if (this.t.Namespace.StartsWith (t.Namespace + ".") || t.Namespace == this.t.Namespace)
+                       return type.Substring (t.Namespace.Length + 1);
+       
                return type;
        }
 
+       public static string RemoveGenericArity (string name)
+       {
+               int start = 0;
+               StringBuilder sb = new StringBuilder ();
+               while (start < name.Length) {
+                       int pos = name.IndexOf ('`', start);
+                       if (pos < 0) {
+                               sb.Append (name.Substring (start));
+                               break;
+                       }
+                       sb.Append (name.Substring (start, pos-start));
+
+                       pos++;
+
+                       while ((pos < name.Length) && Char.IsNumber (name [pos]))
+                               pos++;
+
+                       start = pos;
+               }
+
+               return sb.ToString ();
+       }
+
+       string GetTypeName (Type t)
+       {
+               StringBuilder sb = new StringBuilder ();
+               GetTypeName (sb, t);
+               return sb.ToString ();
+       }
+
+       void GetTypeName (StringBuilder sb, Type t)
+       {
+               sb.Append (RemoveGenericArity (t.Name));
+#if NET_2_0
+               sb.Append (FormatGenericParams (t.GetGenericArguments ()));
+#endif
+       }
+
+       string GetFullName (Type t)
+       {
+               StringBuilder sb = new StringBuilder ();
+               GetFullName_recursed (sb, t, false);
+               return sb.ToString ();
+       }
+
+       void GetFullName_recursed (StringBuilder sb, Type t, bool recursed)
+       {
+#if NET_2_0
+               if (t.IsGenericParameter) {
+                       sb.Append (t.Name);
+                       return;
+               }
+#endif
+
+               if (t.DeclaringType != null) {
+                       GetFullName_recursed (sb, t.DeclaringType, true);
+                       sb.Append (".");
+               }
+
+               if (!recursed) {
+                       string ns = t.Namespace;
+                       if ((ns != null) && (ns != "")) {
+                               sb.Append (ns);
+                               sb.Append (".");
+                       }
+               }
+
+               GetTypeName (sb, t);
+       }
+
+#if NET_2_0
+       void WriteGenericConstraints (Type [] args)
+       {
+
+               foreach (Type t in args) {
+                       bool first = true;
+                       Type[] ifaces = TypeGetInterfaces (t, true);
+                       
+                       GenericParameterAttributes attrs = t.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
+                       GenericParameterAttributes [] interesting = {
+                               GenericParameterAttributes.ReferenceTypeConstraint,
+                               GenericParameterAttributes.NotNullableValueTypeConstraint,
+                               GenericParameterAttributes.DefaultConstructorConstraint
+                       };
+                       
+                       if (t.BaseType != typeof (object) || ifaces.Length != 0 || attrs != 0) {
+                               o.Write (" where ");
+                               o.Write (FormatType (t));
+                               o.Write (" : ");
+                       }
+
+                       if (t.BaseType != typeof (object)) {
+                               o.Write (FormatType (t.BaseType));
+                               first = false;
+                       }
+
+                       foreach (Type iface in ifaces) {
+                               if (!first)
+                                       o.Write (", ");
+                               first = false;
+                               
+                               o.Write (FormatType (iface));
+                       }
+
+                       foreach (GenericParameterAttributes a in interesting) {
+                               if ((attrs & a) == 0)
+                                       continue;
+                               
+                               if (!first)
+                                       o.Write (", ");
+                               first = false;
+                               
+                               switch (a) {
+                               case GenericParameterAttributes.ReferenceTypeConstraint:
+                                       o.Write ("class");
+                                       break;
+                               case GenericParameterAttributes.NotNullableValueTypeConstraint:
+                                       o.Write ("struct");
+                                       break;
+                               case GenericParameterAttributes.DefaultConstructorConstraint:
+                                       o.Write ("new ()");
+                                       break;
+                               }
+                       }
+               }
+       }
+#endif
        string OperatorFromName (string name)
        {
                switch (name) {
@@ -467,6 +777,98 @@ public class Outline {
                default: return name;
                }
        }
+
+       bool MethodIsExplicitIfaceImpl (MethodBase mb)
+       {
+               if (!(mb.IsFinal && mb.IsVirtual && mb.IsPrivate))
+                       return false;
+               
+               // UGH msft has no way to get the info about what method is
+               // getting overriden. Another reason to use cecil :-)
+               //
+               //MethodInfo mi = mb as MethodInfo;
+               //if (mi == null)
+               //      return false;
+               //
+               //Console.WriteLine (mi.GetBaseDefinition ().DeclaringType);
+               //return mi.GetBaseDefinition ().DeclaringType.IsInterface;
+               
+               // So, we guess that virtual final private methods only come
+               // from ifaces :-)
+               return true;
+       }
+       
+       bool ShowMember (MemberInfo mi)
+       {
+               if (mi.MemberType == MemberTypes.Constructor && ((MethodBase) mi).IsStatic)
+                       return false;
+               
+               if (options.ShowPrivate)
+                       return true;
+
+               if (options.FilterObsolete && mi.IsDefined (typeof (ObsoleteAttribute), false))
+                       return false;
+               
+               switch (mi.MemberType) {
+               case MemberTypes.Constructor:
+               case MemberTypes.Method:
+                       MethodBase mb = mi as MethodBase;
+               
+                       if (mb.IsFamily || mb.IsPublic || mb.IsFamilyOrAssembly)
+                               return true;
+                       
+                       if (MethodIsExplicitIfaceImpl (mb))
+                               return true;
+                                       
+                       return false;
+               
+               
+               case MemberTypes.Field:
+                       FieldInfo fi = mi as FieldInfo;
+               
+                       if (fi.IsFamily || fi.IsPublic || fi.IsFamilyOrAssembly)
+                               return true;
+                       
+                       return false;
+               
+               
+               case MemberTypes.NestedType:
+               case MemberTypes.TypeInfo:
+                       Type t = mi as Type;
+               
+                       switch (t.Attributes & TypeAttributes.VisibilityMask){
+                       case TypeAttributes.Public:
+                       case TypeAttributes.NestedPublic:
+                       case TypeAttributes.NestedFamily:
+                       case TypeAttributes.NestedFamORAssem:
+                               return true;
+                       }
+                       
+                       return false;
+               }
+               
+               // What am I !!!
+               return true;
+       }
+
+       static Type [] TypeGetInterfaces (Type t, bool declonly)
+       {
+               Type [] ifaces = t.GetInterfaces ();
+               if (! declonly)
+                       return ifaces;
+
+               // Handle Object. Also, optimize for no interfaces
+               if (t.BaseType == null || ifaces.Length == 0)
+                       return ifaces;
+
+               ArrayList ar = new ArrayList ();
+
+               foreach (Type i in ifaces)
+                       if (! i.IsAssignableFrom (t.BaseType))
+                               ar.Add (i);
+
+               return (Type []) ar.ToArray (typeof (Type));
+       }
 }
 
 public class Comparer : IComparer  {
@@ -520,9 +922,27 @@ public class Comparer : IComparer  {
        {
                MethodBase aa = (MethodBase) a, bb = (MethodBase) b;
                
-               if (aa.IsStatic == bb.IsStatic)
-                       return CompareMemberInfo (a, b);
-               
+               if (aa.IsStatic == bb.IsStatic) {
+                       int c = CompareMemberInfo (a, b);
+                       if (c != 0)
+                               return c;
+                       ParameterInfo [] ap, bp;
+
+                       //
+                       // Sort overloads by the names of their types
+                       // put methods with fewer params first.
+                       //
+                       
+                       ap = aa.GetParameters ();
+                       bp = bb.GetParameters ();
+                       int n = Math.Min (ap.Length, bp.Length);
+
+                       for (int i = 0; i < n; i ++)
+                               if ((c = CompareType (ap [i].ParameterType, bp [i].ParameterType)) != 0)
+                                       return c;
+
+                       return ap.Length.CompareTo (bp.Length);
+               }
                if (aa.IsStatic)
                        return -1;