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;
14 using System.Runtime.CompilerServices;
15 using System.Runtime.InteropServices;
16 using System.Security.Permissions;
27 public static int Main (string [] args)
34 AssemblyCollection acoll = new AssemblyCollection ();
36 foreach (string arg in args) {
43 XmlDocument doc = new XmlDocument ();
47 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
48 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
49 doc.InsertBefore (decl, doc.DocumentElement);
54 internal static bool AbiMode { get; private set; }
59 public static string CleanupTypeName (TypeReference type)
61 return CleanupTypeName (type.FullName);
64 static string CleanupTypeName (string t)
66 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
70 class AssemblyCollection
73 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
75 public AssemblyCollection ()
79 public bool Add (string name)
81 AssemblyDefinition ass = LoadAssembly (name);
89 public void DoOutput ()
92 throw new InvalidOperationException ("Document not set");
94 XmlNode nassemblies = document.CreateElement ("assemblies", null);
95 document.AppendChild (nassemblies);
96 foreach (AssemblyDefinition a in assemblies) {
97 AssemblyData data = new AssemblyData (document, nassemblies, a);
102 public XmlDocument Document {
103 set { document = value; }
106 AssemblyDefinition LoadAssembly (string assembly)
109 return TypeHelper.Resolver.Resolve (assembly);
116 abstract class BaseData
118 protected XmlDocument document;
119 protected XmlNode parent;
121 protected BaseData (XmlDocument doc, XmlNode parent)
124 this.parent = parent;
127 public abstract void DoOutput ();
129 protected void AddAttribute (XmlNode node, string name, string value)
131 XmlAttribute attr = document.CreateAttribute (name);
133 node.Attributes.Append (attr);
137 class TypeForwardedToData : BaseData
139 AssemblyDefinition ass;
141 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
142 : base (document, parent)
147 public override void DoOutput ()
149 XmlNode natts = parent.SelectSingleNode("attributes");
151 natts = document.CreateElement ("attributes", null);
152 parent.AppendChild (natts);
155 foreach (TypeReference tref in ass.MainModule.ExternTypes) {
156 TypeDefinition def = tref.Resolve ();
160 if (((uint)def.Attributes & 0x200000u) == 0)
163 XmlNode node = document.CreateElement ("attribute");
164 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
165 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
166 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
167 AddAttribute (property, "name", "Destination");
168 AddAttribute (property, "value", Utils.CleanupTypeName (tref));
169 natts.AppendChild (node);
173 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
175 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
180 class AssemblyData : BaseData
182 AssemblyDefinition ass;
184 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
185 : base (document, parent)
190 public override void DoOutput ()
192 if (document == null)
193 throw new InvalidOperationException ("Document not set");
195 XmlNode nassembly = document.CreateElement ("assembly", null);
196 AssemblyNameDefinition aname = ass.Name;
197 AddAttribute (nassembly, "name", aname.Name);
198 AddAttribute (nassembly, "version", aname.Version.ToString ());
199 parent.AppendChild (nassembly);
200 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
201 AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
202 TypeDefinitionCollection typesCollection = ass.MainModule.Types;
203 if (typesCollection == null || typesCollection.Count == 0)
205 object [] typesArray = new object [typesCollection.Count];
206 for (int i = 0; i < typesCollection.Count; i++) {
207 typesArray [i] = typesCollection [i];
209 Array.Sort (typesArray, TypeReferenceComparer.Default);
211 XmlNode nss = document.CreateElement ("namespaces", null);
212 nassembly.AppendChild (nss);
214 string current_namespace = "$%&$&";
216 XmlNode classes = null;
217 foreach (TypeDefinition t in typesArray) {
218 if (string.IsNullOrEmpty (t.Namespace))
221 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
224 if (t.DeclaringType != null)
225 continue; // enforce !nested
227 if (t.Namespace != current_namespace) {
228 current_namespace = t.Namespace;
229 ns = document.CreateElement ("namespace", null);
230 AddAttribute (ns, "name", current_namespace);
231 nss.AppendChild (ns);
232 classes = document.CreateElement ("classes", null);
233 ns.AppendChild (classes);
236 TypeData bd = new TypeData (document, classes, t);
242 abstract class MemberData : BaseData
244 MemberReference [] members;
246 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
247 : base (document, parent)
249 this.members = members;
252 public override void DoOutput ()
254 XmlNode mclass = document.CreateElement (ParentTag, null);
255 parent.AppendChild (mclass);
257 foreach (MemberReference member in members) {
258 XmlNode mnode = document.CreateElement (Tag, null);
259 mclass.AppendChild (mnode);
260 AddAttribute (mnode, "name", GetName (member));
261 if (!NoMemberAttributes)
262 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
264 AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
266 AddExtraData (mnode, member);
271 protected abstract CustomAttributeCollection GetCustomAttributes (MemberReference member);
273 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
277 protected virtual string GetName (MemberReference memberDefenition)
282 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
287 public virtual bool NoMemberAttributes {
288 get { return false; }
292 public virtual string ParentTag {
293 get { return "NoPARENTTAG"; }
296 public virtual string Tag {
297 get { return "NoTAG"; }
300 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
302 if (provider.GenericParameters.Count == 0)
305 var gparameters = provider.GenericParameters;
307 XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
308 nclass.AppendChild (ngeneric);
310 foreach (GenericParameter gp in gparameters) {
311 XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
312 nparam.SetAttribute ("name", gp.Name);
313 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
315 AttributeData.OutputAttributes (document, nparam, gp.CustomAttributes);
317 ngeneric.AppendChild (nparam);
319 var constraints = gp.Constraints;
320 if (constraints.Count == 0)
323 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
325 foreach (TypeReference constraint in constraints) {
326 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
327 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
328 nconstraint.AppendChild (ncons);
331 nparam.AppendChild (nconstraint);
336 class TypeData : MemberData
340 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
341 : base (document, parent, null)
346 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
347 return ((TypeDefinition) member).CustomAttributes;
350 public override void DoOutput ()
352 if (document == null)
353 throw new InvalidOperationException ("Document not set");
355 XmlNode nclass = document.CreateElement ("class", null);
356 AddAttribute (nclass, "name", type.Name);
357 string classType = GetClassType (type);
358 AddAttribute (nclass, "type", classType);
360 if (type.BaseType != null)
361 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
364 AddAttribute (nclass, "sealed", "true");
367 AddAttribute (nclass, "abstract", "true");
369 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
370 AddAttribute (nclass, "serializable", "true");
372 string charSet = GetCharSet (type);
373 AddAttribute (nclass, "charset", charSet);
375 string layout = GetLayout (type);
377 AddAttribute (nclass, "layout", layout);
379 parent.AppendChild (nclass);
381 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
383 XmlNode ifaces = null;
385 foreach (TypeReference iface in TypeHelper.GetInterfaces (type)) {
386 if (!TypeHelper.IsPublic (iface))
387 // we're only interested in public interfaces
390 if (ifaces == null) {
391 ifaces = document.CreateElement ("interfaces", null);
392 nclass.AppendChild (ifaces);
395 XmlNode iface_node = document.CreateElement ("interface", null);
396 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
397 ifaces.AppendChild (iface_node);
400 MemberData.OutputGenericParameters (document, nclass, type);
402 ArrayList members = new ArrayList ();
404 FieldDefinition [] fields = GetFields (type);
405 if (fields.Length > 0) {
406 Array.Sort (fields, MemberReferenceComparer.Default);
407 FieldData fd = new FieldData (document, nclass, fields);
412 var value_type = GetEnumValueField (type);
413 if (value_type == null)
414 throw new NotSupportedException ();
416 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
419 if (!Driver.AbiMode) {
421 MethodDefinition [] ctors = GetConstructors (type);
422 if (ctors.Length > 0) {
423 Array.Sort (ctors, MemberReferenceComparer.Default);
424 members.Add (new ConstructorData (document, nclass, ctors));
427 PropertyDefinition[] properties = GetProperties (type);
428 if (properties.Length > 0) {
429 Array.Sort (properties, MemberReferenceComparer.Default);
430 members.Add (new PropertyData (document, nclass, properties));
433 EventDefinition [] events = GetEvents (type);
434 if (events.Length > 0) {
435 Array.Sort (events, MemberReferenceComparer.Default);
436 members.Add (new EventData (document, nclass, events));
439 MethodDefinition [] methods = GetMethods (type);
440 if (methods.Length > 0) {
441 Array.Sort (methods, MemberReferenceComparer.Default);
442 members.Add (new MethodData (document, nclass, methods));
446 foreach (MemberData md in members)
449 NestedTypeCollection nested = type.NestedTypes;
450 //remove non public(familiy) and nested in second degree
451 for (int i = nested.Count - 1; i >= 0; i--) {
452 TypeDefinition t = nested [i];
453 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
454 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
455 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
457 if (t.DeclaringType == type)
458 continue; // not nested of nested
465 if (nested.Count > 0) {
466 XmlNode classes = document.CreateElement ("classes", null);
467 nclass.AppendChild (classes);
468 foreach (TypeDefinition t in nested) {
469 TypeData td = new TypeData (document, classes, t);
475 static FieldReference GetEnumValueField (TypeDefinition type)
477 foreach (FieldDefinition field in type.Fields)
478 if (field.IsSpecialName && field.Name == "value__")
484 protected override string GetMemberAttributes (MemberReference member)
487 throw new InvalidOperationException ("odd");
489 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
492 public static bool MustDocumentMethod (MethodDefinition method) {
494 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
495 return maskedAccess == MethodAttributes.Public
496 || maskedAccess == MethodAttributes.Family
497 || maskedAccess == MethodAttributes.FamORAssem;
500 static string GetClassType (TypeDefinition t)
511 if (TypeHelper.IsDelegate(t))
517 static string GetCharSet (TypeDefinition type)
519 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
520 if (maskedStringFormat == TypeAttributes.AnsiClass)
521 return CharSet.Ansi.ToString ();
523 if (maskedStringFormat == TypeAttributes.AutoClass)
524 return CharSet.Auto.ToString ();
526 if (maskedStringFormat == TypeAttributes.UnicodeClass)
527 return CharSet.Unicode.ToString ();
529 return CharSet.None.ToString ();
532 static string GetLayout (TypeDefinition type)
534 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
535 if (maskedLayout == TypeAttributes.AutoLayout)
536 return LayoutKind.Auto.ToString ();
538 if (maskedLayout == TypeAttributes.ExplicitLayout)
539 return LayoutKind.Explicit.ToString ();
541 if (maskedLayout == TypeAttributes.SequentialLayout)
542 return LayoutKind.Sequential.ToString ();
547 FieldDefinition [] GetFields (TypeDefinition type) {
548 ArrayList list = new ArrayList ();
550 FieldDefinitionCollection fields = type.Fields;
551 foreach (FieldDefinition field in fields) {
552 if (field.IsSpecialName)
555 if (Driver.AbiMode && field.IsStatic)
558 // we're only interested in public or protected members
559 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
560 if (Driver.AbiMode && !field.IsNotSerialized) {
563 if (maskedVisibility == FieldAttributes.Public
564 || maskedVisibility == FieldAttributes.Family
565 || maskedVisibility == FieldAttributes.FamORAssem) {
571 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
575 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
576 ArrayList list = new ArrayList ();
578 PropertyDefinitionCollection properties = type.Properties;//type.GetProperties (flags);
579 foreach (PropertyDefinition property in properties) {
580 MethodDefinition getMethod = property.GetMethod;
581 MethodDefinition setMethod = property.SetMethod;
583 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
584 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
586 // if neither the getter or setter should be documented, then
588 if (hasGetter || hasSetter) {
593 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
596 private MethodDefinition[] GetMethods (TypeDefinition type)
598 ArrayList list = new ArrayList ();
600 MethodDefinitionCollection methods = type.Methods;//type.GetMethods (flags);
601 foreach (MethodDefinition method in methods) {
602 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
605 // we're only interested in public or protected members
606 if (!MustDocumentMethod(method))
609 if (IsFinalizer (method))
615 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
618 static bool IsFinalizer (MethodDefinition method)
620 if (method.Name != "Finalize")
623 if (!method.IsVirtual)
626 if (method.Parameters.Count != 0)
632 private MethodDefinition [] GetConstructors (TypeDefinition type)
634 ArrayList list = new ArrayList ();
636 ConstructorCollection ctors = type.Constructors;//type.GetConstructors (flags);
637 foreach (MethodDefinition constructor in ctors) {
638 // we're only interested in public or protected members
639 if (!MustDocumentMethod(constructor))
642 list.Add (constructor);
645 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
648 private EventDefinition[] GetEvents (TypeDefinition type)
650 ArrayList list = new ArrayList ();
652 EventDefinitionCollection events = type.Events;//type.GetEvents (flags);
653 foreach (EventDefinition eventDef in events) {
654 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
656 if (addMethod == null || !MustDocumentMethod (addMethod))
662 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
666 class FieldData : MemberData
668 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
669 : base (document, parent, members)
673 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
674 return ((FieldDefinition) member).CustomAttributes;
677 protected override string GetName (MemberReference memberDefenition)
679 FieldDefinition field = (FieldDefinition) memberDefenition;
683 protected override string GetMemberAttributes (MemberReference memberDefenition)
685 FieldDefinition field = (FieldDefinition) memberDefenition;
686 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
689 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
691 base.AddExtraData (p, memberDefenition);
692 FieldDefinition field = (FieldDefinition) memberDefenition;
693 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
695 if (field.IsLiteral) {
696 object value = field.Constant;//object value = field.GetValue (null);
697 string stringValue = null;
698 //if (value is Enum) {
699 // // FIXME: when Mono bug #60090 has been
700 // // fixed, we should just be able to use
701 // // Convert.ToString
702 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
705 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
708 if (stringValue != null)
709 AddAttribute (p, "value", stringValue);
713 public override string ParentTag {
714 get { return "fields"; }
717 public override string Tag {
718 get { return "field"; }
722 class PropertyData : MemberData
724 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
725 : base (document, parent, members)
729 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
730 return ((PropertyDefinition) member).CustomAttributes;
733 protected override string GetName (MemberReference memberDefenition)
735 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
739 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
741 base.AddExtraData (p, memberDefenition);
742 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
743 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
744 MethodDefinition _get = prop.GetMethod;
745 MethodDefinition _set = prop.SetMethod;
746 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
747 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
748 MethodDefinition [] methods;
750 if (haveGet && haveSet) {
751 methods = new MethodDefinition [] { _get, _set };
752 } else if (haveGet) {
753 methods = new MethodDefinition [] { _get };
754 } else if (haveSet) {
755 methods = new MethodDefinition [] { _set };
761 string parms = Parameters.GetSignature (methods [0].Parameters);
762 if (!string.IsNullOrEmpty (parms))
763 AddAttribute (p, "params", parms);
765 MethodData data = new MethodData (document, p, methods);
766 //data.NoMemberAttributes = true;
770 protected override string GetMemberAttributes (MemberReference memberDefenition)
772 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
773 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
776 public override string ParentTag {
777 get { return "properties"; }
780 public override string Tag {
781 get { return "property"; }
785 class EventData : MemberData
787 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
788 : base (document, parent, members)
792 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
793 return ((EventDefinition) member).CustomAttributes;
796 protected override string GetName (MemberReference memberDefenition)
798 EventDefinition evt = (EventDefinition) memberDefenition;
802 protected override string GetMemberAttributes (MemberReference memberDefenition)
804 EventDefinition evt = (EventDefinition) memberDefenition;
805 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
808 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
810 base.AddExtraData (p, memberDefenition);
811 EventDefinition evt = (EventDefinition) memberDefenition;
812 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
815 public override string ParentTag {
816 get { return "events"; }
819 public override string Tag {
820 get { return "event"; }
824 class MethodData : MemberData
828 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
829 : base (document, parent, members)
833 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
834 return ((MethodDefinition) member).CustomAttributes;
837 protected override string GetName (MemberReference memberDefenition)
839 MethodDefinition method = (MethodDefinition) memberDefenition;
840 string name = method.Name;
841 string parms = Parameters.GetSignature (method.Parameters);
843 return string.Format ("{0}({1})", name, parms);
846 protected override string GetMemberAttributes (MemberReference memberDefenition)
848 MethodDefinition method = (MethodDefinition) memberDefenition;
849 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
852 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
854 base.AddExtraData (p, memberDefenition);
856 if (!(memberDefenition is MethodDefinition))
859 MethodDefinition mbase = (MethodDefinition) memberDefenition;
861 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
864 if (mbase.IsAbstract)
865 AddAttribute (p, "abstract", "true");
867 AddAttribute (p, "virtual", "true");
869 AddAttribute (p, "static", "true");
871 string rettype = Utils.CleanupTypeName (mbase.ReturnType.ReturnType);
872 if (rettype != "System.Void" || !mbase.IsConstructor)
873 AddAttribute (p, "returntype", (rettype));
875 AttributeData.OutputAttributes (document, p, mbase.ReturnType.CustomAttributes);
877 MemberData.OutputGenericParameters (document, p, mbase);
880 public override bool NoMemberAttributes {
881 get { return noAtts; }
882 set { noAtts = value; }
885 public override string ParentTag {
886 get { return "methods"; }
889 public override string Tag {
890 get { return "method"; }
894 class ConstructorData : MethodData
896 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
897 : base (document, parent, members)
901 public override string ParentTag {
902 get { return "constructors"; }
905 public override string Tag {
906 get { return "constructor"; }
910 class ParameterData : BaseData
912 private ParameterDefinitionCollection parameters;
914 public ParameterData (XmlDocument document, XmlNode parent, ParameterDefinitionCollection parameters)
915 : base (document, parent)
917 this.parameters = parameters;
920 public override void DoOutput ()
922 XmlNode parametersNode = document.CreateElement ("parameters");
923 parent.AppendChild (parametersNode);
925 foreach (ParameterDefinition parameter in parameters) {
926 XmlNode paramNode = document.CreateElement ("parameter");
927 parametersNode.AppendChild (paramNode);
928 AddAttribute (paramNode, "name", parameter.Name);
929 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
930 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
932 string direction = "in";
934 if (parameter.ParameterType is ReferenceType)
935 direction = parameter.IsOut ? "out" : "ref";
937 TypeReference t = parameter.ParameterType;
938 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
940 if (parameter.IsOptional) {
941 AddAttribute (paramNode, "optional", "true");
942 if (parameter.HasConstant)
943 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
946 if (direction != "in")
947 AddAttribute (paramNode, "direction", direction);
949 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
954 class AttributeData : BaseData
956 CustomAttributeCollection atts;
958 AttributeData (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
964 public override void DoOutput ()
966 if (document == null)
967 throw new InvalidOperationException ("Document not set");
969 if (atts == null || atts.Count == 0)
972 XmlNode natts = parent.SelectSingleNode("attributes");
974 natts = document.CreateElement ("attributes", null);
975 parent.AppendChild (natts);
978 for (int i = 0; i < atts.Count; ++i) {
979 CustomAttribute att = atts [i];
987 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
988 if (SkipAttribute (att))
991 XmlNode node = document.CreateElement ("attribute");
992 AddAttribute (node, "name", attName);
994 XmlNode properties = null;
996 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
998 foreach (string name in attribute_mapping.Keys) {
999 if (name == "TypeId")
1002 if (properties == null) {
1003 properties = node.AppendChild (document.CreateElement ("properties"));
1006 object o = attribute_mapping [name];
1008 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1009 AddAttribute (n, "name", name);
1012 AddAttribute (n, "value", "null");
1015 string value = o.ToString ();
1016 if (attName.EndsWith ("GuidAttribute"))
1017 value = value.ToUpper ();
1018 AddAttribute (n, "value", value);
1021 natts.AppendChild (node);
1025 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1027 var mapping = new Dictionary<string, object> ();
1029 PopulateMapping (mapping, attribute);
1031 var constructor = attribute.Constructor.Resolve ();
1032 if (constructor == null || constructor.Parameters.Count == 0)
1035 PopulateMapping (mapping, constructor, attribute);
1040 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1042 foreach (DictionaryEntry entry in attribute.Properties) {
1043 var name = (string) entry.Key;
1045 mapping.Add (name, GetArgumentValue (attribute.GetPropertyType (name), entry.Value));
1049 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1051 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1053 int? argument = null;
1055 foreach (Instruction instruction in constructor.Body.Instructions) {
1056 switch (instruction.OpCode.Code) {
1068 argument = ((ParameterDefinition) instruction.Operand).Sequence;
1072 FieldReference field = (FieldReference) instruction.Operand;
1073 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1076 if (!argument.HasValue)
1079 if (!field_mapping.ContainsKey (field))
1080 field_mapping.Add (field, (int) argument - 1);
1087 return field_mapping;
1090 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1092 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1094 foreach (PropertyDefinition property in type.Properties) {
1095 if (property.GetMethod == null)
1097 if (!property.GetMethod.HasBody)
1100 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1101 if (instruction.OpCode.Code != Code.Ldfld)
1104 FieldReference field = (FieldReference) instruction.Operand;
1105 if (field.DeclaringType.FullName != type.FullName)
1108 property_mapping.Add (property, field);
1113 return property_mapping;
1116 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1118 if (!constructor.HasBody)
1121 var field_mapping = CreateArgumentFieldMapping (constructor);
1122 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1124 foreach (var pair in property_mapping) {
1126 if (!field_mapping.TryGetValue (pair.Value, out argument))
1129 mapping.Add (pair.Key.Name, GetArgumentValue (constructor.Parameters [argument].ParameterType, attribute.ConstructorParameters [argument]));
1133 static object GetArgumentValue (TypeReference reference, object value)
1135 var type = reference.Resolve ();
1140 if (IsFlaggedEnum (type))
1141 return GetFlaggedEnumValue (type, value);
1143 return GetEnumValue (type, value);
1149 static bool IsFlaggedEnum (TypeDefinition type)
1154 if (type.CustomAttributes.Count == 0)
1157 foreach (CustomAttribute attribute in type.CustomAttributes)
1158 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1164 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1166 long flags = Convert.ToInt64 (value);
1167 var signature = new StringBuilder ();
1169 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1170 FieldDefinition field = type.Fields [i];
1172 if (!field.HasConstant)
1175 long flag = Convert.ToInt64 (field.Constant);
1180 if ((flags & flag) == flag) {
1181 if (signature.Length != 0)
1182 signature.Append (", ");
1184 signature.Append (field.Name);
1189 return signature.ToString ();
1192 static object GetEnumValue (TypeDefinition type, object value)
1194 foreach (FieldDefinition field in type.Fields) {
1195 if (!field.HasConstant)
1198 if (Comparer.Default.Compare (field.Constant, value) == 0)
1205 static bool SkipAttribute (CustomAttribute attribute)
1207 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1209 return !TypeHelper.IsPublic (attribute)
1210 || type_name.EndsWith ("TODOAttribute");
1213 public static void OutputAttributes (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
1215 AttributeData ad = new AttributeData (doc, parent, attributes);
1220 static class Parameters {
1222 public static string GetSignature (ParameterDefinitionCollection infos)
1224 if (infos == null || infos.Count == 0)
1227 var signature = new StringBuilder ();
1228 for (int i = 0; i < infos.Count; i++) {
1231 signature.Append (", ");
1233 ParameterDefinition info = infos [i];
1236 if ((info.Attributes & ParameterAttributes.In) != 0)
1238 else if ((info.Attributes & ParameterAttributes.Retval) != 0)
1240 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1243 modifier = string.Empty;
1245 if (modifier.Length > 0)
1246 signature.AppendFormat ("{0} ", modifier);
1248 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1251 return signature.ToString ();
1256 class TypeReferenceComparer : IComparer
1258 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1260 public int Compare (object a, object b)
1262 TypeReference ta = (TypeReference) a;
1263 TypeReference tb = (TypeReference) b;
1264 int result = String.Compare (ta.Namespace, tb.Namespace);
1268 return String.Compare (ta.Name, tb.Name);
1272 class MemberReferenceComparer : IComparer
1274 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1276 public int Compare (object a, object b)
1278 MemberReference ma = (MemberReference) a;
1279 MemberReference mb = (MemberReference) b;
1280 return String.Compare (ma.Name, mb.Name);
1284 class MethodDefinitionComparer : IComparer
1286 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1288 public int Compare (object a, object b)
1290 MethodDefinition ma = (MethodDefinition) a;
1291 MethodDefinition mb = (MethodDefinition) b;
1292 int res = String.Compare (ma.Name, mb.Name);
1296 ParameterDefinitionCollection pia = ma.Parameters ;
1297 ParameterDefinitionCollection pib = mb.Parameters;
1298 res = pia.Count - pib.Count;
1302 string siga = Parameters.GetSignature (pia);
1303 string sigb = Parameters.GetSignature (pib);
1304 return String.Compare (siga, sigb);