[mono-api-info] Sort constructors using full signature.
[mono-project.git] / mcs / tools / corcompare / mono-api-info.cs
blobb32394dd5f79d0b8aec634b48cb236b5981f15d3
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.Linq;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
18 using System.Text;
19 using System.Xml;
21 using Mono.Cecil;
22 using Mono.Cecil.Cil;
23 using System.IO;
25 namespace CorCompare
27 public class Driver
29 public static int Main (string [] args)
31 if (args.Length == 0)
32 return 1;
34 AbiMode = false;
36 AssemblyCollection acoll = new AssemblyCollection ();
38 string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
39 string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
40 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
42 foreach (string arg in args) {
43 if (arg == "--abi") {
44 AbiMode = true;
45 } else {
46 acoll.Add (arg);
48 if (arg.Contains ("v3.0")) {
49 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
50 } else if (arg.Contains ("v3.5")) {
51 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
52 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
53 } else if (arg.Contains ("v4.0")) {
54 if (arg.Contains ("Silverlight")) {
55 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
56 } else {
57 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
58 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
60 } else {
61 TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
66 XmlDocument doc = new XmlDocument ();
67 acoll.Document = doc;
68 acoll.DoOutput ();
70 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
71 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
72 doc.InsertBefore (decl, doc.DocumentElement);
73 doc.WriteTo (writer);
74 return 0;
77 internal static bool AbiMode { get; private set; }
80 public class Utils {
82 public static string CleanupTypeName (TypeReference type)
84 return CleanupTypeName (type.FullName);
87 public static string CleanupTypeName (string t)
89 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
93 class AssemblyCollection
95 XmlDocument document;
96 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
98 public AssemblyCollection ()
102 public bool Add (string name)
104 AssemblyDefinition ass = LoadAssembly (name);
105 if (ass == null) {
106 Console.Error.WriteLine ("Cannot load assembly file " + name);
107 return false;
110 assemblies.Add (ass);
111 return true;
114 public void DoOutput ()
116 if (document == null)
117 throw new InvalidOperationException ("Document not set");
119 XmlNode nassemblies = document.CreateElement ("assemblies", null);
120 document.AppendChild (nassemblies);
121 foreach (AssemblyDefinition a in assemblies) {
122 AssemblyData data = new AssemblyData (document, nassemblies, a);
123 data.DoOutput ();
127 public XmlDocument Document {
128 set { document = value; }
131 AssemblyDefinition LoadAssembly (string assembly)
133 try {
134 if (File.Exists (assembly))
135 return TypeHelper.Resolver.ResolveFile (assembly);
137 return TypeHelper.Resolver.Resolve (assembly);
138 } catch (Exception e) {
139 Console.WriteLine (e);
140 return null;
145 abstract class BaseData
147 protected XmlDocument document;
148 protected XmlNode parent;
150 protected BaseData (XmlDocument doc, XmlNode parent)
152 this.document = doc;
153 this.parent = parent;
156 public abstract void DoOutput ();
158 protected void AddAttribute (XmlNode node, string name, string value)
160 XmlAttribute attr = document.CreateAttribute (name);
161 attr.Value = value;
162 node.Attributes.Append (attr);
166 class TypeForwardedToData : BaseData
168 AssemblyDefinition ass;
170 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
171 : base (document, parent)
173 this.ass = ass;
176 public override void DoOutput ()
178 XmlNode natts = parent.SelectSingleNode("attributes");
179 if (natts == null) {
180 natts = document.CreateElement ("attributes", null);
181 parent.AppendChild (natts);
184 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
186 if (((uint)type.Attributes & 0x200000u) == 0)
187 continue;
189 XmlNode node = document.CreateElement ("attribute");
190 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
191 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
192 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
193 AddAttribute (property, "name", "Destination");
194 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
195 natts.AppendChild (node);
199 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
201 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
202 tftd.DoOutput ();
206 class AssemblyData : BaseData
208 AssemblyDefinition ass;
210 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
211 : base (document, parent)
213 this.ass = ass;
216 public override void DoOutput ()
218 if (document == null)
219 throw new InvalidOperationException ("Document not set");
221 XmlNode nassembly = document.CreateElement ("assembly", null);
222 AssemblyNameDefinition aname = ass.Name;
223 AddAttribute (nassembly, "name", aname.Name);
224 AddAttribute (nassembly, "version", aname.Version.ToString ());
225 parent.AppendChild (nassembly);
226 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
227 AttributeData.OutputAttributes (document, nassembly, ass);
228 var typesCollection = ass.MainModule.Types;
229 if (typesCollection == null || typesCollection.Count == 0)
230 return;
231 var typesArray = new TypeDefinition [typesCollection.Count];
232 for (int i = 0; i < typesCollection.Count; i++) {
233 typesArray [i] = typesCollection [i];
235 Array.Sort (typesArray, TypeReferenceComparer.Default);
237 XmlNode nss = document.CreateElement ("namespaces", null);
238 nassembly.AppendChild (nss);
240 string current_namespace = "$%&$&";
241 XmlNode ns = null;
242 XmlNode classes = null;
243 foreach (TypeDefinition t in typesArray) {
244 if (string.IsNullOrEmpty (t.Namespace))
245 continue;
247 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
248 continue;
250 if (t.DeclaringType != null)
251 continue; // enforce !nested
253 if (t.Namespace != current_namespace) {
254 current_namespace = t.Namespace;
255 ns = document.CreateElement ("namespace", null);
256 AddAttribute (ns, "name", current_namespace);
257 nss.AppendChild (ns);
258 classes = document.CreateElement ("classes", null);
259 ns.AppendChild (classes);
262 TypeData bd = new TypeData (document, classes, t);
263 bd.DoOutput ();
268 abstract class MemberData : BaseData
270 MemberReference [] members;
272 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
273 : base (document, parent)
275 this.members = members;
278 public override void DoOutput ()
280 XmlNode mclass = document.CreateElement (ParentTag, null);
281 parent.AppendChild (mclass);
283 foreach (MemberReference member in members) {
284 XmlNode mnode = document.CreateElement (Tag, null);
285 mclass.AppendChild (mnode);
286 AddAttribute (mnode, "name", GetName (member));
287 if (!NoMemberAttributes)
288 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
290 AttributeData.OutputAttributes (document, mnode, (ICustomAttributeProvider) member);
292 AddExtraData (mnode, member);
296 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
300 protected virtual string GetName (MemberReference memberDefenition)
302 return "NoNAME";
305 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
307 return null;
310 public virtual bool NoMemberAttributes {
311 get { return false; }
312 set {}
315 public virtual string ParentTag {
316 get { return "NoPARENTTAG"; }
319 public virtual string Tag {
320 get { return "NoTAG"; }
323 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
325 if (provider.GenericParameters.Count == 0)
326 return;
328 var gparameters = provider.GenericParameters;
330 XmlElement ngeneric = document.CreateElement ("generic-parameters");
331 nclass.AppendChild (ngeneric);
333 foreach (GenericParameter gp in gparameters) {
334 XmlElement nparam = document.CreateElement ("generic-parameter");
335 nparam.SetAttribute ("name", gp.Name);
336 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
338 AttributeData.OutputAttributes (document, nparam, gp);
340 ngeneric.AppendChild (nparam);
342 var constraints = gp.Constraints;
343 if (constraints.Count == 0)
344 continue;
346 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
348 foreach (TypeReference constraint in constraints) {
349 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
350 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
351 nconstraint.AppendChild (ncons);
354 nparam.AppendChild (nconstraint);
359 class TypeData : MemberData
361 TypeDefinition type;
363 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
364 : base (document, parent, null)
366 this.type = type;
368 public override void DoOutput ()
370 if (document == null)
371 throw new InvalidOperationException ("Document not set");
373 XmlNode nclass = document.CreateElement ("class", null);
374 AddAttribute (nclass, "name", type.Name);
375 string classType = GetClassType (type);
376 AddAttribute (nclass, "type", classType);
378 if (type.BaseType != null)
379 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
381 if (type.IsSealed)
382 AddAttribute (nclass, "sealed", "true");
384 if (type.IsAbstract)
385 AddAttribute (nclass, "abstract", "true");
387 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
388 AddAttribute (nclass, "serializable", "true");
390 string charSet = GetCharSet (type);
391 AddAttribute (nclass, "charset", charSet);
393 string layout = GetLayout (type);
394 if (layout != null)
395 AddAttribute (nclass, "layout", layout);
397 if (type.PackingSize >= 0) {
398 AddAttribute (nclass, "pack", type.PackingSize.ToString ());
401 if (type.ClassSize >= 0) {
402 AddAttribute (nclass, "size", type.ClassSize.ToString ());
405 parent.AppendChild (nclass);
407 AttributeData.OutputAttributes (document, nclass, type);
409 XmlNode ifaces = null;
411 foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) {
412 if (!TypeHelper.IsPublic (iface))
413 // we're only interested in public interfaces
414 continue;
416 if (ifaces == null) {
417 ifaces = document.CreateElement ("interfaces", null);
418 nclass.AppendChild (ifaces);
421 XmlNode iface_node = document.CreateElement ("interface", null);
422 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
423 ifaces.AppendChild (iface_node);
426 MemberData.OutputGenericParameters (document, nclass, type);
428 ArrayList members = new ArrayList ();
430 FieldDefinition [] fields = GetFields (type);
431 if (fields.Length > 0) {
432 Array.Sort (fields, MemberReferenceComparer.Default);
433 FieldData fd = new FieldData (document, nclass, fields);
434 members.Add (fd);
437 if (type.IsEnum) {
438 var value_type = GetEnumValueField (type);
439 if (value_type == null)
440 throw new NotSupportedException ();
442 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
445 if (!Driver.AbiMode) {
447 MethodDefinition [] ctors = GetConstructors (type);
448 if (ctors.Length > 0) {
449 Array.Sort (ctors, MethodDefinitionComparer.Default);
450 members.Add (new ConstructorData (document, nclass, ctors));
453 PropertyDefinition[] properties = GetProperties (type);
454 if (properties.Length > 0) {
455 Array.Sort (properties, MemberReferenceComparer.Default);
456 members.Add (new PropertyData (document, nclass, properties));
459 EventDefinition [] events = GetEvents (type);
460 if (events.Length > 0) {
461 Array.Sort (events, MemberReferenceComparer.Default);
462 members.Add (new EventData (document, nclass, events));
465 MethodDefinition [] methods = GetMethods (type);
466 if (methods.Length > 0) {
467 Array.Sort (methods, MethodDefinitionComparer.Default);
468 members.Add (new MethodData (document, nclass, methods));
472 foreach (MemberData md in members)
473 md.DoOutput ();
475 var nested = type.NestedTypes;
476 //remove non public(familiy) and nested in second degree
477 for (int i = nested.Count - 1; i >= 0; i--) {
478 TypeDefinition t = nested [i];
479 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
480 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
481 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
482 // public
483 if (t.DeclaringType == type)
484 continue; // not nested of nested
487 nested.RemoveAt (i);
490 if (nested.Count > 0) {
491 var nestedArray = nested.ToArray ();
492 Array.Sort (nestedArray, TypeReferenceComparer.Default);
494 XmlNode classes = document.CreateElement ("classes", null);
495 nclass.AppendChild (classes);
496 foreach (TypeDefinition t in nestedArray) {
497 TypeData td = new TypeData (document, classes, t);
498 td.DoOutput ();
503 static FieldReference GetEnumValueField (TypeDefinition type)
505 foreach (FieldDefinition field in type.Fields)
506 if (field.IsSpecialName && field.Name == "value__")
507 return field;
509 return null;
512 protected override string GetMemberAttributes (MemberReference member)
514 if (member != type)
515 throw new InvalidOperationException ("odd");
517 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
520 public static bool MustDocumentMethod (MethodDefinition method) {
521 // All other methods
522 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
523 return maskedAccess == MethodAttributes.Public
524 || maskedAccess == MethodAttributes.Family
525 || maskedAccess == MethodAttributes.FamORAssem;
528 static string GetClassType (TypeDefinition t)
530 if (t.IsEnum)
531 return "enum";
533 if (t.IsValueType)
534 return "struct";
536 if (t.IsInterface)
537 return "interface";
539 if (TypeHelper.IsDelegate(t))
540 return "delegate";
542 if (t.IsPointer)
543 return "pointer";
545 return "class";
548 static string GetCharSet (TypeDefinition type)
550 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
551 if (maskedStringFormat == TypeAttributes.AnsiClass)
552 return CharSet.Ansi.ToString ();
554 if (maskedStringFormat == TypeAttributes.AutoClass)
555 return CharSet.Auto.ToString ();
557 if (maskedStringFormat == TypeAttributes.UnicodeClass)
558 return CharSet.Unicode.ToString ();
560 return CharSet.None.ToString ();
563 static string GetLayout (TypeDefinition type)
565 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
566 if (maskedLayout == TypeAttributes.AutoLayout)
567 return LayoutKind.Auto.ToString ();
569 if (maskedLayout == TypeAttributes.ExplicitLayout)
570 return LayoutKind.Explicit.ToString ();
572 if (maskedLayout == TypeAttributes.SequentialLayout)
573 return LayoutKind.Sequential.ToString ();
575 return null;
578 FieldDefinition [] GetFields (TypeDefinition type) {
579 ArrayList list = new ArrayList ();
581 var fields = type.Fields;
582 foreach (FieldDefinition field in fields) {
583 if (field.IsSpecialName)
584 continue;
586 if (Driver.AbiMode && field.IsStatic)
587 continue;
589 // we're only interested in public or protected members
590 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
591 if (Driver.AbiMode && !field.IsNotSerialized) {
592 list.Add (field);
593 } else {
594 if (maskedVisibility == FieldAttributes.Public
595 || maskedVisibility == FieldAttributes.Family
596 || maskedVisibility == FieldAttributes.FamORAssem) {
597 list.Add (field);
602 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
606 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
607 ArrayList list = new ArrayList ();
609 var properties = type.Properties;//type.GetProperties (flags);
610 foreach (PropertyDefinition property in properties) {
611 MethodDefinition getMethod = property.GetMethod;
612 MethodDefinition setMethod = property.SetMethod;
614 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
615 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
617 // if neither the getter or setter should be documented, then
618 // skip the property
619 if (hasGetter || hasSetter) {
620 list.Add (property);
624 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
627 private MethodDefinition[] GetMethods (TypeDefinition type)
629 ArrayList list = new ArrayList ();
631 var methods = type.Methods;//type.GetMethods (flags);
632 foreach (MethodDefinition method in methods) {
633 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
634 continue;
636 // we're only interested in public or protected members
637 if (!MustDocumentMethod(method))
638 continue;
640 if (IsFinalizer (method)) {
641 string name = method.DeclaringType.Name;
642 int arity = name.IndexOf ('`');
643 if (arity > 0)
644 name = name.Substring (0, arity);
646 method.Name = "~" + name;
649 list.Add (method);
652 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
655 static bool IsFinalizer (MethodDefinition method)
657 if (method.Name != "Finalize")
658 return false;
660 if (!method.IsVirtual)
661 return false;
663 if (method.Parameters.Count != 0)
664 return false;
666 return true;
669 private MethodDefinition [] GetConstructors (TypeDefinition type)
671 ArrayList list = new ArrayList ();
673 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
674 foreach (MethodDefinition constructor in ctors) {
675 // we're only interested in public or protected members
676 if (!MustDocumentMethod(constructor))
677 continue;
679 list.Add (constructor);
682 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
685 private EventDefinition[] GetEvents (TypeDefinition type)
687 ArrayList list = new ArrayList ();
689 var events = type.Events;//type.GetEvents (flags);
690 foreach (EventDefinition eventDef in events) {
691 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
693 if (addMethod == null || !MustDocumentMethod (addMethod))
694 continue;
696 list.Add (eventDef);
699 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
703 class FieldData : MemberData
705 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
706 : base (document, parent, members)
710 protected override string GetName (MemberReference memberDefenition)
712 FieldDefinition field = (FieldDefinition) memberDefenition;
713 return field.Name;
716 protected override string GetMemberAttributes (MemberReference memberDefenition)
718 FieldDefinition field = (FieldDefinition) memberDefenition;
719 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
722 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
724 base.AddExtraData (p, memberDefenition);
725 FieldDefinition field = (FieldDefinition) memberDefenition;
726 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
728 if (field.IsLiteral) {
729 object value = field.Constant;//object value = field.GetValue (null);
730 string stringValue = null;
731 //if (value is Enum) {
732 // // FIXME: when Mono bug #60090 has been
733 // // fixed, we should just be able to use
734 // // Convert.ToString
735 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
737 //else {
738 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
741 if (stringValue != null)
742 AddAttribute (p, "value", stringValue);
746 public override string ParentTag {
747 get { return "fields"; }
750 public override string Tag {
751 get { return "field"; }
755 class PropertyData : MemberData
757 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
758 : base (document, parent, members)
762 protected override string GetName (MemberReference memberDefenition)
764 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
765 return prop.Name;
768 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
770 base.AddExtraData (p, memberDefenition);
771 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
772 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
773 MethodDefinition _get = prop.GetMethod;
774 MethodDefinition _set = prop.SetMethod;
775 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
776 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
777 MethodDefinition [] methods;
779 if (haveGet && haveSet) {
780 methods = new MethodDefinition [] { _get, _set };
781 } else if (haveGet) {
782 methods = new MethodDefinition [] { _get };
783 } else if (haveSet) {
784 methods = new MethodDefinition [] { _set };
785 } else {
786 //odd
787 return;
790 if (haveGet || _set.Parameters.Count > 1) {
791 string parms = Parameters.GetSignature (methods [0].Parameters);
792 if (!string.IsNullOrEmpty (parms))
793 AddAttribute (p, "params", parms);
796 MethodData data = new MethodData (document, p, methods);
797 //data.NoMemberAttributes = true;
798 data.DoOutput ();
801 protected override string GetMemberAttributes (MemberReference memberDefenition)
803 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
804 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
807 public override string ParentTag {
808 get { return "properties"; }
811 public override string Tag {
812 get { return "property"; }
816 class EventData : MemberData
818 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
819 : base (document, parent, members)
823 protected override string GetName (MemberReference memberDefenition)
825 EventDefinition evt = (EventDefinition) memberDefenition;
826 return evt.Name;
829 protected override string GetMemberAttributes (MemberReference memberDefenition)
831 EventDefinition evt = (EventDefinition) memberDefenition;
832 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
835 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
837 base.AddExtraData (p, memberDefenition);
838 EventDefinition evt = (EventDefinition) memberDefenition;
839 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
842 public override string ParentTag {
843 get { return "events"; }
846 public override string Tag {
847 get { return "event"; }
851 class MethodData : MemberData
853 bool noAtts;
855 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
856 : base (document, parent, members)
860 protected override string GetName (MemberReference memberDefenition)
862 MethodDefinition method = (MethodDefinition) memberDefenition;
863 string name = method.Name;
864 string parms = Parameters.GetSignature (method.Parameters);
866 return string.Format ("{0}({1})", name, parms);
869 protected override string GetMemberAttributes (MemberReference memberDefenition)
871 MethodDefinition method = (MethodDefinition) memberDefenition;
872 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
875 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
877 base.AddExtraData (p, memberDefenition);
879 if (!(memberDefenition is MethodDefinition))
880 return;
882 MethodDefinition mbase = (MethodDefinition) memberDefenition;
884 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
885 parms.DoOutput ();
887 if (mbase.IsAbstract)
888 AddAttribute (p, "abstract", "true");
889 if (mbase.IsVirtual)
890 AddAttribute (p, "virtual", "true");
891 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
892 AddAttribute (p, "sealed", "true");
893 if (mbase.IsStatic)
894 AddAttribute (p, "static", "true");
896 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
897 if (rettype != "System.Void" || !mbase.IsConstructor)
898 AddAttribute (p, "returntype", (rettype));
900 AttributeData.OutputAttributes (document, p, mbase.MethodReturnType);
902 MemberData.OutputGenericParameters (document, p, mbase);
905 public override bool NoMemberAttributes {
906 get { return noAtts; }
907 set { noAtts = value; }
910 public override string ParentTag {
911 get { return "methods"; }
914 public override string Tag {
915 get { return "method"; }
919 class ConstructorData : MethodData
921 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
922 : base (document, parent, members)
926 public override string ParentTag {
927 get { return "constructors"; }
930 public override string Tag {
931 get { return "constructor"; }
935 class ParameterData : BaseData
937 private IList<ParameterDefinition> parameters;
939 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
940 : base (document, parent)
942 this.parameters = parameters;
945 public override void DoOutput ()
947 XmlNode parametersNode = document.CreateElement ("parameters");
948 parent.AppendChild (parametersNode);
950 foreach (ParameterDefinition parameter in parameters) {
951 XmlNode paramNode = document.CreateElement ("parameter");
952 parametersNode.AppendChild (paramNode);
953 AddAttribute (paramNode, "name", parameter.Name);
954 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
955 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
957 string direction = "in";
959 if (parameter.ParameterType is ByReferenceType)
960 direction = parameter.IsOut ? "out" : "ref";
962 TypeReference t = parameter.ParameterType;
963 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
965 if (parameter.IsOptional) {
966 AddAttribute (paramNode, "optional", "true");
967 if (parameter.HasConstant)
968 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
971 if (direction != "in")
972 AddAttribute (paramNode, "direction", direction);
974 AttributeData.OutputAttributes (document, paramNode, parameter);
979 class AttributeData : BaseData
981 IList<CustomAttribute> atts;
983 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
984 : base (doc, parent)
986 atts = attributes;
989 public override void DoOutput ()
991 if (document == null)
992 throw new InvalidOperationException ("Document not set");
994 if (atts == null || atts.Count == 0)
995 return;
997 XmlNode natts = parent.SelectSingleNode("attributes");
998 if (natts == null) {
999 natts = document.CreateElement ("attributes", null);
1000 parent.AppendChild (natts);
1003 for (int i = 0; i < atts.Count; ++i) {
1004 CustomAttribute att = atts [i];
1006 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1007 if (SkipAttribute (att))
1008 continue;
1010 XmlNode node = document.CreateElement ("attribute");
1011 AddAttribute (node, "name", attName);
1013 XmlNode properties = null;
1015 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
1017 foreach (string name in attribute_mapping.Keys) {
1018 if (name == "TypeId")
1019 continue;
1021 if (properties == null) {
1022 properties = node.AppendChild (document.CreateElement ("properties"));
1025 object o = attribute_mapping [name];
1027 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1028 AddAttribute (n, "name", name);
1030 if (o == null) {
1031 AddAttribute (n, "value", "null");
1032 continue;
1035 string value = o.ToString ();
1036 if (attName.EndsWith ("GuidAttribute"))
1037 value = value.ToUpper ();
1038 AddAttribute (n, "value", value);
1041 natts.AppendChild (node);
1045 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1047 var mapping = new Dictionary<string, object> ();
1049 PopulateMapping (mapping, attribute);
1051 var constructor = attribute.Constructor.Resolve ();
1052 if (constructor == null || !constructor.HasParameters)
1053 return mapping;
1055 PopulateMapping (mapping, constructor, attribute);
1057 return mapping;
1060 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1062 if (!attribute.HasProperties)
1063 return;
1065 foreach (var named_argument in attribute.Properties) {
1066 var name = named_argument.Name;
1067 var arg = named_argument.Argument;
1069 if (arg.Value is CustomAttributeArgument)
1070 arg = (CustomAttributeArgument) arg.Value;
1072 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1076 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1078 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1080 int? argument = null;
1082 foreach (Instruction instruction in constructor.Body.Instructions) {
1083 switch (instruction.OpCode.Code) {
1084 case Code.Ldarg_1:
1085 argument = 1;
1086 break;
1087 case Code.Ldarg_2:
1088 argument = 2;
1089 break;
1090 case Code.Ldarg_3:
1091 argument = 3;
1092 break;
1093 case Code.Ldarg:
1094 case Code.Ldarg_S:
1095 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1096 break;
1098 case Code.Stfld:
1099 FieldReference field = (FieldReference) instruction.Operand;
1100 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1101 continue;
1103 if (!argument.HasValue)
1104 break;
1106 if (!field_mapping.ContainsKey (field))
1107 field_mapping.Add (field, (int) argument - 1);
1109 argument = null;
1110 break;
1114 return field_mapping;
1117 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1119 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1121 foreach (PropertyDefinition property in type.Properties) {
1122 if (property.GetMethod == null)
1123 continue;
1124 if (!property.GetMethod.HasBody)
1125 continue;
1127 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1128 if (instruction.OpCode.Code != Code.Ldfld)
1129 continue;
1131 FieldReference field = (FieldReference) instruction.Operand;
1132 if (field.DeclaringType.FullName != type.FullName)
1133 continue;
1135 property_mapping.Add (property, field);
1136 break;
1140 return property_mapping;
1143 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1145 if (!constructor.HasBody)
1146 return;
1148 // Custom handling for attributes with arguments which cannot be easily extracted
1149 var ca = attribute.ConstructorArguments;
1150 switch (constructor.DeclaringType.FullName) {
1151 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1152 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1153 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1154 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1156 mapping.Add ("Value", dca.Value);
1157 return;
1158 case "System.ComponentModel.BindableAttribute":
1159 if (ca.Count != 1)
1160 break;
1162 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1163 mapping.Add ("Bindable", ca[0].Value);
1164 } else {
1165 throw new NotImplementedException ();
1168 return;
1171 var field_mapping = CreateArgumentFieldMapping (constructor);
1172 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1174 foreach (var pair in property_mapping) {
1175 int argument;
1176 if (!field_mapping.TryGetValue (pair.Value, out argument))
1177 continue;
1179 var ca_arg = ca [argument];
1180 if (ca_arg.Value is CustomAttributeArgument)
1181 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1183 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1187 static object GetArgumentValue (TypeReference reference, object value)
1189 var type = reference.Resolve ();
1190 if (type == null)
1191 return value;
1193 if (type.IsEnum) {
1194 if (IsFlaggedEnum (type))
1195 return GetFlaggedEnumValue (type, value);
1197 return GetEnumValue (type, value);
1200 return value;
1203 static bool IsFlaggedEnum (TypeDefinition type)
1205 if (!type.IsEnum)
1206 return false;
1208 if (!type.HasCustomAttributes)
1209 return false;
1211 foreach (CustomAttribute attribute in type.CustomAttributes)
1212 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1213 return true;
1215 return false;
1218 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1220 if (value is ulong)
1221 return GetFlaggedEnumValue (type, (ulong)value);
1223 long flags = Convert.ToInt64 (value);
1224 var signature = new StringBuilder ();
1226 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1227 FieldDefinition field = type.Fields [i];
1229 if (!field.HasConstant)
1230 continue;
1232 long flag = Convert.ToInt64 (field.Constant);
1234 if (flag == 0)
1235 continue;
1237 if ((flags & flag) == flag) {
1238 if (signature.Length != 0)
1239 signature.Append (", ");
1241 signature.Append (field.Name);
1242 flags -= flag;
1246 return signature.ToString ();
1249 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1251 var signature = new StringBuilder ();
1253 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1254 FieldDefinition field = type.Fields [i];
1256 if (!field.HasConstant)
1257 continue;
1259 ulong flag = Convert.ToUInt64 (field.Constant);
1261 if (flag == 0)
1262 continue;
1264 if ((flags & flag) == flag) {
1265 if (signature.Length != 0)
1266 signature.Append (", ");
1268 signature.Append (field.Name);
1269 flags -= flag;
1273 return signature.ToString ();
1276 static object GetEnumValue (TypeDefinition type, object value)
1278 foreach (FieldDefinition field in type.Fields) {
1279 if (!field.HasConstant)
1280 continue;
1282 if (Comparer.Default.Compare (field.Constant, value) == 0)
1283 return field.Name;
1286 return value;
1289 static bool SkipAttribute (CustomAttribute attribute)
1291 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1293 return !TypeHelper.IsPublic (attribute)
1294 || type_name.EndsWith ("TODOAttribute");
1297 public static void OutputAttributes (XmlDocument doc, XmlNode parent, ICustomAttributeProvider provider)
1299 if (!provider.HasCustomAttributes)
1300 return;
1302 AttributeData ad = new AttributeData (doc, parent, provider.CustomAttributes);
1303 ad.DoOutput ();
1307 static class Parameters {
1309 public static string GetSignature (IList<ParameterDefinition> infos)
1311 if (infos == null || infos.Count == 0)
1312 return string.Empty;
1314 var signature = new StringBuilder ();
1315 for (int i = 0; i < infos.Count; i++) {
1317 if (i > 0)
1318 signature.Append (", ");
1320 ParameterDefinition info = infos [i];
1322 string modifier;
1323 if ((info.Attributes & ParameterAttributes.In) != 0)
1324 modifier = "in";
1325 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1326 modifier = "out";
1327 else
1328 modifier = string.Empty;
1330 if (modifier.Length > 0) {
1331 signature.Append (modifier);
1332 signature.Append (" ");
1335 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1338 return signature.ToString ();
1343 class TypeReferenceComparer : IComparer
1345 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1347 public int Compare (object a, object b)
1349 TypeReference ta = (TypeReference) a;
1350 TypeReference tb = (TypeReference) b;
1351 int result = String.Compare (ta.Namespace, tb.Namespace);
1352 if (result != 0)
1353 return result;
1355 return String.Compare (ta.Name, tb.Name);
1359 class MemberReferenceComparer : IComparer
1361 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1363 public int Compare (object a, object b)
1365 MemberReference ma = (MemberReference) a;
1366 MemberReference mb = (MemberReference) b;
1367 return String.Compare (ma.Name, mb.Name);
1371 class MethodDefinitionComparer : IComparer
1373 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1375 public int Compare (object a, object b)
1377 MethodDefinition ma = (MethodDefinition) a;
1378 MethodDefinition mb = (MethodDefinition) b;
1379 int res = String.Compare (ma.Name, mb.Name);
1380 if (res != 0)
1381 return res;
1383 if (!ma.HasParameters && !mb.HasParameters)
1384 return 0;
1386 if (!ma.HasParameters)
1387 return -1;
1389 if (!mb.HasParameters)
1390 return 1;
1392 IList<ParameterDefinition> pia = ma.Parameters ;
1393 IList<ParameterDefinition> pib = mb.Parameters;
1394 res = pia.Count - pib.Count;
1395 if (res != 0)
1396 return res;
1398 string siga = Parameters.GetSignature (pia);
1399 string sigb = Parameters.GetSignature (pib);
1400 return String.Compare (siga, sigb);