2 // mono-api-info.cs - Dumps public assembly information to an xml file.
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2003 Novell, Inc (http://www.novell.com)
11 using System.Collections;
12 using System.Reflection;
16 namespace Mono.AssemblyInfo
20 static int Main (string [] args)
25 AssemblyCollection acoll = new AssemblyCollection ();
27 foreach (string fullName in args) {
31 XmlDocument doc = new XmlDocument ();
35 XmlTextWriter writer = new XmlTextWriter (Console.Out);
36 writer.Formatting = Formatting.Indented;
37 XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
38 doc.InsertBefore (decl, doc.DocumentElement);
44 class AssemblyCollection
49 public AssemblyCollection ()
51 assemblies = new ArrayList ();
54 public bool Add (string name)
56 Assembly ass = LoadAssembly (name);
64 public void DoOutput ()
67 throw new InvalidOperationException ("Document not set");
69 XmlNode nassemblies = document.CreateElement ("assemblies", null);
70 document.AppendChild (nassemblies);
71 foreach (Assembly a in assemblies) {
72 AssemblyData data = new AssemblyData (document, nassemblies, a);
77 public XmlDocument Document {
78 set { document = value; }
81 static Assembly LoadAssembly (string aname)
86 if (!name.EndsWith (".dll"))
88 ass = Assembly.LoadFrom (name);
93 ass = Assembly.LoadWithPartialName (aname);
101 abstract class BaseData
103 protected XmlDocument document;
104 protected XmlNode parent;
106 protected BaseData (XmlDocument doc, XmlNode parent)
109 this.parent = parent;
112 public abstract void DoOutput ();
114 protected void AddAttribute (XmlNode node, string name, string value)
116 XmlAttribute attr = document.CreateAttribute (name);
118 node.Attributes.Append (attr);
122 class AssemblyData : BaseData
126 public AssemblyData (XmlDocument document, XmlNode parent, Assembly ass)
127 : base (document, parent)
132 public override void DoOutput ()
134 if (document == null)
135 throw new InvalidOperationException ("Document not set");
137 XmlNode nassembly = document.CreateElement ("assembly", null);
138 AssemblyName aname = ass.GetName ();
139 AddAttribute (nassembly, "name", aname.Name);
140 AddAttribute (nassembly, "version", aname.Version.ToString ());
141 parent.AppendChild (nassembly);
142 AttributeData.OutputAttributes (document, nassembly, ass.GetCustomAttributes (false));
143 Type [] types = ass.GetTypes ();
144 if (types == null || types.Length == 0)
147 Array.Sort (types, TypeComparer.Default);
149 XmlNode nss = document.CreateElement ("namespaces", null);
150 nassembly.AppendChild (nss);
152 string currentNS = "$%&$&";
154 XmlNode classes = null;
155 foreach (Type t in types) {
156 if (t.Namespace == null || t.Namespace == "")
162 if (t.IsNestedPublic || t.IsNestedAssembly || t.IsNestedFamANDAssem ||
163 t.IsNestedFamORAssem || t.IsNestedPrivate)
166 if (t.DeclaringType != null)
167 continue; // enforce !nested
169 if (t.Namespace != currentNS) {
170 currentNS = t.Namespace;
171 ns = document.CreateElement ("namespace", null);
172 AddAttribute (ns, "name", currentNS);
173 nss.AppendChild (ns);
174 classes = document.CreateElement ("classes", null);
175 ns.AppendChild (classes);
178 TypeData bd = new TypeData (document, classes, t);
184 abstract class MemberData : BaseData
186 MemberInfo [] members;
188 public MemberData (XmlDocument document, XmlNode parent, MemberInfo [] members)
189 : base (document, parent)
191 this.members = members;
194 public override void DoOutput ()
196 XmlNode mclass = document.CreateElement (ParentTag, null);
197 parent.AppendChild (mclass);
199 foreach (MemberInfo member in members) {
200 XmlNode mnode = document.CreateElement (Tag, null);
201 mclass.AppendChild (mnode);
202 AddAttribute (mnode, "name", GetName (member));
203 if (!NoMemberAttributes)
204 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
206 AttributeData.OutputAttributes (document, mnode,
207 member.GetCustomAttributes (false));
209 AddExtraData (mnode, member);
213 protected virtual void AddExtraData (XmlNode p, MemberInfo member)
217 protected virtual string GetName (MemberInfo member)
222 protected virtual string GetMemberAttributes (MemberInfo member)
227 public virtual bool NoMemberAttributes {
228 get { return false; }
232 public virtual string ParentTag {
233 get { return "NoPARENTTAG"; }
236 public virtual string Tag {
237 get { return "NoTAG"; }
241 class TypeData : MemberData
244 const BindingFlags flags = BindingFlags.Public | BindingFlags.Static |
245 BindingFlags.Instance | BindingFlags.DeclaredOnly |
246 BindingFlags.NonPublic;
248 public TypeData (XmlDocument document, XmlNode parent, Type type)
249 : base (document, parent, null)
254 public override void DoOutput ()
256 if (document == null)
257 throw new InvalidOperationException ("Document not set");
259 XmlNode nclass = document.CreateElement ("class", null);
260 AddAttribute (nclass, "name", type.Name);
261 string classType = GetClassType (type);
262 AddAttribute (nclass, "type", classType);
263 if (type.BaseType != null)
264 AddAttribute (nclass, "base", type.BaseType.FullName);
267 AddAttribute (nclass, "sealed", "true");
269 parent.AppendChild (nclass);
271 AttributeData.OutputAttributes (document, nclass, type.GetCustomAttributes (false));
273 Type [] interfaces = type.GetInterfaces ();
274 if (interfaces != null && interfaces.Length > 0) {
275 XmlNode ifaces = document.CreateElement ("interfaces", null);
276 nclass.AppendChild (ifaces);
277 foreach (Type t in interfaces) {
279 // we're only interested in public interfaces
282 XmlNode iface = document.CreateElement ("interface", null);
283 AddAttribute (iface, "name", t.FullName);
284 ifaces.AppendChild (iface);
288 ArrayList members = new ArrayList ();
290 FieldInfo[] fields = GetFields (type);
291 if (fields.Length > 0) {
292 Array.Sort (fields, MemberInfoComparer.Default);
293 FieldData fd = new FieldData (document, nclass, fields);
294 // Special case for enum fields
295 if (classType == "enum") {
296 string etype = fields [0].GetType ().FullName;
297 AddAttribute (nclass, "enumtype", etype);
302 ConstructorInfo [] ctors = GetConstructors (type);
303 if (ctors.Length > 0) {
304 Array.Sort (ctors, MemberInfoComparer.Default);
305 members.Add (new ConstructorData (document, nclass, ctors));
308 PropertyInfo[] properties = GetProperties (type);
309 if (properties.Length > 0) {
310 Array.Sort (properties, MemberInfoComparer.Default);
311 members.Add (new PropertyData (document, nclass, properties));
314 EventInfo [] events = GetEvents (type);
315 if (events.Length > 0) {
316 Array.Sort (events, MemberInfoComparer.Default);
317 members.Add (new EventData (document, nclass, events));
320 MethodInfo [] methods = GetMethods (type);
321 if (methods.Length > 0) {
322 Array.Sort (methods, MemberInfoComparer.Default);
323 members.Add (new MethodData (document, nclass, methods));
326 foreach (MemberData md in members)
329 Type [] nested = type.GetNestedTypes ();
330 if (nested != null && nested.Length > 0) {
331 XmlNode classes = document.CreateElement ("classes", null);
332 nclass.AppendChild (classes);
333 foreach (Type t in nested) {
334 TypeData td = new TypeData (document, classes, t);
340 protected override string GetMemberAttributes (MemberInfo member)
343 throw new InvalidOperationException ("odd");
345 return ((int) type.Attributes).ToString ();
348 public static bool MustDocumentMethod(MethodBase method)
351 return (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly);
354 static string GetClassType (Type t)
365 if (typeof (Delegate).IsAssignableFrom (t))
371 private FieldInfo[] GetFields (Type type)
373 ArrayList list = new ArrayList ();
375 FieldInfo[] fields = type.GetFields (flags);
376 foreach (FieldInfo field in fields) {
377 if (field.IsSpecialName)
380 // we're only interested in public or protected members
381 if (!field.IsPublic && !field.IsFamily && !field.IsFamilyOrAssembly)
387 return (FieldInfo[]) list.ToArray (typeof (FieldInfo));
390 private PropertyInfo[] GetProperties (Type type)
392 ArrayList list = new ArrayList ();
394 PropertyInfo[] properties = type.GetProperties (flags);
395 foreach (PropertyInfo property in properties) {
396 MethodInfo getMethod = null;
397 MethodInfo setMethod = null;
399 if (property.CanRead) {
400 try { getMethod = property.GetGetMethod (true); }
401 catch (System.Security.SecurityException) { }
403 if (property.CanWrite) {
404 try { setMethod = property.GetSetMethod (true); }
405 catch (System.Security.SecurityException) { }
408 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
409 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
411 // if neither the getter or setter should be documented, then
413 if (!hasGetter && !hasSetter) {
420 return (PropertyInfo[]) list.ToArray (typeof (PropertyInfo));
423 private MethodInfo[] GetMethods (Type type)
425 ArrayList list = new ArrayList ();
427 MethodInfo[] methods = type.GetMethods (flags);
428 foreach (MethodInfo method in methods) {
429 if (method.IsSpecialName)
432 // we're only interested in public or protected members
433 if (!MustDocumentMethod(method))
439 return (MethodInfo[]) list.ToArray (typeof (MethodInfo));
442 private ConstructorInfo[] GetConstructors (Type type)
444 ArrayList list = new ArrayList ();
446 ConstructorInfo[] ctors = type.GetConstructors (flags);
447 foreach (ConstructorInfo constructor in ctors) {
448 // we're only interested in public or protected members
449 if (!constructor.IsPublic && !constructor.IsFamily && !constructor.IsFamilyOrAssembly)
452 list.Add (constructor);
455 return (ConstructorInfo[]) list.ToArray (typeof (ConstructorInfo));
458 private EventInfo[] GetEvents (Type type)
460 ArrayList list = new ArrayList ();
462 EventInfo[] events = type.GetEvents (flags);
463 foreach (EventInfo eventInfo in events) {
464 MethodInfo addMethod = eventInfo.GetAddMethod (true);
466 if (addMethod == null || !MustDocumentMethod (addMethod))
469 list.Add (eventInfo);
472 return (EventInfo[]) list.ToArray (typeof (EventInfo));
476 class FieldData : MemberData
478 public FieldData (XmlDocument document, XmlNode parent, FieldInfo [] members)
479 : base (document, parent, members)
483 protected override string GetName (MemberInfo member)
485 FieldInfo field = (FieldInfo) member;
489 protected override string GetMemberAttributes (MemberInfo member)
491 FieldInfo field = (FieldInfo) member;
492 return ((int) field.Attributes).ToString ();
495 protected override void AddExtraData (XmlNode p, MemberInfo member)
497 base.AddExtraData (p, member);
498 FieldInfo field = (FieldInfo) member;
499 AddAttribute (p, "fieldtype", field.FieldType.FullName);
502 public override string ParentTag {
503 get { return "fields"; }
506 public override string Tag {
507 get { return "field"; }
511 class PropertyData : MemberData
513 public PropertyData (XmlDocument document, XmlNode parent, PropertyInfo [] members)
514 : base (document, parent, members)
518 protected override string GetName (MemberInfo member)
520 PropertyInfo prop = (PropertyInfo) member;
524 protected override void AddExtraData (XmlNode p, MemberInfo member)
526 base.AddExtraData (p, member);
527 PropertyInfo prop = (PropertyInfo) member;
528 AddAttribute (p, "ptype", prop.PropertyType.FullName);
529 MethodInfo _get = prop.GetGetMethod (true);
530 MethodInfo _set = prop.GetSetMethod (true);
531 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
532 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
533 MethodInfo [] methods;
535 if (haveGet && haveSet) {
536 methods = new MethodInfo [] {_get, _set};
537 } else if (haveGet) {
538 methods = new MethodInfo [] {_get};
539 } else if (haveSet) {
540 methods = new MethodInfo [] {_set};
546 string parms = Parameters.GetSignature (methods [0].GetParameters ());
547 AddAttribute (p, "params", parms);
549 MethodData data = new MethodData (document, p, methods);
550 data.NoMemberAttributes = true;
554 protected override string GetMemberAttributes (MemberInfo member)
556 PropertyInfo prop = (PropertyInfo) member;
557 return ((int) prop.Attributes).ToString ();
560 public override string ParentTag {
561 get { return "properties"; }
564 public override string Tag {
565 get { return "property"; }
569 class EventData : MemberData
571 public EventData (XmlDocument document, XmlNode parent, EventInfo [] members)
572 : base (document, parent, members)
576 protected override string GetName (MemberInfo member)
578 EventInfo evt = (EventInfo) member;
582 protected override string GetMemberAttributes (MemberInfo member)
584 EventInfo evt = (EventInfo) member;
585 return ((int) evt.Attributes).ToString ();
588 protected override void AddExtraData (XmlNode p, MemberInfo member)
590 base.AddExtraData (p, member);
591 EventInfo evt = (EventInfo) member;
592 AddAttribute (p, "eventtype", evt.EventHandlerType.FullName);
595 public override string ParentTag {
596 get { return "events"; }
599 public override string Tag {
600 get { return "event"; }
604 class MethodData : MemberData
608 public MethodData (XmlDocument document, XmlNode parent, MethodBase [] members)
609 : base (document, parent, members)
613 protected override string GetName (MemberInfo member)
615 MethodBase method = (MethodBase) member;
616 string name = method.Name;
617 string parms = Parameters.GetSignature (method.GetParameters ());
618 return String.Format ("{0}({1})", name, parms);
621 protected override string GetMemberAttributes (MemberInfo member)
623 MethodBase method = (MethodBase) member;
624 return ((int) method.Attributes).ToString ();
627 protected override void AddExtraData (XmlNode p, MemberInfo member)
629 base.AddExtraData (p, member);
630 if (!(member is MethodInfo))
633 MethodInfo method = (MethodInfo) member;
634 AddAttribute (p, "returntype", method.ReturnType.FullName);
637 public override bool NoMemberAttributes {
638 get { return noAtts; }
639 set { noAtts = value; }
642 public override string ParentTag {
643 get { return "methods"; }
646 public override string Tag {
647 get { return "method"; }
651 class ConstructorData : MethodData
653 public ConstructorData (XmlDocument document, XmlNode parent, ConstructorInfo [] members)
654 : base (document, parent, members)
658 public override string ParentTag {
659 get { return "constructors"; }
662 public override string Tag {
663 get { return "constructor"; }
667 class AttributeData : BaseData
671 AttributeData (XmlDocument doc, XmlNode parent, object [] attributes)
674 this.atts = attributes;
677 public override void DoOutput ()
679 if (document == null)
680 throw new InvalidOperationException ("Document not set");
682 if (atts == null || atts.Length == 0)
685 XmlNode natts = document.CreateElement ("attributes", null);
686 parent.AppendChild (natts);
688 ArrayList typeList = new ArrayList (atts.Length);
689 string comment = null;
690 for (int i = atts.Length - 1; i >= 0; i--) {
691 Type attType = atts [i].GetType ();
692 if (!MustDocumentAttribute (attType))
694 typeList.Add (attType);
695 if (attType.Name.EndsWith ("TODOAttribute")) {
696 PropertyInfo prop = attType.GetProperty ("Comment");
698 comment = (string) prop.GetValue (atts [i], null);
702 Type[] types = (Type[]) typeList.ToArray (typeof (Type));
703 Array.Sort (types, TypeComparer.Default);
704 foreach (Type t in types) {
705 XmlNode node = document.CreateElement ("attribute");
706 AddAttribute (node, "name", t.FullName);
707 if (comment != null && t.Name.EndsWith ("TODOAttribute"))
708 AddAttribute (node, "comment", comment);
710 natts.AppendChild (node);
714 public static void OutputAttributes (XmlDocument doc, XmlNode parent, object [] attributes)
716 AttributeData ad = new AttributeData (doc, parent, attributes);
720 private static bool MustDocumentAttribute (Type attributeType)
722 // only document public attributes
723 return attributeType.IsPublic;
729 private Parameters () {}
731 public static string GetSignature (ParameterInfo [] infos)
733 if (infos == null || infos.Length == 0)
736 StringBuilder sb = new StringBuilder ();
737 foreach (ParameterInfo info in infos) {
741 else if (info.IsRetval)
748 //TODO: parameter attributes
750 string type_name = info.ParameterType.ToString ();
751 sb.AppendFormat ("{0}{1}, ", modifier, type_name);
754 sb.Length -= 2; // remove ", "
755 return sb.ToString ();
760 class TypeComparer : IComparer
762 public static TypeComparer Default = new TypeComparer ();
764 public int Compare (object a, object b)
768 int result = String.Compare (ta.Namespace, tb.Namespace);
772 return String.Compare (ta.Name, tb.Name);
776 class MemberInfoComparer : IComparer
778 public static MemberInfoComparer Default = new MemberInfoComparer ();
780 public int Compare (object a, object b)
782 MemberInfo ma = (MemberInfo) a;
783 MemberInfo mb = (MemberInfo) b;
784 return String.Compare (ma.Name, mb.Name);
788 class MethodBaseComparer : IComparer
790 public static MethodBaseComparer Default = new MethodBaseComparer ();
792 public int Compare (object a, object b)
794 MethodBase ma = (MethodBase) a;
795 MethodBase mb = (MethodBase) b;
796 int res = String.Compare (ma.Name, mb.Name);
800 ParameterInfo [] pia = ma.GetParameters ();
801 ParameterInfo [] pib = mb.GetParameters ();
802 if (pia.Length != pib.Length)
803 return pia.Length - pib.Length;
805 string siga = Parameters.GetSignature (pia);
806 string sigb = Parameters.GetSignature (pib);
807 return String.Compare (siga, sigb);