2 // mono-api-info.cs - Dumps public assembly information to an xml file.
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Copyright (C) 2003-2008 Novell, Inc (http://www.novell.com)
11 using System.Collections;
12 using System.Collections.Generic;
13 using System.Globalization;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
29 public static int Main (string [] args)
36 AssemblyCollection acoll = new AssemblyCollection ();
38 string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
39 string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
40 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
42 foreach (string arg in args) {
48 if (arg.Contains ("v3.0")) {
49 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
50 } else if (arg.Contains ("v3.5")) {
51 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
52 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
53 } else if (arg.Contains ("v4.0")) {
54 if (arg.Contains ("Silverlight")) {
55 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
57 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
58 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
61 TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
66 XmlDocument doc = new XmlDocument ();
70 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
71 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
72 doc.InsertBefore (decl, doc.DocumentElement);
77 internal static bool AbiMode { get; private set; }
82 public static string CleanupTypeName (TypeReference type)
84 return CleanupTypeName (type.FullName);
87 public static string CleanupTypeName (string t)
89 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
93 class AssemblyCollection
96 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
98 public AssemblyCollection ()
102 public bool Add (string name)
104 AssemblyDefinition ass = LoadAssembly (name);
106 Console.Error.WriteLine ("Cannot load assembly file " + name);
110 assemblies.Add (ass);
114 public void DoOutput ()
116 if (document == null)
117 throw new InvalidOperationException ("Document not set");
119 XmlNode nassemblies = document.CreateElement ("assemblies", null);
120 document.AppendChild (nassemblies);
121 foreach (AssemblyDefinition a in assemblies) {
122 AssemblyData data = new AssemblyData (document, nassemblies, a);
127 public XmlDocument Document {
128 set { document = value; }
131 AssemblyDefinition LoadAssembly (string assembly)
134 if (File.Exists (assembly))
135 return TypeHelper.Resolver.ResolveFile (assembly);
137 return TypeHelper.Resolver.Resolve (assembly);
138 } catch (Exception e) {
139 Console.WriteLine (e);
145 abstract class BaseData
147 protected XmlDocument document;
148 protected XmlNode parent;
150 protected BaseData (XmlDocument doc, XmlNode parent)
153 this.parent = parent;
156 public abstract void DoOutput ();
158 protected void AddAttribute (XmlNode node, string name, string value)
160 XmlAttribute attr = document.CreateAttribute (name);
162 node.Attributes.Append (attr);
166 class TypeForwardedToData : BaseData
168 AssemblyDefinition ass;
170 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
171 : base (document, parent)
176 public override void DoOutput ()
178 XmlNode natts = parent.SelectSingleNode("attributes");
180 natts = document.CreateElement ("attributes", null);
181 parent.AppendChild (natts);
184 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
186 if (((uint)type.Attributes & 0x200000u) == 0)
189 XmlNode node = document.CreateElement ("attribute");
190 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
191 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
192 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
193 AddAttribute (property, "name", "Destination");
194 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
195 natts.AppendChild (node);
199 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
201 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
206 class AssemblyData : BaseData
208 AssemblyDefinition ass;
210 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
211 : base (document, parent)
216 public override void DoOutput ()
218 if (document == null)
219 throw new InvalidOperationException ("Document not set");
221 XmlNode nassembly = document.CreateElement ("assembly", null);
222 AssemblyNameDefinition aname = ass.Name;
223 AddAttribute (nassembly, "name", aname.Name);
224 AddAttribute (nassembly, "version", aname.Version.ToString ());
225 parent.AppendChild (nassembly);
226 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
227 AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
228 var typesCollection = ass.MainModule.Types;
229 if (typesCollection == null || typesCollection.Count == 0)
231 object [] typesArray = new object [typesCollection.Count];
232 for (int i = 0; i < typesCollection.Count; i++) {
233 typesArray [i] = typesCollection [i];
235 Array.Sort (typesArray, TypeReferenceComparer.Default);
237 XmlNode nss = document.CreateElement ("namespaces", null);
238 nassembly.AppendChild (nss);
240 string current_namespace = "$%&$&";
242 XmlNode classes = null;
243 foreach (TypeDefinition t in typesArray) {
244 if (string.IsNullOrEmpty (t.Namespace))
247 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
250 if (t.DeclaringType != null)
251 continue; // enforce !nested
253 if (t.Namespace != current_namespace) {
254 current_namespace = t.Namespace;
255 ns = document.CreateElement ("namespace", null);
256 AddAttribute (ns, "name", current_namespace);
257 nss.AppendChild (ns);
258 classes = document.CreateElement ("classes", null);
259 ns.AppendChild (classes);
262 TypeData bd = new TypeData (document, classes, t);
268 abstract class MemberData : BaseData
270 MemberReference [] members;
272 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
273 : base (document, parent)
275 this.members = members;
278 public override void DoOutput ()
280 XmlNode mclass = document.CreateElement (ParentTag, null);
281 parent.AppendChild (mclass);
283 foreach (MemberReference member in members) {
284 XmlNode mnode = document.CreateElement (Tag, null);
285 mclass.AppendChild (mnode);
286 AddAttribute (mnode, "name", GetName (member));
287 if (!NoMemberAttributes)
288 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
290 AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
292 AddExtraData (mnode, member);
297 protected abstract IList<CustomAttribute> GetCustomAttributes (MemberReference member);
299 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
303 protected virtual string GetName (MemberReference memberDefenition)
308 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
313 public virtual bool NoMemberAttributes {
314 get { return false; }
318 public virtual string ParentTag {
319 get { return "NoPARENTTAG"; }
322 public virtual string Tag {
323 get { return "NoTAG"; }
326 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
328 if (provider.GenericParameters.Count == 0)
331 var gparameters = provider.GenericParameters;
333 XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
334 nclass.AppendChild (ngeneric);
336 foreach (GenericParameter gp in gparameters) {
337 XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
338 nparam.SetAttribute ("name", gp.Name);
339 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
341 AttributeData.OutputAttributes (document, nparam, gp.CustomAttributes);
343 ngeneric.AppendChild (nparam);
345 var constraints = gp.Constraints;
346 if (constraints.Count == 0)
349 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
351 foreach (TypeReference constraint in constraints) {
352 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
353 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
354 nconstraint.AppendChild (ncons);
357 nparam.AppendChild (nconstraint);
362 class TypeData : MemberData
366 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
367 : base (document, parent, null)
372 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
373 return ((TypeDefinition) member).CustomAttributes;
376 public override void DoOutput ()
378 if (document == null)
379 throw new InvalidOperationException ("Document not set");
381 XmlNode nclass = document.CreateElement ("class", null);
382 AddAttribute (nclass, "name", type.Name);
383 string classType = GetClassType (type);
384 AddAttribute (nclass, "type", classType);
386 if (type.BaseType != null)
387 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
390 AddAttribute (nclass, "sealed", "true");
393 AddAttribute (nclass, "abstract", "true");
395 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
396 AddAttribute (nclass, "serializable", "true");
398 string charSet = GetCharSet (type);
399 AddAttribute (nclass, "charset", charSet);
401 string layout = GetLayout (type);
403 AddAttribute (nclass, "layout", layout);
405 if (type.PackingSize >= 0) {
406 AddAttribute (nclass, "pack", type.PackingSize.ToString ());
409 if (type.ClassSize >= 0) {
410 AddAttribute (nclass, "size", type.ClassSize.ToString ());
413 parent.AppendChild (nclass);
415 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
417 XmlNode ifaces = null;
419 foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) {
420 if (!TypeHelper.IsPublic (iface))
421 // we're only interested in public interfaces
424 if (ifaces == null) {
425 ifaces = document.CreateElement ("interfaces", null);
426 nclass.AppendChild (ifaces);
429 XmlNode iface_node = document.CreateElement ("interface", null);
430 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
431 ifaces.AppendChild (iface_node);
434 MemberData.OutputGenericParameters (document, nclass, type);
436 ArrayList members = new ArrayList ();
438 FieldDefinition [] fields = GetFields (type);
439 if (fields.Length > 0) {
440 Array.Sort (fields, MemberReferenceComparer.Default);
441 FieldData fd = new FieldData (document, nclass, fields);
446 var value_type = GetEnumValueField (type);
447 if (value_type == null)
448 throw new NotSupportedException ();
450 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
453 if (!Driver.AbiMode) {
455 MethodDefinition [] ctors = GetConstructors (type);
456 if (ctors.Length > 0) {
457 Array.Sort (ctors, MemberReferenceComparer.Default);
458 members.Add (new ConstructorData (document, nclass, ctors));
461 PropertyDefinition[] properties = GetProperties (type);
462 if (properties.Length > 0) {
463 Array.Sort (properties, MemberReferenceComparer.Default);
464 members.Add (new PropertyData (document, nclass, properties));
467 EventDefinition [] events = GetEvents (type);
468 if (events.Length > 0) {
469 Array.Sort (events, MemberReferenceComparer.Default);
470 members.Add (new EventData (document, nclass, events));
473 MethodDefinition [] methods = GetMethods (type);
474 if (methods.Length > 0) {
475 Array.Sort (methods, MethodDefinitionComparer.Default);
476 members.Add (new MethodData (document, nclass, methods));
480 foreach (MemberData md in members)
483 var nested = type.NestedTypes;
484 //remove non public(familiy) and nested in second degree
485 for (int i = nested.Count - 1; i >= 0; i--) {
486 TypeDefinition t = nested [i];
487 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
488 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
489 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
491 if (t.DeclaringType == type)
492 continue; // not nested of nested
499 if (nested.Count > 0) {
500 XmlNode classes = document.CreateElement ("classes", null);
501 nclass.AppendChild (classes);
502 foreach (TypeDefinition t in nested) {
503 TypeData td = new TypeData (document, classes, t);
509 static FieldReference GetEnumValueField (TypeDefinition type)
511 foreach (FieldDefinition field in type.Fields)
512 if (field.IsSpecialName && field.Name == "value__")
518 protected override string GetMemberAttributes (MemberReference member)
521 throw new InvalidOperationException ("odd");
523 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
526 public static bool MustDocumentMethod (MethodDefinition method) {
528 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
529 return maskedAccess == MethodAttributes.Public
530 || maskedAccess == MethodAttributes.Family
531 || maskedAccess == MethodAttributes.FamORAssem;
534 static string GetClassType (TypeDefinition t)
545 if (TypeHelper.IsDelegate(t))
554 static string GetCharSet (TypeDefinition type)
556 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
557 if (maskedStringFormat == TypeAttributes.AnsiClass)
558 return CharSet.Ansi.ToString ();
560 if (maskedStringFormat == TypeAttributes.AutoClass)
561 return CharSet.Auto.ToString ();
563 if (maskedStringFormat == TypeAttributes.UnicodeClass)
564 return CharSet.Unicode.ToString ();
566 return CharSet.None.ToString ();
569 static string GetLayout (TypeDefinition type)
571 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
572 if (maskedLayout == TypeAttributes.AutoLayout)
573 return LayoutKind.Auto.ToString ();
575 if (maskedLayout == TypeAttributes.ExplicitLayout)
576 return LayoutKind.Explicit.ToString ();
578 if (maskedLayout == TypeAttributes.SequentialLayout)
579 return LayoutKind.Sequential.ToString ();
584 FieldDefinition [] GetFields (TypeDefinition type) {
585 ArrayList list = new ArrayList ();
587 var fields = type.Fields;
588 foreach (FieldDefinition field in fields) {
589 if (field.IsSpecialName)
592 if (Driver.AbiMode && field.IsStatic)
595 // we're only interested in public or protected members
596 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
597 if (Driver.AbiMode && !field.IsNotSerialized) {
600 if (maskedVisibility == FieldAttributes.Public
601 || maskedVisibility == FieldAttributes.Family
602 || maskedVisibility == FieldAttributes.FamORAssem) {
608 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
612 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
613 ArrayList list = new ArrayList ();
615 var properties = type.Properties;//type.GetProperties (flags);
616 foreach (PropertyDefinition property in properties) {
617 MethodDefinition getMethod = property.GetMethod;
618 MethodDefinition setMethod = property.SetMethod;
620 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
621 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
623 // if neither the getter or setter should be documented, then
625 if (hasGetter || hasSetter) {
630 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
633 private MethodDefinition[] GetMethods (TypeDefinition type)
635 ArrayList list = new ArrayList ();
637 var methods = type.Methods;//type.GetMethods (flags);
638 foreach (MethodDefinition method in methods) {
639 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
642 // we're only interested in public or protected members
643 if (!MustDocumentMethod(method))
646 if (IsFinalizer (method)) {
647 string name = method.DeclaringType.Name;
648 int arity = name.IndexOf ('`');
650 name = name.Substring (0, arity);
652 method.Name = "~" + name;
658 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
661 static bool IsFinalizer (MethodDefinition method)
663 if (method.Name != "Finalize")
666 if (!method.IsVirtual)
669 if (method.Parameters.Count != 0)
675 private MethodDefinition [] GetConstructors (TypeDefinition type)
677 ArrayList list = new ArrayList ();
679 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
680 foreach (MethodDefinition constructor in ctors) {
681 // we're only interested in public or protected members
682 if (!MustDocumentMethod(constructor))
685 list.Add (constructor);
688 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
691 private EventDefinition[] GetEvents (TypeDefinition type)
693 ArrayList list = new ArrayList ();
695 var events = type.Events;//type.GetEvents (flags);
696 foreach (EventDefinition eventDef in events) {
697 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
699 if (addMethod == null || !MustDocumentMethod (addMethod))
705 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
709 class FieldData : MemberData
711 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
712 : base (document, parent, members)
716 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
717 return ((FieldDefinition) member).CustomAttributes;
720 protected override string GetName (MemberReference memberDefenition)
722 FieldDefinition field = (FieldDefinition) memberDefenition;
726 protected override string GetMemberAttributes (MemberReference memberDefenition)
728 FieldDefinition field = (FieldDefinition) memberDefenition;
729 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
732 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
734 base.AddExtraData (p, memberDefenition);
735 FieldDefinition field = (FieldDefinition) memberDefenition;
736 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
738 if (field.IsLiteral) {
739 object value = field.Constant;//object value = field.GetValue (null);
740 string stringValue = null;
741 //if (value is Enum) {
742 // // FIXME: when Mono bug #60090 has been
743 // // fixed, we should just be able to use
744 // // Convert.ToString
745 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
748 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
751 if (stringValue != null)
752 AddAttribute (p, "value", stringValue);
756 public override string ParentTag {
757 get { return "fields"; }
760 public override string Tag {
761 get { return "field"; }
765 class PropertyData : MemberData
767 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
768 : base (document, parent, members)
772 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
773 return ((PropertyDefinition) member).CustomAttributes;
776 protected override string GetName (MemberReference memberDefenition)
778 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
782 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
784 base.AddExtraData (p, memberDefenition);
785 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
786 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
787 MethodDefinition _get = prop.GetMethod;
788 MethodDefinition _set = prop.SetMethod;
789 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
790 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
791 MethodDefinition [] methods;
793 if (haveGet && haveSet) {
794 methods = new MethodDefinition [] { _get, _set };
795 } else if (haveGet) {
796 methods = new MethodDefinition [] { _get };
797 } else if (haveSet) {
798 methods = new MethodDefinition [] { _set };
804 if (haveGet || _set.Parameters.Count > 1) {
805 string parms = Parameters.GetSignature (methods [0].Parameters);
806 if (!string.IsNullOrEmpty (parms))
807 AddAttribute (p, "params", parms);
810 MethodData data = new MethodData (document, p, methods);
811 //data.NoMemberAttributes = true;
815 protected override string GetMemberAttributes (MemberReference memberDefenition)
817 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
818 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
821 public override string ParentTag {
822 get { return "properties"; }
825 public override string Tag {
826 get { return "property"; }
830 class EventData : MemberData
832 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
833 : base (document, parent, members)
837 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
838 return ((EventDefinition) member).CustomAttributes;
841 protected override string GetName (MemberReference memberDefenition)
843 EventDefinition evt = (EventDefinition) memberDefenition;
847 protected override string GetMemberAttributes (MemberReference memberDefenition)
849 EventDefinition evt = (EventDefinition) memberDefenition;
850 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
853 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
855 base.AddExtraData (p, memberDefenition);
856 EventDefinition evt = (EventDefinition) memberDefenition;
857 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
860 public override string ParentTag {
861 get { return "events"; }
864 public override string Tag {
865 get { return "event"; }
869 class MethodData : MemberData
873 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
874 : base (document, parent, members)
878 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
879 return ((MethodDefinition) member).CustomAttributes;
882 protected override string GetName (MemberReference memberDefenition)
884 MethodDefinition method = (MethodDefinition) memberDefenition;
885 string name = method.Name;
886 string parms = Parameters.GetSignature (method.Parameters);
888 return string.Format ("{0}({1})", name, parms);
891 protected override string GetMemberAttributes (MemberReference memberDefenition)
893 MethodDefinition method = (MethodDefinition) memberDefenition;
894 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
897 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
899 base.AddExtraData (p, memberDefenition);
901 if (!(memberDefenition is MethodDefinition))
904 MethodDefinition mbase = (MethodDefinition) memberDefenition;
906 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
909 if (mbase.IsAbstract)
910 AddAttribute (p, "abstract", "true");
912 AddAttribute (p, "virtual", "true");
913 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
914 AddAttribute (p, "sealed", "true");
916 AddAttribute (p, "static", "true");
918 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
919 if (rettype != "System.Void" || !mbase.IsConstructor)
920 AddAttribute (p, "returntype", (rettype));
922 AttributeData.OutputAttributes (document, p, mbase.MethodReturnType.CustomAttributes);
924 MemberData.OutputGenericParameters (document, p, mbase);
927 public override bool NoMemberAttributes {
928 get { return noAtts; }
929 set { noAtts = value; }
932 public override string ParentTag {
933 get { return "methods"; }
936 public override string Tag {
937 get { return "method"; }
941 class ConstructorData : MethodData
943 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
944 : base (document, parent, members)
948 public override string ParentTag {
949 get { return "constructors"; }
952 public override string Tag {
953 get { return "constructor"; }
957 class ParameterData : BaseData
959 private IList<ParameterDefinition> parameters;
961 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
962 : base (document, parent)
964 this.parameters = parameters;
967 public override void DoOutput ()
969 XmlNode parametersNode = document.CreateElement ("parameters");
970 parent.AppendChild (parametersNode);
972 foreach (ParameterDefinition parameter in parameters) {
973 XmlNode paramNode = document.CreateElement ("parameter");
974 parametersNode.AppendChild (paramNode);
975 AddAttribute (paramNode, "name", parameter.Name);
976 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
977 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
979 string direction = "in";
981 if (parameter.ParameterType is ByReferenceType)
982 direction = parameter.IsOut ? "out" : "ref";
984 TypeReference t = parameter.ParameterType;
985 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
987 if (parameter.IsOptional) {
988 AddAttribute (paramNode, "optional", "true");
989 if (parameter.HasConstant)
990 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
993 if (direction != "in")
994 AddAttribute (paramNode, "direction", direction);
996 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
1001 class AttributeData : BaseData
1003 IList<CustomAttribute> atts;
1005 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1006 : base (doc, parent)
1011 public override void DoOutput ()
1013 if (document == null)
1014 throw new InvalidOperationException ("Document not set");
1016 if (atts == null || atts.Count == 0)
1019 XmlNode natts = parent.SelectSingleNode("attributes");
1020 if (natts == null) {
1021 natts = document.CreateElement ("attributes", null);
1022 parent.AppendChild (natts);
1025 for (int i = 0; i < atts.Count; ++i) {
1026 CustomAttribute att = atts [i];
1028 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1029 if (SkipAttribute (att))
1032 XmlNode node = document.CreateElement ("attribute");
1033 AddAttribute (node, "name", attName);
1035 XmlNode properties = null;
1037 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
1039 foreach (string name in attribute_mapping.Keys) {
1040 if (name == "TypeId")
1043 if (properties == null) {
1044 properties = node.AppendChild (document.CreateElement ("properties"));
1047 object o = attribute_mapping [name];
1049 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1050 AddAttribute (n, "name", name);
1053 AddAttribute (n, "value", "null");
1057 string value = o.ToString ();
1058 if (attName.EndsWith ("GuidAttribute"))
1059 value = value.ToUpper ();
1060 AddAttribute (n, "value", value);
1063 natts.AppendChild (node);
1067 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1069 var mapping = new Dictionary<string, object> ();
1071 PopulateMapping (mapping, attribute);
1073 var constructor = attribute.Constructor.Resolve ();
1074 if (constructor == null || constructor.Parameters.Count == 0)
1077 PopulateMapping (mapping, constructor, attribute);
1082 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1084 foreach (var named_argument in attribute.Properties) {
1085 var name = named_argument.Name;
1086 var arg = named_argument.Argument;
1088 if (arg.Value is CustomAttributeArgument)
1089 arg = (CustomAttributeArgument) arg.Value;
1091 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1095 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1097 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1099 int? argument = null;
1101 foreach (Instruction instruction in constructor.Body.Instructions) {
1102 switch (instruction.OpCode.Code) {
1114 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1118 FieldReference field = (FieldReference) instruction.Operand;
1119 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1122 if (!argument.HasValue)
1125 if (!field_mapping.ContainsKey (field))
1126 field_mapping.Add (field, (int) argument - 1);
1133 return field_mapping;
1136 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1138 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1140 foreach (PropertyDefinition property in type.Properties) {
1141 if (property.GetMethod == null)
1143 if (!property.GetMethod.HasBody)
1146 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1147 if (instruction.OpCode.Code != Code.Ldfld)
1150 FieldReference field = (FieldReference) instruction.Operand;
1151 if (field.DeclaringType.FullName != type.FullName)
1154 property_mapping.Add (property, field);
1159 return property_mapping;
1162 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1164 if (!constructor.HasBody)
1167 // Custom handling for attributes with arguments which cannot be easily extracted
1168 var ca = attribute.ConstructorArguments;
1169 switch (constructor.DeclaringType.FullName) {
1170 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1171 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1172 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1173 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1175 mapping.Add ("Value", dca.Value);
1177 case "System.ComponentModel.BindableAttribute":
1181 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1182 mapping.Add ("Bindable", ca[0].Value);
1184 throw new NotImplementedException ();
1190 var field_mapping = CreateArgumentFieldMapping (constructor);
1191 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1193 foreach (var pair in property_mapping) {
1195 if (!field_mapping.TryGetValue (pair.Value, out argument))
1198 var ca_arg = ca [argument];
1199 if (ca_arg.Value is CustomAttributeArgument)
1200 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1202 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1206 static object GetArgumentValue (TypeReference reference, object value)
1208 var type = reference.Resolve ();
1213 if (IsFlaggedEnum (type))
1214 return GetFlaggedEnumValue (type, value);
1216 return GetEnumValue (type, value);
1222 static bool IsFlaggedEnum (TypeDefinition type)
1227 if (type.CustomAttributes.Count == 0)
1230 foreach (CustomAttribute attribute in type.CustomAttributes)
1231 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1237 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1240 return GetFlaggedEnumValue (type, (ulong)value);
1242 long flags = Convert.ToInt64 (value);
1243 var signature = new StringBuilder ();
1245 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1246 FieldDefinition field = type.Fields [i];
1248 if (!field.HasConstant)
1251 long flag = Convert.ToInt64 (field.Constant);
1256 if ((flags & flag) == flag) {
1257 if (signature.Length != 0)
1258 signature.Append (", ");
1260 signature.Append (field.Name);
1265 return signature.ToString ();
1268 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1270 var signature = new StringBuilder ();
1272 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1273 FieldDefinition field = type.Fields [i];
1275 if (!field.HasConstant)
1278 ulong flag = Convert.ToUInt64 (field.Constant);
1283 if ((flags & flag) == flag) {
1284 if (signature.Length != 0)
1285 signature.Append (", ");
1287 signature.Append (field.Name);
1292 return signature.ToString ();
1295 static object GetEnumValue (TypeDefinition type, object value)
1297 foreach (FieldDefinition field in type.Fields) {
1298 if (!field.HasConstant)
1301 if (Comparer.Default.Compare (field.Constant, value) == 0)
1308 static bool SkipAttribute (CustomAttribute attribute)
1310 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1312 return !TypeHelper.IsPublic (attribute)
1313 || type_name.EndsWith ("TODOAttribute");
1316 public static void OutputAttributes (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1318 AttributeData ad = new AttributeData (doc, parent, attributes);
1323 static class Parameters {
1325 public static string GetSignature (IList<ParameterDefinition> infos)
1327 if (infos == null || infos.Count == 0)
1330 var signature = new StringBuilder ();
1331 for (int i = 0; i < infos.Count; i++) {
1334 signature.Append (", ");
1336 ParameterDefinition info = infos [i];
1339 if ((info.Attributes & ParameterAttributes.In) != 0)
1341 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1344 modifier = string.Empty;
1346 if (modifier.Length > 0)
1347 signature.AppendFormat ("{0} ", modifier);
1349 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1352 return signature.ToString ();
1357 class TypeReferenceComparer : IComparer
1359 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1361 public int Compare (object a, object b)
1363 TypeReference ta = (TypeReference) a;
1364 TypeReference tb = (TypeReference) b;
1365 int result = String.Compare (ta.Namespace, tb.Namespace);
1369 return String.Compare (ta.Name, tb.Name);
1373 class MemberReferenceComparer : IComparer
1375 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1377 public int Compare (object a, object b)
1379 MemberReference ma = (MemberReference) a;
1380 MemberReference mb = (MemberReference) b;
1381 return String.Compare (ma.Name, mb.Name);
1385 class MethodDefinitionComparer : IComparer
1387 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1389 public int Compare (object a, object b)
1391 MethodDefinition ma = (MethodDefinition) a;
1392 MethodDefinition mb = (MethodDefinition) b;
1393 int res = String.Compare (ma.Name, mb.Name);
1397 IList<ParameterDefinition> pia = ma.Parameters ;
1398 IList<ParameterDefinition> pib = mb.Parameters;
1399 res = pia.Count - pib.Count;
1403 string siga = Parameters.GetSignature (pia);
1404 string sigb = Parameters.GetSignature (pib);
1405 return String.Compare (siga, sigb);