merging the Mainsoft branch to the trunk
[mono.git] / mcs / tools / corcompare / mono-api-info.cs
index b6e04c1a9bb57cc2210f088f387caf888b37eea3..67a773f5d47b1cdab0212d23f01759a95b8db4b2 100644 (file)
@@ -1,15 +1,18 @@
 //
-// ainfo.cs
+// mono-api-info.cs - Dumps public assembly information to an xml file.
 //
 // Authors:
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)
 //
-// (C) 2003 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2003-2005 Novell, Inc (http://www.novell.com)
 //
 
 using System;
 using System.Collections;
+using System.Globalization;
 using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
 using System.Text;
 using System.Xml;
 
@@ -140,7 +143,7 @@ namespace Mono.AssemblyInfo
                        AddAttribute (nassembly, "version", aname.Version.ToString ());
                        parent.AppendChild (nassembly);
                        AttributeData.OutputAttributes (document, nassembly, ass.GetCustomAttributes (false));
-                       Type [] types = ass.GetTypes ();
+                       Type [] types = ass.GetExportedTypes ();
                        if (types == null || types.Length == 0)
                                return;
 
@@ -160,9 +163,12 @@ namespace Mono.AssemblyInfo
                                        continue;
 
                                if (t.IsNestedPublic || t.IsNestedAssembly || t.IsNestedFamANDAssem ||
-                                   t.IsNestedFamORAssem || t.IsNestedPrivate)
+                                       t.IsNestedFamORAssem || t.IsNestedPrivate)
                                        continue;
 
+                               if (t.DeclaringType != null)
+                                       continue; // enforce !nested
+                               
                                if (t.Namespace != currentNS) {
                                        currentNS = t.Namespace;
                                        ns = document.CreateElement ("namespace", null);
@@ -234,12 +240,13 @@ namespace Mono.AssemblyInfo
                        get { return "NoTAG"; }
                }
        }
-       
+
        class TypeData : MemberData
        {
                Type type;
                const BindingFlags flags = BindingFlags.Public | BindingFlags.Static |
-                                          BindingFlags.Instance | BindingFlags.DeclaredOnly;
+                                               BindingFlags.Instance | BindingFlags.DeclaredOnly | 
+                                               BindingFlags.NonPublic;
                
                public TypeData (XmlDocument document, XmlNode parent, Type type)
                        : base (document, parent, null)
@@ -256,12 +263,26 @@ namespace Mono.AssemblyInfo
                        AddAttribute (nclass, "name", type.Name);
                        string classType = GetClassType (type);
                        AddAttribute (nclass, "type", classType);
+
                        if (type.BaseType != null)
                                AddAttribute (nclass, "base", type.BaseType.FullName);
 
                        if (type.IsSealed)
                                AddAttribute (nclass, "sealed", "true");
 
+                       if (type.IsAbstract)
+                               AddAttribute (nclass, "abstract", "true");
+
+                       if (type.IsSerializable)
+                               AddAttribute (nclass, "serializable", "true");
+
+                       string charSet = GetCharSet (type);
+                       AddAttribute (nclass, "charset", charSet);
+
+                       string layout = GetLayout (type);
+                       if (layout != null)
+                               AddAttribute (nclass, "layout", layout);
+
                        parent.AppendChild (nclass);
                        
                        AttributeData.OutputAttributes (document, nclass, type.GetCustomAttributes (false));
@@ -271,6 +292,10 @@ namespace Mono.AssemblyInfo
                                XmlNode ifaces = document.CreateElement ("interfaces", null);
                                nclass.AppendChild (ifaces);
                                foreach (Type t in interfaces) {
+                                       if (!t.IsPublic) {
+                                               // we're only interested in public interfaces
+                                               continue;
+                                       }
                                        XmlNode iface = document.CreateElement ("interface", null);
                                        AddAttribute (iface, "name", t.FullName);
                                        ifaces.AppendChild (iface);
@@ -279,59 +304,40 @@ namespace Mono.AssemblyInfo
 
                        ArrayList members = new ArrayList ();
 
-                       FieldInfo [] fields = type.GetFields (flags);
-                       if (fields != null && fields.Length > 0) {
-                               fields = FieldRemoveSpecials (fields);
-                               if (fields != null) {
-                                       Array.Sort (fields, MemberInfoComparer.Default);
-                                       FieldData fd = new FieldData (document, nclass, fields);
-                                       // Special case for enum fields
-                                       if (classType == "enum") {
-                                               string etype = fields [0].GetType ().FullName;
-                                               AddAttribute (nclass, "enumtype", etype);
-                                       }
-
-                                       members.Add (fd);
+                       FieldInfo[] fields = GetFields (type);
+                       if (fields.Length > 0) {
+                               Array.Sort (fields, MemberInfoComparer.Default);
+                               FieldData fd = new FieldData (document, nclass, fields);
+                               // Special case for enum fields
+                               if (classType == "enum") {
+                                       string etype = fields [0].GetType ().FullName;
+                                       AddAttribute (nclass, "enumtype", etype);
                                }
+                               members.Add (fd);
                        }
 
-                       ConstructorInfo [] ctors = type.GetConstructors (flags);
-                       ConstructorInfo [] cctor = type.GetConstructors (BindingFlags.NonPublic |
-                                                                        BindingFlags.Static);
-
-                       ArrayList allctors = new ArrayList ();
-                       if (ctors != null)
-                               allctors.AddRange (ctors);
-
-                       if (cctor != null)
-                               allctors.AddRange (cctor);
-       
-                       if (allctors.Count > 0) {
-                               ConstructorInfo [] all;
-                               all = (ConstructorInfo []) allctors.ToArray (typeof (ConstructorInfo));
-                               Array.Sort (all, MethodBaseComparer.Default);
-                               members.Add (new ConstructorData (document, nclass, all));
+                       ConstructorInfo [] ctors = GetConstructors (type);
+                       if (ctors.Length > 0) {
+                               Array.Sort (ctors, MemberInfoComparer.Default);
+                               members.Add (new ConstructorData (document, nclass, ctors));
                        }
 
-                       PropertyInfo [] props = type.GetProperties (flags);
-                       if (props != null && props.Length > 0) {
-                               Array.Sort (props, MemberInfoComparer.Default);
-                               members.Add (new PropertyData (document, nclass, props));
+                       PropertyInfo[] properties = GetProperties (type);
+                       if (properties.Length > 0) {
+                               Array.Sort (properties, MemberInfoComparer.Default);
+                               members.Add (new PropertyData (document, nclass, properties));
                        }
 
-                       EventInfo [] events = type.GetEvents (flags);
-                       if (events != null && events.Length > 0) {
+                       EventInfo [] events = GetEvents (type);
+                       if (events.Length > 0) {
                                Array.Sort (events, MemberInfoComparer.Default);
                                members.Add (new EventData (document, nclass, events));
                        }
 
-                       MethodInfo [] methods = type.GetMethods (flags);
-                       if (methods != null && methods.Length > 0) {
-                               methods = MethodRemoveSpecials (methods);
-                               if (methods != null) {
-                                       Array.Sort (methods, MethodBaseComparer.Default);
-                                       members.Add (new MethodData (document, nclass, methods));
-                               }
+                       MethodInfo [] methods = GetMethods (type);
+                       if (methods.Length > 0) {
+                               Array.Sort (methods, MemberInfoComparer.Default);
+                               members.Add (new MethodData (document, nclass, methods));
                        }
 
                        foreach (MemberData md in members)
@@ -353,62 +359,162 @@ namespace Mono.AssemblyInfo
                        if (member != type)
                                throw new InvalidOperationException ("odd");
                                
-                       return ((int) type.Attributes).ToString ();
+                       return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
                }
 
-               static MethodInfo [] MethodRemoveSpecials (MethodInfo [] methods)
+               public static bool MustDocumentMethod(MethodBase method)
                {
-                       ArrayList list = null;
-                       foreach (MethodInfo method in methods) {
-                               if (method.IsSpecialName)
-                                       continue;
+                       // All other methods
+                       return (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly);
+               }
+
+               static string GetClassType (Type t)
+               {
+                       if (t.IsEnum)
+                               return "enum";
 
-                               if (list == null)
-                                       list = new ArrayList ();
+                       if (t.IsValueType)
+                               return "struct";
 
-                               list.Add (method);
-                       }
+                       if (t.IsInterface)
+                               return "interface";
+
+                       if (typeof (Delegate).IsAssignableFrom (t))
+                               return "delegate";
+
+                       return "class";
+               }
+
+               private static string GetCharSet (Type type)
+               {
+                       if (type.IsAnsiClass)
+                               return CharSet.Ansi.ToString (CultureInfo.InvariantCulture);
+
+                       if (type.IsAutoClass)
+                               return CharSet.Auto.ToString (CultureInfo.InvariantCulture);
+
+                       if (type.IsUnicodeClass)
+                               return CharSet.Unicode.ToString (CultureInfo.InvariantCulture);
 
-                       if (list == null)
-                               return null;
+                       return CharSet.None.ToString (CultureInfo.InvariantCulture);
+               }
+
+               private static string GetLayout (Type type)
+               {
+                       if (type.IsAutoLayout)
+                               return LayoutKind.Auto.ToString (CultureInfo.InvariantCulture);
+
+                       if (type.IsExplicitLayout)
+                               return LayoutKind.Explicit.ToString (CultureInfo.InvariantCulture);
+
+                       if (type.IsLayoutSequential)
+                               return LayoutKind.Sequential.ToString (CultureInfo.InvariantCulture);
 
-                       return (MethodInfo []) list.ToArray (typeof (MethodInfo));
+                       return null;
                }
 
-               static FieldInfo [] FieldRemoveSpecials (FieldInfo [] fields)
+               private FieldInfo[] GetFields (Type type)
                {
-                       ArrayList list = null;
+                       ArrayList list = new ArrayList ();
+
+                       FieldInfo[] fields = type.GetFields (flags);
                        foreach (FieldInfo field in fields) {
                                if (field.IsSpecialName)
                                        continue;
 
-                               if (list == null)
-                                       list = new ArrayList ();
+                               // we're only interested in public or protected members
+                               if (!field.IsPublic && !field.IsFamily && !field.IsFamilyOrAssembly)
+                                       continue;
 
                                list.Add (field);
                        }
 
-                       if (list == null)
-                               return null;
+                       return (FieldInfo[]) list.ToArray (typeof (FieldInfo));
+               }
+
+               internal static PropertyInfo[] GetProperties (Type type)
+               {
+                       ArrayList list = new ArrayList ();
+
+                       PropertyInfo[] properties = type.GetProperties (flags);
+                       foreach (PropertyInfo property in properties) {
+                               MethodInfo getMethod = null;
+                               MethodInfo setMethod = null;
+
+                               if (property.CanRead) {
+                                       try { getMethod = property.GetGetMethod (true); }
+                                       catch (System.Security.SecurityException) { }
+                               }
+                               if (property.CanWrite) {
+                                       try { setMethod = property.GetSetMethod (true); }
+                                       catch (System.Security.SecurityException) { }
+                               }
+
+                               bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
+                               bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
+
+                               // if neither the getter or setter should be documented, then
+                               // skip the property
+                               if (!hasGetter && !hasSetter) {
+                                       continue;
+                               }
+
+                               list.Add (property);
+                       }
 
-                       return (FieldInfo []) list.ToArray (typeof (FieldInfo));
+                       return (PropertyInfo[]) list.ToArray (typeof (PropertyInfo));
                }
 
-               static string GetClassType (Type t)
+               private MethodInfo[] GetMethods (Type type)
                {
-                       if (t.IsEnum)
-                               return "enum";
+                       ArrayList list = new ArrayList ();
 
-                       if (t.IsValueType)
-                               return "struct";
+                       MethodInfo[] methods = type.GetMethods (flags);
+                       foreach (MethodInfo method in methods) {
+                               if (method.IsSpecialName)
+                                       continue;
 
-                       if (t.IsInterface)
-                               return "interface";
+                               // we're only interested in public or protected members
+                               if (!MustDocumentMethod(method))
+                                       continue;
 
-                       if (typeof (Delegate).IsAssignableFrom (t))
-                               return "delegate";
+                               list.Add (method);
+                       }
 
-                       return "class";
+                       return (MethodInfo[]) list.ToArray (typeof (MethodInfo));
+               }
+
+               private ConstructorInfo[] GetConstructors (Type type)
+               {
+                       ArrayList list = new ArrayList ();
+
+                       ConstructorInfo[] ctors = type.GetConstructors (flags);
+                       foreach (ConstructorInfo constructor in ctors) {
+                               // we're only interested in public or protected members
+                               if (!constructor.IsPublic && !constructor.IsFamily && !constructor.IsFamilyOrAssembly)
+                                       continue;
+
+                               list.Add (constructor);
+                       }
+
+                       return (ConstructorInfo[]) list.ToArray (typeof (ConstructorInfo));
+               }
+
+               private EventInfo[] GetEvents (Type type)
+               {
+                       ArrayList list = new ArrayList ();
+
+                       EventInfo[] events = type.GetEvents (flags);
+                       foreach (EventInfo eventInfo in events) {
+                               MethodInfo addMethod = eventInfo.GetAddMethod (true);
+
+                               if (addMethod == null || !MustDocumentMethod (addMethod))
+                                       continue;
+
+                               list.Add (eventInfo);
+                       }
+
+                       return (EventInfo[]) list.ToArray (typeof (EventInfo));
                }
        }
 
@@ -428,7 +534,7 @@ namespace Mono.AssemblyInfo
                protected override string GetMemberAttributes (MemberInfo member)
                {
                        FieldInfo field = (FieldInfo) member;
-                       return ((int) field.Attributes).ToString ();
+                       return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
                }
 
                protected override void AddExtraData (XmlNode p, MemberInfo member)
@@ -436,6 +542,22 @@ namespace Mono.AssemblyInfo
                        base.AddExtraData (p, member);
                        FieldInfo field = (FieldInfo) member;
                        AddAttribute (p, "fieldtype", field.FieldType.FullName);
+
+                       if (field.IsLiteral) {
+                               object value = field.GetValue (null);
+                               string stringValue = null;
+                               if (value is Enum) {
+                                       // FIXME: when Mono bug #60090 has been
+                                       // fixed, we should just be able to use
+                                       // Convert.ToString
+                                       stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
+                               } else {
+                                       stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
+                               }
+
+                               if (stringValue != null)
+                                       AddAttribute (p, "value", stringValue);
+                       }
                }
 
                public override string ParentTag {
@@ -464,11 +586,13 @@ namespace Mono.AssemblyInfo
                {
                        base.AddExtraData (p, member);
                        PropertyInfo prop = (PropertyInfo) member;
-                       MethodInfo _get = prop.GetGetMethod ();
-                       MethodInfo _set = prop.GetSetMethod ();
-                       bool haveGet = (_get != null);
-                       bool haveSet = (_set != null);
+                       AddAttribute (p, "ptype", prop.PropertyType.FullName);
+                       MethodInfo _get = prop.GetGetMethod (true);
+                       MethodInfo _set = prop.GetSetMethod (true);
+                       bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
+                       bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
                        MethodInfo [] methods;
+
                        if (haveGet && haveSet) {
                                methods = new MethodInfo [] {_get, _set};
                        } else if (haveGet) {
@@ -480,6 +604,9 @@ namespace Mono.AssemblyInfo
                                return;
                        }
 
+                       string parms = Parameters.GetSignature (methods [0].GetParameters ());
+                       AddAttribute (p, "params", parms);
+
                        MethodData data = new MethodData (document, p, methods);
                        data.NoMemberAttributes = true;
                        data.DoOutput ();
@@ -488,7 +615,7 @@ namespace Mono.AssemblyInfo
                protected override string GetMemberAttributes (MemberInfo member)
                {
                        PropertyInfo prop = (PropertyInfo) member;
-                       return ((int) prop.Attributes).ToString ();
+                       return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
                }
 
                public override string ParentTag {
@@ -516,7 +643,7 @@ namespace Mono.AssemblyInfo
                protected override string GetMemberAttributes (MemberInfo member)
                {
                        EventInfo evt = (EventInfo) member;
-                       return ((int) evt.Attributes).ToString ();
+                       return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
                }
 
                protected override void AddExtraData (XmlNode p, MemberInfo member)
@@ -555,17 +682,25 @@ namespace Mono.AssemblyInfo
                protected override string GetMemberAttributes (MemberInfo member)
                {
                        MethodBase method = (MethodBase) member;
-                       return ((int) method.Attributes).ToString ();
+                       return ((int) method.Attributes).ToString (CultureInfo.InvariantCulture);
                }
 
                protected override void AddExtraData (XmlNode p, MemberInfo member)
                {
                        base.AddExtraData (p, member);
+
+                       ParameterData parms = new ParameterData (document, p, 
+                               ((MethodBase) member).GetParameters ());
+                       parms.DoOutput ();
+
                        if (!(member is MethodInfo))
                                return;
-                               
+
                        MethodInfo method = (MethodInfo) member;
                        AddAttribute (p, "returntype", method.ReturnType.FullName);
+
+                       AttributeData.OutputAttributes (document, p,
+                               method.ReturnTypeCustomAttributes.GetCustomAttributes (false));
                }
 
                public override bool NoMemberAttributes {
@@ -598,14 +733,66 @@ namespace Mono.AssemblyInfo
                }
        }
 
+       class ParameterData : BaseData
+       {
+               private ParameterInfo[] parameters;
+
+               public ParameterData (XmlDocument document, XmlNode parent, ParameterInfo[] parameters)
+                       : base (document, parent)
+               {
+                       this.parameters = parameters;
+               }
+
+               public override void DoOutput ()
+               {
+                       XmlNode parametersNode = document.CreateElement ("parameters", null);
+                       parent.AppendChild (parametersNode);
+
+                       foreach (ParameterInfo parameter in parameters) {
+                               XmlNode paramNode = document.CreateElement ("parameter", null);
+                               parametersNode.AppendChild (paramNode);
+                               AddAttribute (paramNode, "name", parameter.Name);
+                               AddAttribute (paramNode, "position", parameter.Position.ToString(CultureInfo.InvariantCulture));
+                               AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
+
+                               string direction = "in";
+
+                               if (parameter.ParameterType.IsByRef) {
+                                       direction = parameter.IsOut ? "out" : "ref";
+                               }
+
+                               Type t = parameter.ParameterType;
+                               AddAttribute (paramNode, "type", t.FullName);
+
+                               if (parameter.IsOptional) {
+                                       AddAttribute (paramNode, "optional", "true");
+                                       if (parameter.DefaultValue != System.DBNull.Value)
+                                               AddAttribute (paramNode, "defaultValue", (parameter.DefaultValue == null) ? "NULL" : parameter.DefaultValue.ToString ());
+                               }
+
+                               if (direction != "in")
+                                       AddAttribute (paramNode, "direction", direction);
+
+                               AttributeData.OutputAttributes (document, paramNode, parameter.GetCustomAttributes (false));
+                       }
+               }
+       }
+
        class AttributeData : BaseData
        {
                object [] atts;
+               string target;
 
-               AttributeData (XmlDocument doc, XmlNode parent, object [] attributes)
+               AttributeData (XmlDocument doc, XmlNode parent, object[] attributes, string target)
                        : base (doc, parent)
                {
-                       this.atts = attributes;
+                       atts = attributes;
+                       this.target = target;
+               }
+
+               AttributeData (XmlDocument doc, XmlNode parent, object [] attributes)
+                       : this (doc, parent, attributes, null)
+               {
                }
 
                public override void DoOutput ()
@@ -616,26 +803,83 @@ namespace Mono.AssemblyInfo
                        if (atts == null || atts.Length == 0)
                                return;
 
-                       XmlNode natts = document.CreateElement ("attributes", null);
-                       parent.AppendChild (natts);
+                       XmlNode natts = parent.SelectSingleNode("attributes");
+                       if (natts == null) {
+                               natts = document.CreateElement ("attributes", null);
+                               parent.AppendChild (natts);
+                       }
 
-                       Type [] types = new Type [atts.Length];
-                       for (int i = atts.Length - 1; i >= 0; i--)
-                               types [i] = atts [i].GetType ();
+                       for (int i = 0; i < atts.Length; ++i) {
+                               Type t = atts [i].GetType ();
+                               if (!t.IsPublic && !t.Name.EndsWith ("TODOAttribute"))
+                                       continue;
+
+                               // we ignore attributes that inherit from SecurityAttribute on purpose as they:
+                               // * aren't part of GetCustomAttributes in Fx 1.0/1.1;
+                               // * are encoded differently and in a different metadata table; and
+                               // * won't ever exactly match MS implementation (from a syntax pov)
+                               if (t.IsSubclassOf (typeof (SecurityAttribute)))
+                                       continue;
 
-                       Array.Sort (types, TypeComparer.Default);
-                       foreach (Type t in types) {
                                XmlNode node = document.CreateElement ("attribute");
                                AddAttribute (node, "name", t.FullName);
+
+                               XmlNode properties = null;
+                               foreach (PropertyInfo pi in TypeData.GetProperties (t)) {
+                                       if (pi.Name == "TypeId")
+                                               continue;
+
+                                       if (properties == null) {
+                                               properties = node.AppendChild (document.CreateElement ("properties"));
+                                       }
+
+                                       try {
+                                               object o = pi.GetValue (atts [i], null);
+
+                                               XmlNode n = properties.AppendChild (document.CreateElement ("property"));
+                                               AddAttribute (n, "name", pi.Name);
+
+                                               if (o == null) {
+                                                       AddAttribute (n, "null", "true");
+                                                       continue;
+                                               }
+
+                                               string value = o.ToString ();
+                                               if (t == typeof (GuidAttribute))
+                                                       value = value.ToUpper ();
+
+                                               AddAttribute (n, "value", value);
+                                       }
+                                       catch (TargetInvocationException) {
+                                               continue;
+                                       }
+                               }
+
+                               if (target != null) {
+                                       AddAttribute (node, "target", target);
+                               }
+
                                natts.AppendChild (node);
                        }
                }
 
-               public static void OutputAttributes (XmlDocument doc, XmlNode parent, object [] attributes)
+               public static void OutputAttributes (XmlDocument doc, XmlNode parent, object[] attributes)
+               {
+                       AttributeData ad = new AttributeData (doc, parent, attributes, null);
+                       ad.DoOutput ();
+               }
+
+               public static void OutputAttributes (XmlDocument doc, XmlNode parent, object [] attributes, string target)
                {
-                       AttributeData ad = new AttributeData (doc, parent, attributes);
+                       AttributeData ad = new AttributeData (doc, parent, attributes, target);
                        ad.DoOutput ();
                }
+
+               private static bool MustDocumentAttribute (Type attributeType)
+               {
+                       // only document MonoTODOAttribute and public attributes
+                       return attributeType.Name.EndsWith ("TODOAttribute") || attributeType.IsPublic;
+               }
        }
 
        class Parameters
@@ -659,8 +903,6 @@ namespace Mono.AssemblyInfo
                                else
                                        modifier = "";
 
-                               //TODO: parameter attributes
-                               
                                string type_name = info.ParameterType.ToString ();
                                sb.AppendFormat ("{0}{1}, ", modifier, type_name);
                        }