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.InteropServices;
15 using System.Security.Permissions;
26 public static int Main (string [] args)
31 AssemblyCollection acoll = new AssemblyCollection ();
33 foreach (string fullName in args) {
37 XmlDocument doc = new XmlDocument ();
41 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
42 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
43 doc.InsertBefore (decl, doc.DocumentElement);
51 public static string CleanupTypeName (TypeReference type)
53 return CleanupTypeName (type.FullName);
56 static string CleanupTypeName (string t)
58 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
62 class AssemblyCollection
65 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
67 public AssemblyCollection ()
71 public bool Add (string name)
73 AssemblyDefinition ass = LoadAssembly (name);
81 public void DoOutput ()
84 throw new InvalidOperationException ("Document not set");
86 XmlNode nassemblies = document.CreateElement ("assemblies", null);
87 document.AppendChild (nassemblies);
88 foreach (AssemblyDefinition a in assemblies) {
89 AssemblyData data = new AssemblyData (document, nassemblies, a);
94 public XmlDocument Document {
95 set { document = value; }
98 AssemblyDefinition LoadAssembly (string assembly)
101 return TypeHelper.Resolver.Resolve (assembly);
108 abstract class BaseData
110 protected XmlDocument document;
111 protected XmlNode parent;
113 protected BaseData (XmlDocument doc, XmlNode parent)
116 this.parent = parent;
119 public abstract void DoOutput ();
121 protected void AddAttribute (XmlNode node, string name, string value)
123 XmlAttribute attr = document.CreateAttribute (name);
125 node.Attributes.Append (attr);
129 class AssemblyData : BaseData
131 AssemblyDefinition ass;
133 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
134 : base (document, parent)
139 public override void DoOutput ()
141 if (document == null)
142 throw new InvalidOperationException ("Document not set");
144 XmlNode nassembly = document.CreateElement ("assembly", null);
145 AssemblyNameDefinition aname = ass.Name;
146 AddAttribute (nassembly, "name", aname.Name);
147 AddAttribute (nassembly, "version", aname.Version.ToString ());
148 parent.AppendChild (nassembly);
149 AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
150 TypeDefinitionCollection typesCollection = ass.MainModule.Types;
151 if (typesCollection == null || typesCollection.Count == 0)
153 object [] typesArray = new object [typesCollection.Count];
154 for (int i = 0; i < typesCollection.Count; i++) {
155 typesArray [i] = typesCollection [i];
157 Array.Sort (typesArray, TypeReferenceComparer.Default);
159 XmlNode nss = document.CreateElement ("namespaces", null);
160 nassembly.AppendChild (nss);
162 string current_namespace = "$%&$&";
164 XmlNode classes = null;
165 foreach (TypeDefinition t in typesArray) {
166 if (string.IsNullOrEmpty (t.Namespace))
169 if ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)
172 if (t.DeclaringType != null)
173 continue; // enforce !nested
175 if (t.Namespace != current_namespace) {
176 current_namespace = t.Namespace;
177 ns = document.CreateElement ("namespace", null);
178 AddAttribute (ns, "name", current_namespace);
179 nss.AppendChild (ns);
180 classes = document.CreateElement ("classes", null);
181 ns.AppendChild (classes);
184 TypeData bd = new TypeData (document, classes, t);
190 abstract class MemberData : BaseData
192 MemberReference [] members;
194 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
195 : base (document, parent)
197 this.members = members;
200 public override void DoOutput ()
202 XmlNode mclass = document.CreateElement (ParentTag, null);
203 parent.AppendChild (mclass);
205 foreach (MemberReference member in members) {
206 XmlNode mnode = document.CreateElement (Tag, null);
207 mclass.AppendChild (mnode);
208 AddAttribute (mnode, "name", GetName (member));
209 if (!NoMemberAttributes)
210 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
212 AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
214 AddExtraData (mnode, member);
219 protected abstract CustomAttributeCollection GetCustomAttributes (MemberReference member);
221 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
225 protected virtual string GetName (MemberReference memberDefenition)
230 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
235 public virtual bool NoMemberAttributes {
236 get { return false; }
240 public virtual string ParentTag {
241 get { return "NoPARENTTAG"; }
244 public virtual string Tag {
245 get { return "NoTAG"; }
248 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
250 if (provider.GenericParameters.Count == 0)
253 var gparameters = provider.GenericParameters;
255 XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
256 nclass.AppendChild (ngeneric);
258 foreach (GenericParameter gp in gparameters) {
259 XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
260 nparam.SetAttribute ("name", gp.Name);
261 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
263 ngeneric.AppendChild (nparam);
265 var constraints = gp.Constraints;
266 if (constraints.Count == 0)
269 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
271 foreach (TypeReference constraint in constraints) {
272 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
273 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
274 nconstraint.AppendChild (ncons);
277 nparam.AppendChild (nconstraint);
282 class TypeData : MemberData
286 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
287 : base (document, parent, null)
292 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
293 return ((TypeDefinition) member).CustomAttributes;
296 public override void DoOutput ()
298 if (document == null)
299 throw new InvalidOperationException ("Document not set");
301 XmlNode nclass = document.CreateElement ("class", null);
302 AddAttribute (nclass, "name", type.Name);
303 string classType = GetClassType (type);
304 AddAttribute (nclass, "type", classType);
306 if (type.BaseType != null)
307 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
310 AddAttribute (nclass, "sealed", "true");
313 AddAttribute (nclass, "abstract", "true");
315 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
316 AddAttribute (nclass, "serializable", "true");
318 string charSet = GetCharSet (type);
319 AddAttribute (nclass, "charset", charSet);
321 string layout = GetLayout (type);
323 AddAttribute (nclass, "layout", layout);
325 parent.AppendChild (nclass);
327 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
329 var interfaces = TypeHelper.GetInterfaces (type);
330 XmlNode ifaces = null;
332 foreach (TypeReference iface in interfaces) {
333 if (!TypeHelper.IsPublic (iface))
334 // we're only interested in public interfaces
337 if (ifaces == null) {
338 ifaces = document.CreateElement ("interfaces", null);
339 nclass.AppendChild (ifaces);
342 XmlNode iface_node = document.CreateElement ("interface", null);
343 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
344 ifaces.AppendChild (iface_node);
347 MemberData.OutputGenericParameters (document, nclass, type);
349 ArrayList members = new ArrayList ();
351 FieldDefinition [] fields = GetFields (type);
352 if (fields.Length > 0) {
353 Array.Sort (fields, MemberReferenceComparer.Default);
354 FieldData fd = new FieldData (document, nclass, fields);
355 // Special case for enum fields
356 // TODO:Special case for enum fields
357 //if (classType == "enum") {
358 // string etype = fields [0].GetType ().ToString ();
359 // AddAttribute (nclass, "enumtype", etype);
364 MethodDefinition [] ctors = GetConstructors (type);
365 if (ctors.Length > 0) {
366 Array.Sort (ctors, MemberReferenceComparer.Default);
367 members.Add (new ConstructorData (document, nclass, ctors));
370 PropertyDefinition[] properties = GetProperties (type);
371 if (properties.Length > 0) {
372 Array.Sort (properties, MemberReferenceComparer.Default);
373 members.Add (new PropertyData (document, nclass, properties));
376 EventDefinition [] events = GetEvents (type);
377 if (events.Length > 0) {
378 Array.Sort (events, MemberReferenceComparer.Default);
379 members.Add (new EventData (document, nclass, events));
382 MethodDefinition [] methods = GetMethods (type);
383 if (methods.Length > 0) {
384 Array.Sort (methods, MemberReferenceComparer.Default);
385 members.Add (new MethodData (document, nclass, methods));
388 foreach (MemberData md in members)
391 NestedTypeCollection nested = type.NestedTypes;
392 //remove non public(familiy) and nested in second degree
393 for (int i = nested.Count - 1; i >= 0; i--) {
394 TypeDefinition t = nested [i];
395 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
396 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
397 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
399 if (t.DeclaringType == type)
400 continue; // not nested of nested
407 if (nested.Count > 0) {
408 XmlNode classes = document.CreateElement ("classes", null);
409 nclass.AppendChild (classes);
410 foreach (TypeDefinition t in nested) {
411 TypeData td = new TypeData (document, classes, t);
417 protected override string GetMemberAttributes (MemberReference member)
420 throw new InvalidOperationException ("odd");
422 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
425 public static bool MustDocumentMethod (MethodDefinition method) {
427 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
428 return maskedAccess == MethodAttributes.Public
429 || maskedAccess == MethodAttributes.Family
430 || maskedAccess == MethodAttributes.FamORAssem;
433 static string GetClassType (TypeDefinition t)
444 if (TypeHelper.IsDelegate(t))
450 static string GetCharSet (TypeDefinition type)
452 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
453 if (maskedStringFormat == TypeAttributes.AnsiClass)
454 return CharSet.Ansi.ToString ();
456 if (maskedStringFormat == TypeAttributes.AutoClass)
457 return CharSet.Auto.ToString ();
459 if (maskedStringFormat == TypeAttributes.UnicodeClass)
460 return CharSet.Unicode.ToString ();
462 return CharSet.None.ToString ();
465 static string GetLayout (TypeDefinition type)
467 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
468 if (maskedLayout == TypeAttributes.AutoLayout)
469 return LayoutKind.Auto.ToString ();
471 if (maskedLayout == TypeAttributes.ExplicitLayout)
472 return LayoutKind.Explicit.ToString ();
474 if (maskedLayout == TypeAttributes.SequentialLayout)
475 return LayoutKind.Sequential.ToString ();
480 FieldDefinition [] GetFields (TypeDefinition type) {
481 ArrayList list = new ArrayList ();
483 FieldDefinitionCollection fields = type.Fields;
484 foreach (FieldDefinition field in fields) {
485 if (field.IsSpecialName)
488 // we're only interested in public or protected members
489 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
490 if (maskedVisibility == FieldAttributes.Public
491 || maskedVisibility == FieldAttributes.Family
492 || maskedVisibility == FieldAttributes.FamORAssem) {
497 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
501 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
502 ArrayList list = new ArrayList ();
504 PropertyDefinitionCollection properties = type.Properties;//type.GetProperties (flags);
505 foreach (PropertyDefinition property in properties) {
506 MethodDefinition getMethod = property.GetMethod;
507 MethodDefinition setMethod = property.SetMethod;
509 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
510 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
512 // if neither the getter or setter should be documented, then
514 if (hasGetter || hasSetter) {
519 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
522 private MethodDefinition[] GetMethods (TypeDefinition type)
524 ArrayList list = new ArrayList ();
526 MethodDefinitionCollection methods = type.Methods;//type.GetMethods (flags);
527 foreach (MethodDefinition method in methods) {
528 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
531 // we're only interested in public or protected members
532 if (!MustDocumentMethod(method))
535 if (IsFinalizer (method))
541 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
544 static bool IsFinalizer (MethodDefinition method)
546 if (method.Name != "Finalize")
549 if (!method.IsVirtual)
552 if (method.Parameters.Count != 0)
558 private MethodDefinition [] GetConstructors (TypeDefinition type)
560 ArrayList list = new ArrayList ();
562 ConstructorCollection ctors = type.Constructors;//type.GetConstructors (flags);
563 foreach (MethodDefinition constructor in ctors) {
564 // we're only interested in public or protected members
565 if (!MustDocumentMethod(constructor))
568 list.Add (constructor);
571 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
574 private EventDefinition[] GetEvents (TypeDefinition type)
576 ArrayList list = new ArrayList ();
578 EventDefinitionCollection events = type.Events;//type.GetEvents (flags);
579 foreach (EventDefinition eventDef in events) {
580 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
582 if (addMethod == null || !MustDocumentMethod (addMethod))
588 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
592 class FieldData : MemberData
594 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
595 : base (document, parent, members)
599 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
600 return ((FieldDefinition) member).CustomAttributes;
603 protected override string GetName (MemberReference memberDefenition)
605 FieldDefinition field = (FieldDefinition) memberDefenition;
609 protected override string GetMemberAttributes (MemberReference memberDefenition)
611 FieldDefinition field = (FieldDefinition) memberDefenition;
612 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
615 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
617 base.AddExtraData (p, memberDefenition);
618 FieldDefinition field = (FieldDefinition) memberDefenition;
619 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
621 if (field.IsLiteral) {
622 object value = field.Constant;//object value = field.GetValue (null);
623 string stringValue = null;
624 //if (value is Enum) {
625 // // FIXME: when Mono bug #60090 has been
626 // // fixed, we should just be able to use
627 // // Convert.ToString
628 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
631 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
634 if (stringValue != null)
635 AddAttribute (p, "value", stringValue);
639 public override string ParentTag {
640 get { return "fields"; }
643 public override string Tag {
644 get { return "field"; }
648 class PropertyData : MemberData
650 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
651 : base (document, parent, members)
655 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
656 return ((PropertyDefinition) member).CustomAttributes;
659 protected override string GetName (MemberReference memberDefenition)
661 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
665 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
667 base.AddExtraData (p, memberDefenition);
668 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
669 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
670 MethodDefinition _get = prop.GetMethod;
671 MethodDefinition _set = prop.SetMethod;
672 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
673 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
674 MethodDefinition [] methods;
676 if (haveGet && haveSet) {
677 methods = new MethodDefinition [] { _get, _set };
678 } else if (haveGet) {
679 methods = new MethodDefinition [] { _get };
680 } else if (haveSet) {
681 methods = new MethodDefinition [] { _set };
687 string parms = Parameters.GetSignature (methods [0].Parameters);
688 AddAttribute (p, "params", parms);
690 MethodData data = new MethodData (document, p, methods);
691 //data.NoMemberAttributes = true;
695 protected override string GetMemberAttributes (MemberReference memberDefenition)
697 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
698 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
701 public override string ParentTag {
702 get { return "properties"; }
705 public override string Tag {
706 get { return "property"; }
710 class EventData : MemberData
712 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
713 : base (document, parent, members)
717 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
718 return ((EventDefinition) member).CustomAttributes;
721 protected override string GetName (MemberReference memberDefenition)
723 EventDefinition evt = (EventDefinition) memberDefenition;
727 protected override string GetMemberAttributes (MemberReference memberDefenition)
729 EventDefinition evt = (EventDefinition) memberDefenition;
730 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
733 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
735 base.AddExtraData (p, memberDefenition);
736 EventDefinition evt = (EventDefinition) memberDefenition;
737 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
740 public override string ParentTag {
741 get { return "events"; }
744 public override string Tag {
745 get { return "event"; }
749 class MethodData : MemberData
753 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
754 : base (document, parent, members)
758 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
759 return ((MethodDefinition) member).CustomAttributes;
762 protected override string GetName (MemberReference memberDefenition)
764 MethodDefinition method = (MethodDefinition) memberDefenition;
765 string name = method.Name;
766 string parms = Parameters.GetSignature (method.Parameters);
768 return string.Format ("{0}({1})", name, parms);
771 protected override string GetMemberAttributes (MemberReference memberDefenition)
773 MethodDefinition method = (MethodDefinition) memberDefenition;
774 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
777 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
779 base.AddExtraData (p, memberDefenition);
781 if (!(memberDefenition is MethodDefinition))
784 MethodDefinition mbase = (MethodDefinition) memberDefenition;
786 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
789 if (mbase.IsAbstract)
790 AddAttribute (p, "abstract", "true");
792 AddAttribute (p, "virtual", "true");
794 AddAttribute (p, "static", "true");
796 //if (!(member is MethodInfo))
799 //MethodInfo method = (MethodInfo) member;
800 string rettype = Utils.CleanupTypeName (mbase.ReturnType.ReturnType);
801 if (rettype != "System.Void" || !mbase.IsConstructor)
802 AddAttribute (p, "returntype", (rettype));
804 AttributeData.OutputAttributes (document, p, mbase.ReturnType.CustomAttributes);
806 MemberData.OutputGenericParameters (document, p, mbase);
809 public override bool NoMemberAttributes {
810 get { return noAtts; }
811 set { noAtts = value; }
814 public override string ParentTag {
815 get { return "methods"; }
818 public override string Tag {
819 get { return "method"; }
823 class ConstructorData : MethodData
825 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
826 : base (document, parent, members)
830 public override string ParentTag {
831 get { return "constructors"; }
834 public override string Tag {
835 get { return "constructor"; }
839 class ParameterData : BaseData
841 private ParameterDefinitionCollection parameters;
843 public ParameterData (XmlDocument document, XmlNode parent, ParameterDefinitionCollection parameters)
844 : base (document, parent)
846 this.parameters = parameters;
849 public override void DoOutput ()
851 XmlNode parametersNode = document.CreateElement ("parameters");
852 parent.AppendChild (parametersNode);
854 foreach (ParameterDefinition parameter in parameters) {
855 XmlNode paramNode = document.CreateElement ("parameter");
856 parametersNode.AppendChild (paramNode);
857 AddAttribute (paramNode, "name", parameter.Name);
858 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
859 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
861 string direction = "in";
863 if (parameter.ParameterType is ReferenceType)
864 direction = parameter.IsOut ? "out" : "ref";
866 TypeReference t = parameter.ParameterType;
867 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
869 if (parameter.IsOptional) {
870 AddAttribute (paramNode, "optional", "true");
871 if (parameter.HasConstant)
872 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
875 if (direction != "in")
876 AddAttribute (paramNode, "direction", direction);
878 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
883 class AttributeData : BaseData
885 CustomAttributeCollection atts;
887 AttributeData (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
893 public override void DoOutput ()
895 if (document == null)
896 throw new InvalidOperationException ("Document not set");
898 if (atts == null || atts.Count == 0)
901 XmlNode natts = parent.SelectSingleNode("attributes");
903 natts = document.CreateElement ("attributes", null);
904 parent.AppendChild (natts);
907 for (int i = 0; i < atts.Count; ++i) {
908 CustomAttribute att = atts [i];
916 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
917 if (SkipAttribute (att))
920 XmlNode node = document.CreateElement ("attribute");
921 AddAttribute (node, "name", attName);
923 XmlNode properties = null;
925 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
927 foreach (string name in attribute_mapping.Keys) {
928 if (name == "TypeId")
931 if (properties == null) {
932 properties = node.AppendChild (document.CreateElement ("properties"));
935 object o = attribute_mapping [name];
937 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
938 AddAttribute (n, "name", name);
941 AddAttribute (n, "value", "null");
944 string value = o.ToString ();
945 if (attName.EndsWith ("GuidAttribute"))
946 value = value.ToUpper ();
947 AddAttribute (n, "value", value);
950 natts.AppendChild (node);
954 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
956 var mapping = new Dictionary<string, object> ();
958 PopulateMapping (mapping, attribute);
960 var constructor = TypeHelper.Resolver.Resolve (attribute.Constructor);
961 if (constructor == null || constructor.Parameters.Count == 0)
964 PopulateMapping (mapping, constructor, attribute);
969 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
971 foreach (DictionaryEntry entry in attribute.Properties) {
972 var name = (string) entry.Key;
974 mapping.Add (name, GetArgumentValue (attribute.GetPropertyType (name), entry.Value));
978 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
980 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
982 int? argument = null;
984 foreach (Instruction instruction in constructor.Body.Instructions) {
985 switch (instruction.OpCode.Code) {
997 argument = ((ParameterDefinition) instruction.Operand).Sequence;
1001 FieldReference field = (FieldReference) instruction.Operand;
1002 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1005 if (!argument.HasValue)
1008 if (!field_mapping.ContainsKey (field))
1009 field_mapping.Add (field, (int) argument - 1);
1016 return field_mapping;
1019 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1021 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1023 foreach (PropertyDefinition property in type.Properties) {
1024 if (property.GetMethod == null)
1026 if (!property.GetMethod.HasBody)
1029 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1030 if (instruction.OpCode.Code != Code.Ldfld)
1033 FieldReference field = (FieldReference) instruction.Operand;
1034 if (field.DeclaringType.FullName != type.FullName)
1037 property_mapping.Add (property, field);
1042 return property_mapping;
1045 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1047 if (!constructor.HasBody)
1050 var field_mapping = CreateArgumentFieldMapping (constructor);
1051 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1053 foreach (var pair in property_mapping) {
1055 if (!field_mapping.TryGetValue (pair.Value, out argument))
1058 mapping.Add (pair.Key.Name, GetArgumentValue (constructor.Parameters [argument].ParameterType, attribute.ConstructorParameters [argument]));
1062 static object GetArgumentValue (TypeReference reference, object value)
1064 var type = TypeHelper.Resolver.Resolve (reference);
1069 if (IsFlaggedEnum (type))
1070 return GetFlaggedEnumValue (type, value);
1072 return GetEnumValue (type, value);
1078 static bool IsFlaggedEnum (TypeDefinition type)
1083 if (type.CustomAttributes.Count == 0)
1086 foreach (CustomAttribute attribute in type.CustomAttributes)
1087 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1093 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1095 long flags = Convert.ToInt64 (value);
1096 var signature = new StringBuilder ();
1098 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1099 FieldDefinition field = type.Fields [i];
1101 if (!field.HasConstant)
1104 long flag = Convert.ToInt64 (field.Constant);
1109 if ((flags & flag) == flag) {
1110 if (signature.Length != 0)
1111 signature.Append (", ");
1113 signature.Append (field.Name);
1118 return signature.ToString ();
1121 static object GetEnumValue (TypeDefinition type, object value)
1123 foreach (FieldDefinition field in type.Fields) {
1124 if (!field.HasConstant)
1127 if (Comparer.Default.Compare (field.Constant, value) == 0)
1134 static bool SkipAttribute (CustomAttribute attribute)
1136 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1138 return !TypeHelper.IsPublic (attribute)
1139 || type_name.EndsWith ("TODOAttribute");
1142 public static void OutputAttributes (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
1144 AttributeData ad = new AttributeData (doc, parent, attributes);
1149 static class Parameters {
1151 public static string GetSignature (ParameterDefinitionCollection infos)
1153 if (infos == null || infos.Count == 0)
1156 var signature = new StringBuilder ();
1157 for (int i = 0; i < infos.Count; i++) {
1160 signature.Append (", ");
1162 ParameterDefinition info = infos [i];
1165 if ((info.Attributes & ParameterAttributes.In) != 0)
1167 else if (((int)info.Attributes & 0x8) != 0) // retval
1169 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1172 modifier = string.Empty;
1174 if (modifier.Length > 0)
1175 signature.AppendFormat ("{0} ", modifier);
1177 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1180 return signature.ToString ();
1185 class TypeReferenceComparer : IComparer
1187 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1189 public int Compare (object a, object b)
1191 TypeReference ta = (TypeReference) a;
1192 TypeReference tb = (TypeReference) b;
1193 int result = String.Compare (ta.Namespace, tb.Namespace);
1197 return String.Compare (ta.Name, tb.Name);
1201 class MemberReferenceComparer : IComparer
1203 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1205 public int Compare (object a, object b)
1207 MemberReference ma = (MemberReference) a;
1208 MemberReference mb = (MemberReference) b;
1209 return String.Compare (ma.Name, mb.Name);
1213 class MethodDefinitionComparer : IComparer
1215 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1217 public int Compare (object a, object b)
1219 MethodDefinition ma = (MethodDefinition) a;
1220 MethodDefinition mb = (MethodDefinition) b;
1221 int res = String.Compare (ma.Name, mb.Name);
1225 ParameterDefinitionCollection pia = ma.Parameters ;
1226 ParameterDefinitionCollection pib = mb.Parameters;
1227 res = pia.Count - pib.Count;
1231 string siga = Parameters.GetSignature (pia);
1232 string sigb = Parameters.GetSignature (pib);
1233 return String.Compare (siga, sigb);