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;
28 public static int Main (string [] args)
35 AssemblyCollection acoll = new AssemblyCollection ();
37 foreach (string arg in args) {
44 XmlDocument doc = new XmlDocument ();
48 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
49 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
50 doc.InsertBefore (decl, doc.DocumentElement);
55 internal static bool AbiMode { get; private set; }
60 public static string CleanupTypeName (TypeReference type)
62 return CleanupTypeName (type.FullName);
65 public static string CleanupTypeName (string t)
67 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
71 class AssemblyCollection
74 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
76 public AssemblyCollection ()
80 public bool Add (string name)
82 AssemblyDefinition ass = LoadAssembly (name);
90 public void DoOutput ()
93 throw new InvalidOperationException ("Document not set");
95 XmlNode nassemblies = document.CreateElement ("assemblies", null);
96 document.AppendChild (nassemblies);
97 foreach (AssemblyDefinition a in assemblies) {
98 AssemblyData data = new AssemblyData (document, nassemblies, a);
103 public XmlDocument Document {
104 set { document = value; }
107 AssemblyDefinition LoadAssembly (string assembly)
110 return TypeHelper.Resolver.Resolve (assembly);
117 abstract class BaseData
119 protected XmlDocument document;
120 protected XmlNode parent;
122 protected BaseData (XmlDocument doc, XmlNode parent)
125 this.parent = parent;
128 public abstract void DoOutput ();
130 protected void AddAttribute (XmlNode node, string name, string value)
132 XmlAttribute attr = document.CreateAttribute (name);
134 node.Attributes.Append (attr);
138 class TypeForwardedToData : BaseData
140 AssemblyDefinition ass;
142 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
143 : base (document, parent)
148 public override void DoOutput ()
150 XmlNode natts = parent.SelectSingleNode("attributes");
152 natts = document.CreateElement ("attributes", null);
153 parent.AppendChild (natts);
156 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
158 if (((uint)type.Attributes & 0x200000u) == 0)
161 XmlNode node = document.CreateElement ("attribute");
162 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
163 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
164 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
165 AddAttribute (property, "name", "Destination");
166 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
167 natts.AppendChild (node);
171 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
173 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
178 class AssemblyData : BaseData
180 AssemblyDefinition ass;
182 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
183 : base (document, parent)
188 public override void DoOutput ()
190 if (document == null)
191 throw new InvalidOperationException ("Document not set");
193 XmlNode nassembly = document.CreateElement ("assembly", null);
194 AssemblyNameDefinition aname = ass.Name;
195 AddAttribute (nassembly, "name", aname.Name);
196 AddAttribute (nassembly, "version", aname.Version.ToString ());
197 parent.AppendChild (nassembly);
198 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
199 AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
200 var typesCollection = ass.MainModule.Types;
201 if (typesCollection == null || typesCollection.Count == 0)
203 object [] typesArray = new object [typesCollection.Count];
204 for (int i = 0; i < typesCollection.Count; i++) {
205 typesArray [i] = typesCollection [i];
207 Array.Sort (typesArray, TypeReferenceComparer.Default);
209 XmlNode nss = document.CreateElement ("namespaces", null);
210 nassembly.AppendChild (nss);
212 string current_namespace = "$%&$&";
214 XmlNode classes = null;
215 foreach (TypeDefinition t in typesArray) {
216 if (string.IsNullOrEmpty (t.Namespace))
219 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
222 if (t.DeclaringType != null)
223 continue; // enforce !nested
225 if (t.Namespace != current_namespace) {
226 current_namespace = t.Namespace;
227 ns = document.CreateElement ("namespace", null);
228 AddAttribute (ns, "name", current_namespace);
229 nss.AppendChild (ns);
230 classes = document.CreateElement ("classes", null);
231 ns.AppendChild (classes);
234 TypeData bd = new TypeData (document, classes, t);
240 abstract class MemberData : BaseData
242 MemberReference [] members;
244 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
245 : base (document, parent)
247 this.members = members;
250 public override void DoOutput ()
252 XmlNode mclass = document.CreateElement (ParentTag, null);
253 parent.AppendChild (mclass);
255 foreach (MemberReference member in members) {
256 XmlNode mnode = document.CreateElement (Tag, null);
257 mclass.AppendChild (mnode);
258 AddAttribute (mnode, "name", GetName (member));
259 if (!NoMemberAttributes)
260 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
262 AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
264 AddExtraData (mnode, member);
269 protected abstract IList<CustomAttribute> GetCustomAttributes (MemberReference member);
271 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
275 protected virtual string GetName (MemberReference memberDefenition)
280 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
285 public virtual bool NoMemberAttributes {
286 get { return false; }
290 public virtual string ParentTag {
291 get { return "NoPARENTTAG"; }
294 public virtual string Tag {
295 get { return "NoTAG"; }
298 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
300 if (provider.GenericParameters.Count == 0)
303 var gparameters = provider.GenericParameters;
305 XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
306 nclass.AppendChild (ngeneric);
308 foreach (GenericParameter gp in gparameters) {
309 XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
310 nparam.SetAttribute ("name", gp.Name);
311 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
313 AttributeData.OutputAttributes (document, nparam, gp.CustomAttributes);
315 ngeneric.AppendChild (nparam);
317 var constraints = gp.Constraints;
318 if (constraints.Count == 0)
321 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
323 foreach (TypeReference constraint in constraints) {
324 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
325 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
326 nconstraint.AppendChild (ncons);
329 nparam.AppendChild (nconstraint);
334 class TypeData : MemberData
338 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
339 : base (document, parent, null)
344 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
345 return ((TypeDefinition) member).CustomAttributes;
348 public override void DoOutput ()
350 if (document == null)
351 throw new InvalidOperationException ("Document not set");
353 XmlNode nclass = document.CreateElement ("class", null);
354 AddAttribute (nclass, "name", type.Name);
355 string classType = GetClassType (type);
356 AddAttribute (nclass, "type", classType);
358 if (type.BaseType != null)
359 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
362 AddAttribute (nclass, "sealed", "true");
365 AddAttribute (nclass, "abstract", "true");
367 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
368 AddAttribute (nclass, "serializable", "true");
370 string charSet = GetCharSet (type);
371 AddAttribute (nclass, "charset", charSet);
373 string layout = GetLayout (type);
375 AddAttribute (nclass, "layout", layout);
377 parent.AppendChild (nclass);
379 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
381 XmlNode ifaces = null;
383 foreach (TypeReference iface in TypeHelper.GetInterfaces (type)) {
384 if (!TypeHelper.IsPublic (iface))
385 // we're only interested in public interfaces
388 if (ifaces == null) {
389 ifaces = document.CreateElement ("interfaces", null);
390 nclass.AppendChild (ifaces);
393 XmlNode iface_node = document.CreateElement ("interface", null);
394 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
395 ifaces.AppendChild (iface_node);
398 MemberData.OutputGenericParameters (document, nclass, type);
400 ArrayList members = new ArrayList ();
402 FieldDefinition [] fields = GetFields (type);
403 if (fields.Length > 0) {
404 Array.Sort (fields, MemberReferenceComparer.Default);
405 FieldData fd = new FieldData (document, nclass, fields);
410 var value_type = GetEnumValueField (type);
411 if (value_type == null)
412 throw new NotSupportedException ();
414 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
417 if (!Driver.AbiMode) {
419 MethodDefinition [] ctors = GetConstructors (type);
420 if (ctors.Length > 0) {
421 Array.Sort (ctors, MemberReferenceComparer.Default);
422 members.Add (new ConstructorData (document, nclass, ctors));
425 PropertyDefinition[] properties = GetProperties (type);
426 if (properties.Length > 0) {
427 Array.Sort (properties, MemberReferenceComparer.Default);
428 members.Add (new PropertyData (document, nclass, properties));
431 EventDefinition [] events = GetEvents (type);
432 if (events.Length > 0) {
433 Array.Sort (events, MemberReferenceComparer.Default);
434 members.Add (new EventData (document, nclass, events));
437 MethodDefinition [] methods = GetMethods (type);
438 if (methods.Length > 0) {
439 Array.Sort (methods, MemberReferenceComparer.Default);
440 members.Add (new MethodData (document, nclass, methods));
444 foreach (MemberData md in members)
447 var nested = type.NestedTypes;
448 //remove non public(familiy) and nested in second degree
449 for (int i = nested.Count - 1; i >= 0; i--) {
450 TypeDefinition t = nested [i];
451 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
452 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
453 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
455 if (t.DeclaringType == type)
456 continue; // not nested of nested
463 if (nested.Count > 0) {
464 XmlNode classes = document.CreateElement ("classes", null);
465 nclass.AppendChild (classes);
466 foreach (TypeDefinition t in nested) {
467 TypeData td = new TypeData (document, classes, t);
473 static FieldReference GetEnumValueField (TypeDefinition type)
475 foreach (FieldDefinition field in type.Fields)
476 if (field.IsSpecialName && field.Name == "value__")
482 protected override string GetMemberAttributes (MemberReference member)
485 throw new InvalidOperationException ("odd");
487 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
490 public static bool MustDocumentMethod (MethodDefinition method) {
492 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
493 return maskedAccess == MethodAttributes.Public
494 || maskedAccess == MethodAttributes.Family
495 || maskedAccess == MethodAttributes.FamORAssem;
498 static string GetClassType (TypeDefinition t)
509 if (TypeHelper.IsDelegate(t))
515 static string GetCharSet (TypeDefinition type)
517 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
518 if (maskedStringFormat == TypeAttributes.AnsiClass)
519 return CharSet.Ansi.ToString ();
521 if (maskedStringFormat == TypeAttributes.AutoClass)
522 return CharSet.Auto.ToString ();
524 if (maskedStringFormat == TypeAttributes.UnicodeClass)
525 return CharSet.Unicode.ToString ();
527 return CharSet.None.ToString ();
530 static string GetLayout (TypeDefinition type)
532 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
533 if (maskedLayout == TypeAttributes.AutoLayout)
534 return LayoutKind.Auto.ToString ();
536 if (maskedLayout == TypeAttributes.ExplicitLayout)
537 return LayoutKind.Explicit.ToString ();
539 if (maskedLayout == TypeAttributes.SequentialLayout)
540 return LayoutKind.Sequential.ToString ();
545 FieldDefinition [] GetFields (TypeDefinition type) {
546 ArrayList list = new ArrayList ();
548 var fields = type.Fields;
549 foreach (FieldDefinition field in fields) {
550 if (field.IsSpecialName)
553 if (Driver.AbiMode && field.IsStatic)
556 // we're only interested in public or protected members
557 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
558 if (Driver.AbiMode && !field.IsNotSerialized) {
561 if (maskedVisibility == FieldAttributes.Public
562 || maskedVisibility == FieldAttributes.Family
563 || maskedVisibility == FieldAttributes.FamORAssem) {
569 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
573 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
574 ArrayList list = new ArrayList ();
576 var properties = type.Properties;//type.GetProperties (flags);
577 foreach (PropertyDefinition property in properties) {
578 MethodDefinition getMethod = property.GetMethod;
579 MethodDefinition setMethod = property.SetMethod;
581 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
582 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
584 // if neither the getter or setter should be documented, then
586 if (hasGetter || hasSetter) {
591 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
594 private MethodDefinition[] GetMethods (TypeDefinition type)
596 ArrayList list = new ArrayList ();
598 var methods = type.Methods;//type.GetMethods (flags);
599 foreach (MethodDefinition method in methods) {
600 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
603 // we're only interested in public or protected members
604 if (!MustDocumentMethod(method))
607 if (IsFinalizer (method))
613 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
616 static bool IsFinalizer (MethodDefinition method)
618 if (method.Name != "Finalize")
621 if (!method.IsVirtual)
624 if (method.Parameters.Count != 0)
630 private MethodDefinition [] GetConstructors (TypeDefinition type)
632 ArrayList list = new ArrayList ();
634 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
635 foreach (MethodDefinition constructor in ctors) {
636 // we're only interested in public or protected members
637 if (!MustDocumentMethod(constructor))
640 list.Add (constructor);
643 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
646 private EventDefinition[] GetEvents (TypeDefinition type)
648 ArrayList list = new ArrayList ();
650 var events = type.Events;//type.GetEvents (flags);
651 foreach (EventDefinition eventDef in events) {
652 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
654 if (addMethod == null || !MustDocumentMethod (addMethod))
660 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
664 class FieldData : MemberData
666 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
667 : base (document, parent, members)
671 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
672 return ((FieldDefinition) member).CustomAttributes;
675 protected override string GetName (MemberReference memberDefenition)
677 FieldDefinition field = (FieldDefinition) memberDefenition;
681 protected override string GetMemberAttributes (MemberReference memberDefenition)
683 FieldDefinition field = (FieldDefinition) memberDefenition;
684 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
687 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
689 base.AddExtraData (p, memberDefenition);
690 FieldDefinition field = (FieldDefinition) memberDefenition;
691 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
693 if (field.IsLiteral) {
694 object value = field.Constant;//object value = field.GetValue (null);
695 string stringValue = null;
696 //if (value is Enum) {
697 // // FIXME: when Mono bug #60090 has been
698 // // fixed, we should just be able to use
699 // // Convert.ToString
700 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
703 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
706 if (stringValue != null)
707 AddAttribute (p, "value", stringValue);
711 public override string ParentTag {
712 get { return "fields"; }
715 public override string Tag {
716 get { return "field"; }
720 class PropertyData : MemberData
722 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
723 : base (document, parent, members)
727 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
728 return ((PropertyDefinition) member).CustomAttributes;
731 protected override string GetName (MemberReference memberDefenition)
733 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
737 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
739 base.AddExtraData (p, memberDefenition);
740 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
741 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
742 MethodDefinition _get = prop.GetMethod;
743 MethodDefinition _set = prop.SetMethod;
744 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
745 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
746 MethodDefinition [] methods;
748 if (haveGet && haveSet) {
749 methods = new MethodDefinition [] { _get, _set };
750 } else if (haveGet) {
751 methods = new MethodDefinition [] { _get };
752 } else if (haveSet) {
753 methods = new MethodDefinition [] { _set };
759 string parms = Parameters.GetSignature (methods [0].Parameters);
760 if (!string.IsNullOrEmpty (parms))
761 AddAttribute (p, "params", parms);
763 MethodData data = new MethodData (document, p, methods);
764 //data.NoMemberAttributes = true;
768 protected override string GetMemberAttributes (MemberReference memberDefenition)
770 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
771 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
774 public override string ParentTag {
775 get { return "properties"; }
778 public override string Tag {
779 get { return "property"; }
783 class EventData : MemberData
785 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
786 : base (document, parent, members)
790 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
791 return ((EventDefinition) member).CustomAttributes;
794 protected override string GetName (MemberReference memberDefenition)
796 EventDefinition evt = (EventDefinition) memberDefenition;
800 protected override string GetMemberAttributes (MemberReference memberDefenition)
802 EventDefinition evt = (EventDefinition) memberDefenition;
803 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
806 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
808 base.AddExtraData (p, memberDefenition);
809 EventDefinition evt = (EventDefinition) memberDefenition;
810 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
813 public override string ParentTag {
814 get { return "events"; }
817 public override string Tag {
818 get { return "event"; }
822 class MethodData : MemberData
826 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
827 : base (document, parent, members)
831 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
832 return ((MethodDefinition) member).CustomAttributes;
835 protected override string GetName (MemberReference memberDefenition)
837 MethodDefinition method = (MethodDefinition) memberDefenition;
838 string name = method.Name;
839 string parms = Parameters.GetSignature (method.Parameters);
841 return string.Format ("{0}({1})", name, parms);
844 protected override string GetMemberAttributes (MemberReference memberDefenition)
846 MethodDefinition method = (MethodDefinition) memberDefenition;
847 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
850 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
852 base.AddExtraData (p, memberDefenition);
854 if (!(memberDefenition is MethodDefinition))
857 MethodDefinition mbase = (MethodDefinition) memberDefenition;
859 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
862 if (mbase.IsAbstract)
863 AddAttribute (p, "abstract", "true");
865 AddAttribute (p, "virtual", "true");
867 AddAttribute (p, "static", "true");
869 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
870 if (rettype != "System.Void" || !mbase.IsConstructor)
871 AddAttribute (p, "returntype", (rettype));
873 AttributeData.OutputAttributes (document, p, mbase.MethodReturnType.CustomAttributes);
875 MemberData.OutputGenericParameters (document, p, mbase);
878 public override bool NoMemberAttributes {
879 get { return noAtts; }
880 set { noAtts = value; }
883 public override string ParentTag {
884 get { return "methods"; }
887 public override string Tag {
888 get { return "method"; }
892 class ConstructorData : MethodData
894 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
895 : base (document, parent, members)
899 public override string ParentTag {
900 get { return "constructors"; }
903 public override string Tag {
904 get { return "constructor"; }
908 class ParameterData : BaseData
910 private IList<ParameterDefinition> parameters;
912 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
913 : base (document, parent)
915 this.parameters = parameters;
918 public override void DoOutput ()
920 XmlNode parametersNode = document.CreateElement ("parameters");
921 parent.AppendChild (parametersNode);
923 foreach (ParameterDefinition parameter in parameters) {
924 XmlNode paramNode = document.CreateElement ("parameter");
925 parametersNode.AppendChild (paramNode);
926 AddAttribute (paramNode, "name", parameter.Name);
927 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
928 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
930 string direction = "in";
932 if (parameter.ParameterType is ByReferenceType)
933 direction = parameter.IsOut ? "out" : "ref";
935 TypeReference t = parameter.ParameterType;
936 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
938 if (parameter.IsOptional) {
939 AddAttribute (paramNode, "optional", "true");
940 if (parameter.HasConstant)
941 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
944 if (direction != "in")
945 AddAttribute (paramNode, "direction", direction);
947 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
952 class AttributeData : BaseData
954 IList<CustomAttribute> atts;
956 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
962 public override void DoOutput ()
964 if (document == null)
965 throw new InvalidOperationException ("Document not set");
967 if (atts == null || atts.Count == 0)
970 XmlNode natts = parent.SelectSingleNode("attributes");
972 natts = document.CreateElement ("attributes", null);
973 parent.AppendChild (natts);
976 for (int i = 0; i < atts.Count; ++i) {
977 CustomAttribute att = atts [i];
979 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
980 if (SkipAttribute (att))
983 XmlNode node = document.CreateElement ("attribute");
984 AddAttribute (node, "name", attName);
986 XmlNode properties = null;
988 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
990 foreach (string name in attribute_mapping.Keys) {
991 if (name == "TypeId")
994 if (properties == null) {
995 properties = node.AppendChild (document.CreateElement ("properties"));
998 object o = attribute_mapping [name];
1000 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1001 AddAttribute (n, "name", name);
1004 AddAttribute (n, "value", "null");
1007 string value = o.ToString ();
1008 if (attName.EndsWith ("GuidAttribute"))
1009 value = value.ToUpper ();
1010 AddAttribute (n, "value", value);
1013 natts.AppendChild (node);
1017 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1019 var mapping = new Dictionary<string, object> ();
1021 PopulateMapping (mapping, attribute);
1023 var constructor = attribute.Constructor.Resolve ();
1024 if (constructor == null || constructor.Parameters.Count == 0)
1027 PopulateMapping (mapping, constructor, attribute);
1032 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1034 foreach (var named_argument in attribute.Properties) {
1035 var name = named_argument.Name;
1037 mapping.Add (name, GetArgumentValue (named_argument.Argument.Type, named_argument.Argument.Value));
1041 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1043 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1045 int? argument = null;
1047 foreach (Instruction instruction in constructor.Body.Instructions) {
1048 switch (instruction.OpCode.Code) {
1060 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1064 FieldReference field = (FieldReference) instruction.Operand;
1065 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1068 if (!argument.HasValue)
1071 if (!field_mapping.ContainsKey (field))
1072 field_mapping.Add (field, (int) argument - 1);
1079 return field_mapping;
1082 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1084 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1086 foreach (PropertyDefinition property in type.Properties) {
1087 if (property.GetMethod == null)
1089 if (!property.GetMethod.HasBody)
1092 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1093 if (instruction.OpCode.Code != Code.Ldfld)
1096 FieldReference field = (FieldReference) instruction.Operand;
1097 if (field.DeclaringType.FullName != type.FullName)
1100 property_mapping.Add (property, field);
1105 return property_mapping;
1108 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1110 if (!constructor.HasBody)
1113 var field_mapping = CreateArgumentFieldMapping (constructor);
1114 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1116 foreach (var pair in property_mapping) {
1118 if (!field_mapping.TryGetValue (pair.Value, out argument))
1121 var ca_arg = attribute.ConstructorArguments [argument];
1122 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1126 static object GetArgumentValue (TypeReference reference, object value)
1128 var type = reference.Resolve ();
1133 if (IsFlaggedEnum (type))
1134 return GetFlaggedEnumValue (type, value);
1136 return GetEnumValue (type, value);
1142 static bool IsFlaggedEnum (TypeDefinition type)
1147 if (type.CustomAttributes.Count == 0)
1150 foreach (CustomAttribute attribute in type.CustomAttributes)
1151 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1157 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1159 long flags = Convert.ToInt64 (value);
1160 var signature = new StringBuilder ();
1162 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1163 FieldDefinition field = type.Fields [i];
1165 if (!field.HasConstant)
1168 long flag = Convert.ToInt64 (field.Constant);
1173 if ((flags & flag) == flag) {
1174 if (signature.Length != 0)
1175 signature.Append (", ");
1177 signature.Append (field.Name);
1182 return signature.ToString ();
1185 static object GetEnumValue (TypeDefinition type, object value)
1187 foreach (FieldDefinition field in type.Fields) {
1188 if (!field.HasConstant)
1191 if (Comparer.Default.Compare (field.Constant, value) == 0)
1198 static bool SkipAttribute (CustomAttribute attribute)
1200 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1202 return !TypeHelper.IsPublic (attribute)
1203 || type_name.EndsWith ("TODOAttribute");
1206 public static void OutputAttributes (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1208 AttributeData ad = new AttributeData (doc, parent, attributes);
1213 static class Parameters {
1215 public static string GetSignature (IList<ParameterDefinition> infos)
1217 if (infos == null || infos.Count == 0)
1220 var signature = new StringBuilder ();
1221 for (int i = 0; i < infos.Count; i++) {
1224 signature.Append (", ");
1226 ParameterDefinition info = infos [i];
1229 if ((info.Attributes & ParameterAttributes.In) != 0)
1231 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1234 modifier = string.Empty;
1236 if (modifier.Length > 0)
1237 signature.AppendFormat ("{0} ", modifier);
1239 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1242 return signature.ToString ();
1247 class TypeReferenceComparer : IComparer
1249 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1251 public int Compare (object a, object b)
1253 TypeReference ta = (TypeReference) a;
1254 TypeReference tb = (TypeReference) b;
1255 int result = String.Compare (ta.Namespace, tb.Namespace);
1259 return String.Compare (ta.Name, tb.Name);
1263 class MemberReferenceComparer : IComparer
1265 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1267 public int Compare (object a, object b)
1269 MemberReference ma = (MemberReference) a;
1270 MemberReference mb = (MemberReference) b;
1271 return String.Compare (ma.Name, mb.Name);
1275 class MethodDefinitionComparer : IComparer
1277 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1279 public int Compare (object a, object b)
1281 MethodDefinition ma = (MethodDefinition) a;
1282 MethodDefinition mb = (MethodDefinition) b;
1283 int res = String.Compare (ma.Name, mb.Name);
1287 IList<ParameterDefinition> pia = ma.Parameters ;
1288 IList<ParameterDefinition> pib = mb.Parameters;
1289 res = pia.Count - pib.Count;
1293 string siga = Parameters.GetSignature (pia);
1294 string sigb = Parameters.GetSignature (pib);
1295 return String.Compare (siga, sigb);