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;
21 using Mono.Util.CorCompare.Cecil;
23 namespace Mono.AssemblyInfo
27 public static int Main (string [] args)
32 AssemblyCollection acoll = new AssemblyCollection ();
34 foreach (string fullName in args) {
38 XmlDocument doc = new XmlDocument ();
42 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
43 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
44 doc.InsertBefore (decl, doc.DocumentElement);
52 public static string CleanupTypeName (TypeReference type)
54 return CleanupTypeName (type.FullName);
57 static string CleanupTypeName (string t)
59 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
63 class AssemblyCollection
66 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
68 public AssemblyCollection ()
72 public bool Add (string name)
74 AssemblyDefinition ass = LoadAssembly (name);
82 public void DoOutput ()
85 throw new InvalidOperationException ("Document not set");
87 XmlNode nassemblies = document.CreateElement ("assemblies", null);
88 document.AppendChild (nassemblies);
89 foreach (AssemblyDefinition a in assemblies) {
90 AssemblyData data = new AssemblyData (document, nassemblies, a);
95 public XmlDocument Document {
96 set { document = value; }
99 AssemblyDefinition LoadAssembly (string assembly)
102 return TypeHelper.Resolver.Resolve (assembly);
109 abstract class BaseData
111 protected XmlDocument document;
112 protected XmlNode parent;
114 protected BaseData (XmlDocument doc, XmlNode parent)
117 this.parent = parent;
120 public abstract void DoOutput ();
122 protected void AddAttribute (XmlNode node, string name, string value)
124 XmlAttribute attr = document.CreateAttribute (name);
126 node.Attributes.Append (attr);
130 class AssemblyData : BaseData
132 AssemblyDefinition ass;
134 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
135 : base (document, parent)
140 public override void DoOutput ()
142 if (document == null)
143 throw new InvalidOperationException ("Document not set");
145 XmlNode nassembly = document.CreateElement ("assembly", null);
146 AssemblyNameDefinition aname = ass.Name;
147 AddAttribute (nassembly, "name", aname.Name);
148 AddAttribute (nassembly, "version", aname.Version.ToString ());
149 parent.AppendChild (nassembly);
150 AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
151 TypeDefinitionCollection typesCollection = ass.MainModule.Types;
152 if (typesCollection == null || typesCollection.Count == 0)
154 object [] typesArray = new object [typesCollection.Count];
155 for (int i = 0; i < typesCollection.Count; i++) {
156 typesArray [i] = typesCollection [i];
158 Array.Sort (typesArray, TypeReferenceComparer.Default);
160 XmlNode nss = document.CreateElement ("namespaces", null);
161 nassembly.AppendChild (nss);
163 string current_namespace = "$%&$&";
165 XmlNode classes = null;
166 foreach (TypeDefinition t in typesArray) {
167 if (string.IsNullOrEmpty (t.Namespace))
170 if ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)
173 if (t.DeclaringType != null)
174 continue; // enforce !nested
176 if (t.Namespace != current_namespace) {
177 current_namespace = t.Namespace;
178 ns = document.CreateElement ("namespace", null);
179 AddAttribute (ns, "name", current_namespace);
180 nss.AppendChild (ns);
181 classes = document.CreateElement ("classes", null);
182 ns.AppendChild (classes);
185 TypeData bd = new TypeData (document, classes, t);
191 abstract class MemberData : BaseData
193 MemberReference [] members;
195 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
196 : base (document, parent)
198 this.members = members;
201 public override void DoOutput ()
203 XmlNode mclass = document.CreateElement (ParentTag, null);
204 parent.AppendChild (mclass);
206 foreach (MemberReference member in members) {
207 XmlNode mnode = document.CreateElement (Tag, null);
208 mclass.AppendChild (mnode);
209 AddAttribute (mnode, "name", GetName (member));
210 if (!NoMemberAttributes)
211 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
213 AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
215 AddExtraData (mnode, member);
220 protected abstract CustomAttributeCollection GetCustomAttributes (MemberReference member);
222 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
226 protected virtual string GetName (MemberReference memberDefenition)
231 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
236 public virtual bool NoMemberAttributes {
237 get { return false; }
241 public virtual string ParentTag {
242 get { return "NoPARENTTAG"; }
245 public virtual string Tag {
246 get { return "NoTAG"; }
249 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
251 if (provider.GenericParameters.Count == 0)
254 var gparameters = provider.GenericParameters;
256 XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
257 nclass.AppendChild (ngeneric);
259 foreach (GenericParameter gp in gparameters) {
260 XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
261 nparam.SetAttribute ("name", gp.Name);
262 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
264 ngeneric.AppendChild (nparam);
266 var constraints = gp.Constraints;
267 if (constraints.Count == 0)
270 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
272 foreach (TypeReference constraint in constraints) {
273 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
274 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
275 nconstraint.AppendChild (ncons);
278 nparam.AppendChild (nconstraint);
283 class TypeData : MemberData
287 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
288 : base (document, parent, null)
293 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
294 return ((TypeDefinition) member).CustomAttributes;
297 public override void DoOutput ()
299 if (document == null)
300 throw new InvalidOperationException ("Document not set");
302 XmlNode nclass = document.CreateElement ("class", null);
303 AddAttribute (nclass, "name", type.Name);
304 string classType = GetClassType (type);
305 AddAttribute (nclass, "type", classType);
307 if (type.BaseType != null)
308 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
311 AddAttribute (nclass, "sealed", "true");
314 AddAttribute (nclass, "abstract", "true");
316 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
317 AddAttribute (nclass, "serializable", "true");
319 string charSet = GetCharSet (type);
320 AddAttribute (nclass, "charset", charSet);
322 string layout = GetLayout (type);
324 AddAttribute (nclass, "layout", layout);
326 parent.AppendChild (nclass);
328 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
330 var interfaces = TypeHelper.GetInterfaces (type);
331 XmlNode ifaces = null;
333 foreach (TypeReference iface in interfaces) {
334 if (!TypeHelper.IsPublic (iface))
335 // we're only interested in public interfaces
338 if (ifaces == null) {
339 ifaces = document.CreateElement ("interfaces", null);
340 nclass.AppendChild (ifaces);
343 XmlNode iface_node = document.CreateElement ("interface", null);
344 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
345 ifaces.AppendChild (iface_node);
348 MemberData.OutputGenericParameters (document, nclass, type);
350 ArrayList members = new ArrayList ();
352 FieldDefinition [] fields = GetFields (type);
353 if (fields.Length > 0) {
354 Array.Sort (fields, MemberReferenceComparer.Default);
355 FieldData fd = new FieldData (document, nclass, fields);
356 // Special case for enum fields
357 // TODO:Special case for enum fields
358 //if (classType == "enum") {
359 // string etype = fields [0].GetType ().ToString ();
360 // AddAttribute (nclass, "enumtype", etype);
365 MethodDefinition [] ctors = GetConstructors (type);
366 if (ctors.Length > 0) {
367 Array.Sort (ctors, MemberReferenceComparer.Default);
368 members.Add (new ConstructorData (document, nclass, ctors));
371 PropertyDefinition[] properties = GetProperties (type);
372 if (properties.Length > 0) {
373 Array.Sort (properties, MemberReferenceComparer.Default);
374 members.Add (new PropertyData (document, nclass, properties));
377 EventDefinition [] events = GetEvents (type);
378 if (events.Length > 0) {
379 Array.Sort (events, MemberReferenceComparer.Default);
380 members.Add (new EventData (document, nclass, events));
383 MethodDefinition [] methods = GetMethods (type);
384 if (methods.Length > 0) {
385 Array.Sort (methods, MemberReferenceComparer.Default);
386 members.Add (new MethodData (document, nclass, methods));
389 foreach (MemberData md in members)
392 NestedTypeCollection nested = type.NestedTypes;
393 //remove non public(familiy) and nested in second degree
394 for (int i = nested.Count - 1; i >= 0; i--) {
395 TypeDefinition t = nested [i];
396 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
397 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
398 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
400 if (t.DeclaringType == type)
401 continue; // not nested of nested
408 if (nested.Count > 0) {
409 XmlNode classes = document.CreateElement ("classes", null);
410 nclass.AppendChild (classes);
411 foreach (TypeDefinition t in nested) {
412 TypeData td = new TypeData (document, classes, t);
418 protected override string GetMemberAttributes (MemberReference member)
421 throw new InvalidOperationException ("odd");
423 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
426 public static bool MustDocumentMethod (MethodDefinition method) {
428 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
429 return maskedAccess == MethodAttributes.Public
430 || maskedAccess == MethodAttributes.Family
431 || maskedAccess == MethodAttributes.FamORAssem;
434 static string GetClassType (TypeDefinition t)
445 if (TypeHelper.IsDelegate(t))
451 static string GetCharSet (TypeDefinition type)
453 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
454 if (maskedStringFormat == TypeAttributes.AnsiClass)
455 return CharSet.Ansi.ToString ();
457 if (maskedStringFormat == TypeAttributes.AutoClass)
458 return CharSet.Auto.ToString ();
460 if (maskedStringFormat == TypeAttributes.UnicodeClass)
461 return CharSet.Unicode.ToString ();
463 return CharSet.None.ToString ();
466 static string GetLayout (TypeDefinition type)
468 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
469 if (maskedLayout == TypeAttributes.AutoLayout)
470 return LayoutKind.Auto.ToString ();
472 if (maskedLayout == TypeAttributes.ExplicitLayout)
473 return LayoutKind.Explicit.ToString ();
475 if (maskedLayout == TypeAttributes.SequentialLayout)
476 return LayoutKind.Sequential.ToString ();
481 FieldDefinition [] GetFields (TypeDefinition type) {
482 ArrayList list = new ArrayList ();
484 FieldDefinitionCollection fields = type.Fields;
485 foreach (FieldDefinition field in fields) {
486 if (field.IsSpecialName)
489 // we're only interested in public or protected members
490 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
491 if (maskedVisibility == FieldAttributes.Public
492 || maskedVisibility == FieldAttributes.Family
493 || maskedVisibility == FieldAttributes.FamORAssem) {
498 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
502 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
503 ArrayList list = new ArrayList ();
505 PropertyDefinitionCollection properties = type.Properties;//type.GetProperties (flags);
506 foreach (PropertyDefinition property in properties) {
507 MethodDefinition getMethod = property.GetMethod;
508 MethodDefinition setMethod = property.SetMethod;
510 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
511 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
513 // if neither the getter or setter should be documented, then
515 if (hasGetter || hasSetter) {
520 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
523 private MethodDefinition[] GetMethods (TypeDefinition type)
525 ArrayList list = new ArrayList ();
527 MethodDefinitionCollection methods = type.Methods;//type.GetMethods (flags);
528 foreach (MethodDefinition method in methods) {
529 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
532 // we're only interested in public or protected members
533 if (!MustDocumentMethod(method))
539 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
542 private MethodDefinition [] GetConstructors (TypeDefinition type)
544 ArrayList list = new ArrayList ();
546 ConstructorCollection ctors = type.Constructors;//type.GetConstructors (flags);
547 foreach (MethodDefinition constructor in ctors) {
548 // we're only interested in public or protected members
549 if (!MustDocumentMethod(constructor))
552 list.Add (constructor);
555 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
558 private EventDefinition[] GetEvents (TypeDefinition type)
560 ArrayList list = new ArrayList ();
562 EventDefinitionCollection events = type.Events;//type.GetEvents (flags);
563 foreach (EventDefinition eventDef in events) {
564 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
566 if (addMethod == null || !MustDocumentMethod (addMethod))
572 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
576 class FieldData : MemberData
578 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
579 : base (document, parent, members)
583 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
584 return ((FieldDefinition) member).CustomAttributes;
587 protected override string GetName (MemberReference memberDefenition)
589 FieldDefinition field = (FieldDefinition) memberDefenition;
593 protected override string GetMemberAttributes (MemberReference memberDefenition)
595 FieldDefinition field = (FieldDefinition) memberDefenition;
596 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
599 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
601 base.AddExtraData (p, memberDefenition);
602 FieldDefinition field = (FieldDefinition) memberDefenition;
603 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
605 if (field.IsLiteral) {
606 object value = field.Constant;//object value = field.GetValue (null);
607 string stringValue = null;
608 //if (value is Enum) {
609 // // FIXME: when Mono bug #60090 has been
610 // // fixed, we should just be able to use
611 // // Convert.ToString
612 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
615 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
618 if (stringValue != null)
619 AddAttribute (p, "value", stringValue);
623 public override string ParentTag {
624 get { return "fields"; }
627 public override string Tag {
628 get { return "field"; }
632 class PropertyData : MemberData
634 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
635 : base (document, parent, members)
639 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
640 return ((PropertyDefinition) member).CustomAttributes;
643 protected override string GetName (MemberReference memberDefenition)
645 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
649 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
651 base.AddExtraData (p, memberDefenition);
652 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
653 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
654 MethodDefinition _get = prop.GetMethod;
655 MethodDefinition _set = prop.SetMethod;
656 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
657 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
658 MethodDefinition [] methods;
660 if (haveGet && haveSet) {
661 methods = new MethodDefinition [] { _get, _set };
662 } else if (haveGet) {
663 methods = new MethodDefinition [] { _get };
664 } else if (haveSet) {
665 methods = new MethodDefinition [] { _set };
671 string parms = Parameters.GetSignature (methods [0].Parameters);
672 AddAttribute (p, "params", parms);
674 MethodData data = new MethodData (document, p, methods);
675 //data.NoMemberAttributes = true;
679 protected override string GetMemberAttributes (MemberReference memberDefenition)
681 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
682 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
685 public override string ParentTag {
686 get { return "properties"; }
689 public override string Tag {
690 get { return "property"; }
694 class EventData : MemberData
696 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
697 : base (document, parent, members)
701 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
702 return ((EventDefinition) member).CustomAttributes;
705 protected override string GetName (MemberReference memberDefenition)
707 EventDefinition evt = (EventDefinition) memberDefenition;
711 protected override string GetMemberAttributes (MemberReference memberDefenition)
713 EventDefinition evt = (EventDefinition) memberDefenition;
714 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
717 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
719 base.AddExtraData (p, memberDefenition);
720 EventDefinition evt = (EventDefinition) memberDefenition;
721 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
724 public override string ParentTag {
725 get { return "events"; }
728 public override string Tag {
729 get { return "event"; }
733 class MethodData : MemberData
737 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
738 : base (document, parent, members)
742 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
743 return ((MethodDefinition) member).CustomAttributes;
746 protected override string GetName (MemberReference memberDefenition)
748 MethodDefinition method = (MethodDefinition) memberDefenition;
749 string name = method.Name;
750 string parms = Parameters.GetSignature (method.Parameters);
752 return string.Format ("{0}({1})", name, parms);
755 protected override string GetMemberAttributes (MemberReference memberDefenition)
757 MethodDefinition method = (MethodDefinition) memberDefenition;
758 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
761 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
763 base.AddExtraData (p, memberDefenition);
765 if (!(memberDefenition is MethodDefinition))
768 MethodDefinition mbase = (MethodDefinition) memberDefenition;
770 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
773 if (mbase.IsAbstract)
774 AddAttribute (p, "abstract", "true");
776 AddAttribute (p, "virtual", "true");
778 AddAttribute (p, "static", "true");
780 //if (!(member is MethodInfo))
783 //MethodInfo method = (MethodInfo) member;
784 string rettype = Utils.CleanupTypeName (mbase.ReturnType.ReturnType);
785 if (rettype != "System.Void" || !mbase.IsConstructor)
786 AddAttribute (p, "returntype", (rettype));
788 AttributeData.OutputAttributes (document, p, mbase.ReturnType.CustomAttributes);
790 MemberData.OutputGenericParameters (document, p, mbase);
793 public override bool NoMemberAttributes {
794 get { return noAtts; }
795 set { noAtts = value; }
798 public override string ParentTag {
799 get { return "methods"; }
802 public override string Tag {
803 get { return "method"; }
807 class ConstructorData : MethodData
809 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
810 : base (document, parent, members)
814 public override string ParentTag {
815 get { return "constructors"; }
818 public override string Tag {
819 get { return "constructor"; }
823 class ParameterData : BaseData
825 private ParameterDefinitionCollection parameters;
827 public ParameterData (XmlDocument document, XmlNode parent, ParameterDefinitionCollection parameters)
828 : base (document, parent)
830 this.parameters = parameters;
833 public override void DoOutput ()
835 XmlNode parametersNode = document.CreateElement ("parameters");
836 parent.AppendChild (parametersNode);
838 foreach (ParameterDefinition parameter in parameters) {
839 XmlNode paramNode = document.CreateElement ("parameter");
840 parametersNode.AppendChild (paramNode);
841 AddAttribute (paramNode, "name", parameter.Name);
842 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
843 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
845 string direction = "in";
847 if (parameter.ParameterType is ReferenceType)
848 direction = parameter.IsOut ? "out" : "ref";
850 TypeReference t = parameter.ParameterType;
851 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
853 if (parameter.IsOptional) {
854 AddAttribute (paramNode, "optional", "true");
855 if (parameter.HasConstant)
856 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
859 if (direction != "in")
860 AddAttribute (paramNode, "direction", direction);
862 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
867 class AttributeData : BaseData
869 CustomAttributeCollection atts;
871 AttributeData (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
877 public override void DoOutput ()
879 if (document == null)
880 throw new InvalidOperationException ("Document not set");
882 if (atts == null || atts.Count == 0)
885 XmlNode natts = parent.SelectSingleNode("attributes");
887 natts = document.CreateElement ("attributes", null);
888 parent.AppendChild (natts);
891 for (int i = 0; i < atts.Count; ++i) {
892 CustomAttribute att = atts [i];
900 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
901 if (SkipAttribute (att))
904 XmlNode node = document.CreateElement ("attribute");
905 AddAttribute (node, "name", attName);
907 XmlNode properties = null;
909 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
911 foreach (string name in attribute_mapping.Keys) {
912 if (name == "TypeId")
915 if (properties == null) {
916 properties = node.AppendChild (document.CreateElement ("properties"));
919 object o = attribute_mapping [name];
921 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
922 AddAttribute (n, "name", name);
925 AddAttribute (n, "value", "null");
928 string value = o.ToString ();
929 if (attName.EndsWith ("GuidAttribute"))
930 value = value.ToUpper ();
931 AddAttribute (n, "value", value);
934 natts.AppendChild (node);
938 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
940 var mapping = new Dictionary<string, object> ();
942 PopulateMapping (mapping, attribute);
944 var constructor = TypeHelper.Resolver.Resolve (attribute.Constructor);
945 if (constructor == null || constructor.Parameters.Count == 0)
948 PopulateMapping (mapping, constructor, attribute);
953 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
955 foreach (DictionaryEntry entry in attribute.Properties) {
956 var name = (string) entry.Key;
958 mapping.Add (name, GetArgumentValue (attribute.GetPropertyType (name), entry.Value));
962 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
964 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
966 int? argument = null;
968 foreach (Instruction instruction in constructor.Body.Instructions) {
969 switch (instruction.OpCode.Code) {
981 argument = ((ParameterDefinition) instruction.Operand).Sequence;
985 FieldReference field = (FieldReference) instruction.Operand;
986 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
989 if (!argument.HasValue)
992 if (!field_mapping.ContainsKey (field))
993 field_mapping.Add (field, (int) argument - 1);
1000 return field_mapping;
1003 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1005 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1007 foreach (PropertyDefinition property in type.Properties) {
1008 if (property.GetMethod == null)
1010 if (!property.GetMethod.HasBody)
1013 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1014 if (instruction.OpCode.Code != Code.Ldfld)
1017 FieldReference field = (FieldReference) instruction.Operand;
1018 if (field.DeclaringType.FullName != type.FullName)
1021 property_mapping.Add (property, field);
1026 return property_mapping;
1029 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1031 if (!constructor.HasBody)
1034 var field_mapping = CreateArgumentFieldMapping (constructor);
1035 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1037 foreach (var pair in property_mapping) {
1039 if (!field_mapping.TryGetValue (pair.Value, out argument))
1042 mapping.Add (pair.Key.Name, GetArgumentValue (constructor.Parameters [argument].ParameterType, attribute.ConstructorParameters [argument]));
1046 static object GetArgumentValue (TypeReference reference, object value)
1048 var type = TypeHelper.Resolver.Resolve (reference);
1053 if (IsFlaggedEnum (type))
1054 return GetFlaggedEnumValue (type, value);
1056 return GetEnumValue (type, value);
1062 static bool IsFlaggedEnum (TypeDefinition type)
1067 if (type.CustomAttributes.Count == 0)
1070 foreach (CustomAttribute attribute in type.CustomAttributes)
1071 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1077 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1079 long flags = Convert.ToInt64 (value);
1080 var signature = new StringBuilder ();
1082 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1083 FieldDefinition field = type.Fields [i];
1085 if (!field.HasConstant)
1088 long flag = Convert.ToInt64 (field.Constant);
1093 if ((flags & flag) == flag) {
1094 if (signature.Length != 0)
1095 signature.Append (", ");
1097 signature.Append (field.Name);
1102 return signature.ToString ();
1105 static object GetEnumValue (TypeDefinition type, object value)
1107 foreach (FieldDefinition field in type.Fields) {
1108 if (!field.HasConstant)
1111 if (Comparer.Default.Compare (field.Constant, value) == 0)
1118 static bool SkipAttribute (CustomAttribute attribute)
1120 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1122 return !TypeHelper.IsPublic (attribute)
1123 || type_name.EndsWith ("TODOAttribute");
1126 public static void OutputAttributes (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
1128 AttributeData ad = new AttributeData (doc, parent, attributes);
1133 static class Parameters {
1135 public static string GetSignature (ParameterDefinitionCollection infos)
1137 if (infos == null || infos.Count == 0)
1140 var signature = new StringBuilder ();
1141 for (int i = 0; i < infos.Count; i++) {
1144 signature.Append (", ");
1146 ParameterDefinition info = infos [i];
1149 if ((info.Attributes & ParameterAttributes.In) != 0)
1151 else if (((int)info.Attributes & 0x8) != 0) // retval
1153 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1156 modifier = string.Empty;
1158 if (modifier.Length > 0)
1159 signature.AppendFormat ("{0} ", modifier);
1161 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1164 return signature.ToString ();
1169 class TypeReferenceComparer : IComparer
1171 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1173 public int Compare (object a, object b)
1175 TypeReference ta = (TypeReference) a;
1176 TypeReference tb = (TypeReference) b;
1177 int result = String.Compare (ta.Namespace, tb.Namespace);
1181 return String.Compare (ta.Name, tb.Name);
1185 class MemberReferenceComparer : IComparer
1187 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1189 public int Compare (object a, object b)
1191 MemberReference ma = (MemberReference) a;
1192 MemberReference mb = (MemberReference) b;
1193 return String.Compare (ma.Name, mb.Name);
1197 class MethodDefinitionComparer : IComparer
1199 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1201 public int Compare (object a, object b)
1203 MethodDefinition ma = (MethodDefinition) a;
1204 MethodDefinition mb = (MethodDefinition) b;
1205 int res = String.Compare (ma.Name, mb.Name);
1209 ParameterDefinitionCollection pia = ma.Parameters ;
1210 ParameterDefinitionCollection pib = mb.Parameters;
1211 res = pia.Count - pib.Count;
1215 string siga = Parameters.GetSignature (pia);
1216 string sigb = Parameters.GetSignature (pib);
1217 return String.Compare (siga, sigb);