* xbuild/Microsoft.Common.targets: For referenced projects,
[mcs.git] / tools / corcompare / mono-api-info.cs
blob0c3e60cb6af76fadcd13d232094879ae5f49a306
1 //
2 // mono-api-info.cs - Dumps public assembly information to an xml file.
3 //
4 // Authors:
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // Copyright (C) 2003-2008 Novell, Inc (http://www.novell.com)
8 //
10 using System;
11 using System.Collections;
12 using System.Collections.Generic;
13 using System.Globalization;
14 using System.Runtime.InteropServices;
15 using System.Security.Permissions;
16 using System.Text;
17 using System.Xml;
19 using Mono.Cecil;
20 using Mono.Cecil.Cil;
22 namespace CorCompare
24 public class Driver
26 public static int Main (string [] args)
28 if (args.Length == 0)
29 return 1;
31 AssemblyCollection acoll = new AssemblyCollection ();
33 foreach (string fullName in args) {
34 acoll.Add (fullName);
37 XmlDocument doc = new XmlDocument ();
38 acoll.Document = doc;
39 acoll.DoOutput ();
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);
44 doc.WriteTo (writer);
45 return 0;
49 public class Utils {
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
64 XmlDocument document;
65 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
67 public AssemblyCollection ()
71 public bool Add (string name)
73 AssemblyDefinition ass = LoadAssembly (name);
74 if (ass == null)
75 return false;
77 assemblies.Add (ass);
78 return true;
81 public void DoOutput ()
83 if (document == null)
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);
90 data.DoOutput ();
94 public XmlDocument Document {
95 set { document = value; }
98 AssemblyDefinition LoadAssembly (string assembly)
100 try {
101 return TypeHelper.Resolver.Resolve (assembly);
102 } catch {
103 return null;
108 abstract class BaseData
110 protected XmlDocument document;
111 protected XmlNode parent;
113 protected BaseData (XmlDocument doc, XmlNode parent)
115 this.document = doc;
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);
124 attr.Value = value;
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)
136 this.ass = ass;
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)
152 return;
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 = "$%&$&";
163 XmlNode ns = null;
164 XmlNode classes = null;
165 foreach (TypeDefinition t in typesArray) {
166 if (string.IsNullOrEmpty (t.Namespace))
167 continue;
169 if ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)
170 continue;
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);
185 bd.DoOutput ();
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)
227 return "NoNAME";
230 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
232 return null;
235 public virtual bool NoMemberAttributes {
236 get { return false; }
237 set {}
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)
251 return;
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 AttributeData.OutputAttributes (document, nparam, gp.CustomAttributes);
265 ngeneric.AppendChild (nparam);
267 var constraints = gp.Constraints;
268 if (constraints.Count == 0)
269 continue;
271 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
273 foreach (TypeReference constraint in constraints) {
274 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
275 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
276 nconstraint.AppendChild (ncons);
279 nparam.AppendChild (nconstraint);
284 class TypeData : MemberData
286 TypeDefinition type;
288 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
289 : base (document, parent, null)
291 this.type = type;
294 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
295 return ((TypeDefinition) member).CustomAttributes;
298 public override void DoOutput ()
300 if (document == null)
301 throw new InvalidOperationException ("Document not set");
303 XmlNode nclass = document.CreateElement ("class", null);
304 AddAttribute (nclass, "name", type.Name);
305 string classType = GetClassType (type);
306 AddAttribute (nclass, "type", classType);
308 if (type.BaseType != null)
309 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
311 if (type.IsSealed)
312 AddAttribute (nclass, "sealed", "true");
314 if (type.IsAbstract)
315 AddAttribute (nclass, "abstract", "true");
317 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
318 AddAttribute (nclass, "serializable", "true");
320 string charSet = GetCharSet (type);
321 AddAttribute (nclass, "charset", charSet);
323 string layout = GetLayout (type);
324 if (layout != null)
325 AddAttribute (nclass, "layout", layout);
327 parent.AppendChild (nclass);
329 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
331 XmlNode ifaces = null;
333 foreach (TypeReference iface in TypeHelper.GetInterfaces (type)) {
334 if (!TypeHelper.IsPublic (iface))
335 // we're only interested in public interfaces
336 continue;
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 members.Add (fd);
359 if (type.IsEnum) {
360 var value_type = GetEnumValueField (type);
361 if (value_type == null)
362 throw new NotSupportedException ();
364 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
367 MethodDefinition [] ctors = GetConstructors (type);
368 if (ctors.Length > 0) {
369 Array.Sort (ctors, MemberReferenceComparer.Default);
370 members.Add (new ConstructorData (document, nclass, ctors));
373 PropertyDefinition[] properties = GetProperties (type);
374 if (properties.Length > 0) {
375 Array.Sort (properties, MemberReferenceComparer.Default);
376 members.Add (new PropertyData (document, nclass, properties));
379 EventDefinition [] events = GetEvents (type);
380 if (events.Length > 0) {
381 Array.Sort (events, MemberReferenceComparer.Default);
382 members.Add (new EventData (document, nclass, events));
385 MethodDefinition [] methods = GetMethods (type);
386 if (methods.Length > 0) {
387 Array.Sort (methods, MemberReferenceComparer.Default);
388 members.Add (new MethodData (document, nclass, methods));
391 foreach (MemberData md in members)
392 md.DoOutput ();
394 NestedTypeCollection nested = type.NestedTypes;
395 //remove non public(familiy) and nested in second degree
396 for (int i = nested.Count - 1; i >= 0; i--) {
397 TypeDefinition t = nested [i];
398 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
399 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
400 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
401 // public
402 if (t.DeclaringType == type)
403 continue; // not nested of nested
406 nested.RemoveAt (i);
410 if (nested.Count > 0) {
411 XmlNode classes = document.CreateElement ("classes", null);
412 nclass.AppendChild (classes);
413 foreach (TypeDefinition t in nested) {
414 TypeData td = new TypeData (document, classes, t);
415 td.DoOutput ();
420 static FieldReference GetEnumValueField (TypeDefinition type)
422 foreach (FieldDefinition field in type.Fields)
423 if (field.IsSpecialName && field.Name == "value__")
424 return field;
426 return null;
429 protected override string GetMemberAttributes (MemberReference member)
431 if (member != type)
432 throw new InvalidOperationException ("odd");
434 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
437 public static bool MustDocumentMethod (MethodDefinition method) {
438 // All other methods
439 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
440 return maskedAccess == MethodAttributes.Public
441 || maskedAccess == MethodAttributes.Family
442 || maskedAccess == MethodAttributes.FamORAssem;
445 static string GetClassType (TypeDefinition t)
447 if (t.IsEnum)
448 return "enum";
450 if (t.IsValueType)
451 return "struct";
453 if (t.IsInterface)
454 return "interface";
456 if (TypeHelper.IsDelegate(t))
457 return "delegate";
459 return "class";
462 static string GetCharSet (TypeDefinition type)
464 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
465 if (maskedStringFormat == TypeAttributes.AnsiClass)
466 return CharSet.Ansi.ToString ();
468 if (maskedStringFormat == TypeAttributes.AutoClass)
469 return CharSet.Auto.ToString ();
471 if (maskedStringFormat == TypeAttributes.UnicodeClass)
472 return CharSet.Unicode.ToString ();
474 return CharSet.None.ToString ();
477 static string GetLayout (TypeDefinition type)
479 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
480 if (maskedLayout == TypeAttributes.AutoLayout)
481 return LayoutKind.Auto.ToString ();
483 if (maskedLayout == TypeAttributes.ExplicitLayout)
484 return LayoutKind.Explicit.ToString ();
486 if (maskedLayout == TypeAttributes.SequentialLayout)
487 return LayoutKind.Sequential.ToString ();
489 return null;
492 FieldDefinition [] GetFields (TypeDefinition type) {
493 ArrayList list = new ArrayList ();
495 FieldDefinitionCollection fields = type.Fields;
496 foreach (FieldDefinition field in fields) {
497 if (field.IsSpecialName)
498 continue;
500 // we're only interested in public or protected members
501 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
502 if (maskedVisibility == FieldAttributes.Public
503 || maskedVisibility == FieldAttributes.Family
504 || maskedVisibility == FieldAttributes.FamORAssem) {
505 list.Add (field);
509 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
513 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
514 ArrayList list = new ArrayList ();
516 PropertyDefinitionCollection properties = type.Properties;//type.GetProperties (flags);
517 foreach (PropertyDefinition property in properties) {
518 MethodDefinition getMethod = property.GetMethod;
519 MethodDefinition setMethod = property.SetMethod;
521 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
522 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
524 // if neither the getter or setter should be documented, then
525 // skip the property
526 if (hasGetter || hasSetter) {
527 list.Add (property);
531 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
534 private MethodDefinition[] GetMethods (TypeDefinition type)
536 ArrayList list = new ArrayList ();
538 MethodDefinitionCollection methods = type.Methods;//type.GetMethods (flags);
539 foreach (MethodDefinition method in methods) {
540 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
541 continue;
543 // we're only interested in public or protected members
544 if (!MustDocumentMethod(method))
545 continue;
547 if (IsFinalizer (method))
548 continue;
550 list.Add (method);
553 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
556 static bool IsFinalizer (MethodDefinition method)
558 if (method.Name != "Finalize")
559 return false;
561 if (!method.IsVirtual)
562 return false;
564 if (method.Parameters.Count != 0)
565 return false;
567 return true;
570 private MethodDefinition [] GetConstructors (TypeDefinition type)
572 ArrayList list = new ArrayList ();
574 ConstructorCollection ctors = type.Constructors;//type.GetConstructors (flags);
575 foreach (MethodDefinition constructor in ctors) {
576 // we're only interested in public or protected members
577 if (!MustDocumentMethod(constructor))
578 continue;
580 list.Add (constructor);
583 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
586 private EventDefinition[] GetEvents (TypeDefinition type)
588 ArrayList list = new ArrayList ();
590 EventDefinitionCollection events = type.Events;//type.GetEvents (flags);
591 foreach (EventDefinition eventDef in events) {
592 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
594 if (addMethod == null || !MustDocumentMethod (addMethod))
595 continue;
597 list.Add (eventDef);
600 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
604 class FieldData : MemberData
606 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
607 : base (document, parent, members)
611 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
612 return ((FieldDefinition) member).CustomAttributes;
615 protected override string GetName (MemberReference memberDefenition)
617 FieldDefinition field = (FieldDefinition) memberDefenition;
618 return field.Name;
621 protected override string GetMemberAttributes (MemberReference memberDefenition)
623 FieldDefinition field = (FieldDefinition) memberDefenition;
624 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
627 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
629 base.AddExtraData (p, memberDefenition);
630 FieldDefinition field = (FieldDefinition) memberDefenition;
631 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
633 if (field.IsLiteral) {
634 object value = field.Constant;//object value = field.GetValue (null);
635 string stringValue = null;
636 //if (value is Enum) {
637 // // FIXME: when Mono bug #60090 has been
638 // // fixed, we should just be able to use
639 // // Convert.ToString
640 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
642 //else {
643 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
646 if (stringValue != null)
647 AddAttribute (p, "value", stringValue);
651 public override string ParentTag {
652 get { return "fields"; }
655 public override string Tag {
656 get { return "field"; }
660 class PropertyData : MemberData
662 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
663 : base (document, parent, members)
667 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
668 return ((PropertyDefinition) member).CustomAttributes;
671 protected override string GetName (MemberReference memberDefenition)
673 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
674 return prop.Name;
677 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
679 base.AddExtraData (p, memberDefenition);
680 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
681 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
682 MethodDefinition _get = prop.GetMethod;
683 MethodDefinition _set = prop.SetMethod;
684 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
685 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
686 MethodDefinition [] methods;
688 if (haveGet && haveSet) {
689 methods = new MethodDefinition [] { _get, _set };
690 } else if (haveGet) {
691 methods = new MethodDefinition [] { _get };
692 } else if (haveSet) {
693 methods = new MethodDefinition [] { _set };
694 } else {
695 //odd
696 return;
699 string parms = Parameters.GetSignature (methods [0].Parameters);
700 if (!string.IsNullOrEmpty (parms))
701 AddAttribute (p, "params", parms);
703 MethodData data = new MethodData (document, p, methods);
704 //data.NoMemberAttributes = true;
705 data.DoOutput ();
708 protected override string GetMemberAttributes (MemberReference memberDefenition)
710 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
711 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
714 public override string ParentTag {
715 get { return "properties"; }
718 public override string Tag {
719 get { return "property"; }
723 class EventData : MemberData
725 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
726 : base (document, parent, members)
730 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
731 return ((EventDefinition) member).CustomAttributes;
734 protected override string GetName (MemberReference memberDefenition)
736 EventDefinition evt = (EventDefinition) memberDefenition;
737 return evt.Name;
740 protected override string GetMemberAttributes (MemberReference memberDefenition)
742 EventDefinition evt = (EventDefinition) memberDefenition;
743 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
746 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
748 base.AddExtraData (p, memberDefenition);
749 EventDefinition evt = (EventDefinition) memberDefenition;
750 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
753 public override string ParentTag {
754 get { return "events"; }
757 public override string Tag {
758 get { return "event"; }
762 class MethodData : MemberData
764 bool noAtts;
766 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
767 : base (document, parent, members)
771 protected override CustomAttributeCollection GetCustomAttributes (MemberReference member) {
772 return ((MethodDefinition) member).CustomAttributes;
775 protected override string GetName (MemberReference memberDefenition)
777 MethodDefinition method = (MethodDefinition) memberDefenition;
778 string name = method.Name;
779 string parms = Parameters.GetSignature (method.Parameters);
781 return string.Format ("{0}({1})", name, parms);
784 protected override string GetMemberAttributes (MemberReference memberDefenition)
786 MethodDefinition method = (MethodDefinition) memberDefenition;
787 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
790 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
792 base.AddExtraData (p, memberDefenition);
794 if (!(memberDefenition is MethodDefinition))
795 return;
797 MethodDefinition mbase = (MethodDefinition) memberDefenition;
799 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
800 parms.DoOutput ();
802 if (mbase.IsAbstract)
803 AddAttribute (p, "abstract", "true");
804 if (mbase.IsVirtual)
805 AddAttribute (p, "virtual", "true");
806 if (mbase.IsStatic)
807 AddAttribute (p, "static", "true");
809 string rettype = Utils.CleanupTypeName (mbase.ReturnType.ReturnType);
810 if (rettype != "System.Void" || !mbase.IsConstructor)
811 AddAttribute (p, "returntype", (rettype));
813 AttributeData.OutputAttributes (document, p, mbase.ReturnType.CustomAttributes);
815 MemberData.OutputGenericParameters (document, p, mbase);
818 public override bool NoMemberAttributes {
819 get { return noAtts; }
820 set { noAtts = value; }
823 public override string ParentTag {
824 get { return "methods"; }
827 public override string Tag {
828 get { return "method"; }
832 class ConstructorData : MethodData
834 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
835 : base (document, parent, members)
839 public override string ParentTag {
840 get { return "constructors"; }
843 public override string Tag {
844 get { return "constructor"; }
848 class ParameterData : BaseData
850 private ParameterDefinitionCollection parameters;
852 public ParameterData (XmlDocument document, XmlNode parent, ParameterDefinitionCollection parameters)
853 : base (document, parent)
855 this.parameters = parameters;
858 public override void DoOutput ()
860 XmlNode parametersNode = document.CreateElement ("parameters");
861 parent.AppendChild (parametersNode);
863 foreach (ParameterDefinition parameter in parameters) {
864 XmlNode paramNode = document.CreateElement ("parameter");
865 parametersNode.AppendChild (paramNode);
866 AddAttribute (paramNode, "name", parameter.Name);
867 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
868 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
870 string direction = "in";
872 if (parameter.ParameterType is ReferenceType)
873 direction = parameter.IsOut ? "out" : "ref";
875 TypeReference t = parameter.ParameterType;
876 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
878 if (parameter.IsOptional) {
879 AddAttribute (paramNode, "optional", "true");
880 if (parameter.HasConstant)
881 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
884 if (direction != "in")
885 AddAttribute (paramNode, "direction", direction);
887 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
892 class AttributeData : BaseData
894 CustomAttributeCollection atts;
896 AttributeData (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
897 : base (doc, parent)
899 atts = attributes;
902 public override void DoOutput ()
904 if (document == null)
905 throw new InvalidOperationException ("Document not set");
907 if (atts == null || atts.Count == 0)
908 return;
910 XmlNode natts = parent.SelectSingleNode("attributes");
911 if (natts == null) {
912 natts = document.CreateElement ("attributes", null);
913 parent.AppendChild (natts);
916 for (int i = 0; i < atts.Count; ++i) {
917 CustomAttribute att = atts [i];
918 try {
919 att.Resolve ();
920 } catch {}
922 if (!att.Resolved)
923 continue;
925 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
926 if (SkipAttribute (att))
927 continue;
929 XmlNode node = document.CreateElement ("attribute");
930 AddAttribute (node, "name", attName);
932 XmlNode properties = null;
934 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
936 foreach (string name in attribute_mapping.Keys) {
937 if (name == "TypeId")
938 continue;
940 if (properties == null) {
941 properties = node.AppendChild (document.CreateElement ("properties"));
944 object o = attribute_mapping [name];
946 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
947 AddAttribute (n, "name", name);
949 if (o == null) {
950 AddAttribute (n, "value", "null");
951 continue;
953 string value = o.ToString ();
954 if (attName.EndsWith ("GuidAttribute"))
955 value = value.ToUpper ();
956 AddAttribute (n, "value", value);
959 natts.AppendChild (node);
963 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
965 var mapping = new Dictionary<string, object> ();
967 PopulateMapping (mapping, attribute);
969 var constructor = attribute.Constructor.Resolve ();
970 if (constructor == null || constructor.Parameters.Count == 0)
971 return mapping;
973 PopulateMapping (mapping, constructor, attribute);
975 return mapping;
978 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
980 foreach (DictionaryEntry entry in attribute.Properties) {
981 var name = (string) entry.Key;
983 mapping.Add (name, GetArgumentValue (attribute.GetPropertyType (name), entry.Value));
987 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
989 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
991 int? argument = null;
993 foreach (Instruction instruction in constructor.Body.Instructions) {
994 switch (instruction.OpCode.Code) {
995 case Code.Ldarg_1:
996 argument = 1;
997 break;
998 case Code.Ldarg_2:
999 argument = 2;
1000 break;
1001 case Code.Ldarg_3:
1002 argument = 3;
1003 break;
1004 case Code.Ldarg:
1005 case Code.Ldarg_S:
1006 argument = ((ParameterDefinition) instruction.Operand).Sequence;
1007 break;
1009 case Code.Stfld:
1010 FieldReference field = (FieldReference) instruction.Operand;
1011 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1012 continue;
1014 if (!argument.HasValue)
1015 break;
1017 if (!field_mapping.ContainsKey (field))
1018 field_mapping.Add (field, (int) argument - 1);
1020 argument = null;
1021 break;
1025 return field_mapping;
1028 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1030 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1032 foreach (PropertyDefinition property in type.Properties) {
1033 if (property.GetMethod == null)
1034 continue;
1035 if (!property.GetMethod.HasBody)
1036 continue;
1038 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1039 if (instruction.OpCode.Code != Code.Ldfld)
1040 continue;
1042 FieldReference field = (FieldReference) instruction.Operand;
1043 if (field.DeclaringType.FullName != type.FullName)
1044 continue;
1046 property_mapping.Add (property, field);
1047 break;
1051 return property_mapping;
1054 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1056 if (!constructor.HasBody)
1057 return;
1059 var field_mapping = CreateArgumentFieldMapping (constructor);
1060 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1062 foreach (var pair in property_mapping) {
1063 int argument;
1064 if (!field_mapping.TryGetValue (pair.Value, out argument))
1065 continue;
1067 mapping.Add (pair.Key.Name, GetArgumentValue (constructor.Parameters [argument].ParameterType, attribute.ConstructorParameters [argument]));
1071 static object GetArgumentValue (TypeReference reference, object value)
1073 var type = reference.Resolve ();
1074 if (type == null)
1075 return value;
1077 if (type.IsEnum) {
1078 if (IsFlaggedEnum (type))
1079 return GetFlaggedEnumValue (type, value);
1081 return GetEnumValue (type, value);
1084 return value;
1087 static bool IsFlaggedEnum (TypeDefinition type)
1089 if (!type.IsEnum)
1090 return false;
1092 if (type.CustomAttributes.Count == 0)
1093 return false;
1095 foreach (CustomAttribute attribute in type.CustomAttributes)
1096 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1097 return true;
1099 return false;
1102 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1104 long flags = Convert.ToInt64 (value);
1105 var signature = new StringBuilder ();
1107 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1108 FieldDefinition field = type.Fields [i];
1110 if (!field.HasConstant)
1111 continue;
1113 long flag = Convert.ToInt64 (field.Constant);
1115 if (flag == 0)
1116 continue;
1118 if ((flags & flag) == flag) {
1119 if (signature.Length != 0)
1120 signature.Append (", ");
1122 signature.Append (field.Name);
1123 flags -= flag;
1127 return signature.ToString ();
1130 static object GetEnumValue (TypeDefinition type, object value)
1132 foreach (FieldDefinition field in type.Fields) {
1133 if (!field.HasConstant)
1134 continue;
1136 if (Comparer.Default.Compare (field.Constant, value) == 0)
1137 return field.Name;
1140 return value;
1143 static bool SkipAttribute (CustomAttribute attribute)
1145 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1147 return !TypeHelper.IsPublic (attribute)
1148 || type_name.EndsWith ("TODOAttribute");
1151 public static void OutputAttributes (XmlDocument doc, XmlNode parent, CustomAttributeCollection attributes)
1153 AttributeData ad = new AttributeData (doc, parent, attributes);
1154 ad.DoOutput ();
1158 static class Parameters {
1160 public static string GetSignature (ParameterDefinitionCollection infos)
1162 if (infos == null || infos.Count == 0)
1163 return "";
1165 var signature = new StringBuilder ();
1166 for (int i = 0; i < infos.Count; i++) {
1168 if (i > 0)
1169 signature.Append (", ");
1171 ParameterDefinition info = infos [i];
1173 string modifier;
1174 if ((info.Attributes & ParameterAttributes.In) != 0)
1175 modifier = "in";
1176 else if ((info.Attributes & ParameterAttributes.Retval) != 0)
1177 modifier = "ref";
1178 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1179 modifier = "out";
1180 else
1181 modifier = string.Empty;
1183 if (modifier.Length > 0)
1184 signature.AppendFormat ("{0} ", modifier);
1186 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1189 return signature.ToString ();
1194 class TypeReferenceComparer : IComparer
1196 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1198 public int Compare (object a, object b)
1200 TypeReference ta = (TypeReference) a;
1201 TypeReference tb = (TypeReference) b;
1202 int result = String.Compare (ta.Namespace, tb.Namespace);
1203 if (result != 0)
1204 return result;
1206 return String.Compare (ta.Name, tb.Name);
1210 class MemberReferenceComparer : IComparer
1212 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1214 public int Compare (object a, object b)
1216 MemberReference ma = (MemberReference) a;
1217 MemberReference mb = (MemberReference) b;
1218 return String.Compare (ma.Name, mb.Name);
1222 class MethodDefinitionComparer : IComparer
1224 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1226 public int Compare (object a, object b)
1228 MethodDefinition ma = (MethodDefinition) a;
1229 MethodDefinition mb = (MethodDefinition) b;
1230 int res = String.Compare (ma.Name, mb.Name);
1231 if (res != 0)
1232 return res;
1234 ParameterDefinitionCollection pia = ma.Parameters ;
1235 ParameterDefinitionCollection pib = mb.Parameters;
1236 res = pia.Count - pib.Count;
1237 if (res != 0)
1238 return res;
1240 string siga = Parameters.GetSignature (pia);
1241 string sigb = Parameters.GetSignature (pib);
1242 return String.Compare (siga, sigb);