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;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
29 public static int Main (string [] args)
31 bool showHelp = false;
33 FollowForwarders = false;
36 var acoll = new AssemblyCollection ();
38 var options = new Mono.Options.OptionSet {
39 "usage: mono-api-info [OPTIONS+] ASSEMBLY+",
41 "Expose IL structure of CLR assemblies as XML.",
45 "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
46 v => AbiMode = v != null },
47 { "f|follow-forwarders",
48 "Follow type forwarders.",
49 v => FollowForwarders = v != null },
50 { "d|L|lib|search-directory=",
51 "Check for assembly references in {DIRECTORY}.",
52 v => TypeHelper.Resolver.AddSearchDirectory (v) },
54 "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
55 v => TypeHelper.Resolver.ResolveFile (v) },
57 "The output file. If not specified the output will be written to stdout.",
60 "Show this message and exit.",
61 v => showHelp = v != null },
64 var asms = options.Parse (args);
66 if (showHelp || asms.Count == 0) {
67 options.WriteOptionDescriptions (Console.Out);
69 return showHelp? 0 :1;
72 string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
73 string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
74 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
76 foreach (string arg in asms) {
79 if (arg.Contains ("v3.0")) {
80 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
81 } else if (arg.Contains ("v3.5")) {
82 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
83 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
84 } else if (arg.Contains ("v4.0")) {
85 if (arg.Contains ("Silverlight")) {
86 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
88 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
89 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
92 TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
96 XmlDocument doc = new XmlDocument ();
100 TextWriter outputStream = null;
101 if (!string.IsNullOrEmpty (output))
102 outputStream = new StreamWriter (output);
104 var writer = new WellFormedXmlWriter (new XmlTextWriter (outputStream ?? Console.Out) { Formatting = Formatting.Indented });
105 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
106 doc.InsertBefore (decl, doc.DocumentElement);
107 doc.WriteTo (writer);
109 if (outputStream != null)
110 outputStream.Dispose ();
115 internal static bool AbiMode { get; private set; }
116 internal static bool FollowForwarders { get; private set; }
121 public static string CleanupTypeName (TypeReference type)
123 return CleanupTypeName (type.FullName);
126 public static string CleanupTypeName (string t)
128 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
132 class AssemblyCollection
134 XmlDocument document;
135 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
137 public AssemblyCollection ()
141 public bool Add (string name)
143 AssemblyDefinition ass = LoadAssembly (name);
145 Console.Error.WriteLine ("Cannot load assembly file " + name);
149 assemblies.Add (ass);
153 public void DoOutput ()
155 if (document == null)
156 throw new InvalidOperationException ("Document not set");
158 XmlNode nassemblies = document.CreateElement ("assemblies", null);
159 document.AppendChild (nassemblies);
160 foreach (AssemblyDefinition a in assemblies) {
161 AssemblyData data = new AssemblyData (document, nassemblies, a);
166 public XmlDocument Document {
167 set { document = value; }
170 AssemblyDefinition LoadAssembly (string assembly)
173 if (File.Exists (assembly))
174 return TypeHelper.Resolver.ResolveFile (assembly);
176 return TypeHelper.Resolver.Resolve (assembly);
177 } catch (Exception e) {
178 Console.WriteLine (e);
184 abstract class BaseData
186 protected XmlDocument document;
187 protected XmlNode parent;
189 protected BaseData (XmlDocument doc, XmlNode parent)
192 this.parent = parent;
195 public abstract void DoOutput ();
197 protected void AddAttribute (XmlNode node, string name, string value)
199 XmlAttribute attr = document.CreateAttribute (name);
201 node.Attributes.Append (attr);
205 class TypeForwardedToData : BaseData
207 AssemblyDefinition ass;
209 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
210 : base (document, parent)
215 public override void DoOutput ()
217 XmlNode natts = parent.SelectSingleNode("attributes");
219 natts = document.CreateElement ("attributes", null);
220 parent.AppendChild (natts);
223 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
225 if (((uint)type.Attributes & 0x200000u) == 0)
228 XmlNode node = document.CreateElement ("attribute");
229 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
230 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
231 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
232 AddAttribute (property, "name", "Destination");
233 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
234 natts.AppendChild (node);
238 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
240 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
245 class AssemblyData : BaseData
247 AssemblyDefinition ass;
249 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
250 : base (document, parent)
255 public override void DoOutput ()
257 if (document == null)
258 throw new InvalidOperationException ("Document not set");
260 XmlNode nassembly = document.CreateElement ("assembly", null);
261 AssemblyNameDefinition aname = ass.Name;
262 AddAttribute (nassembly, "name", aname.Name);
263 AddAttribute (nassembly, "version", aname.Version.ToString ());
264 parent.AppendChild (nassembly);
266 if (!Driver.FollowForwarders) {
267 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
270 AttributeData.OutputAttributes (document, nassembly, ass);
272 var types = new List<TypeDefinition> ();
273 if (ass.MainModule.Types != null) {
274 types.AddRange (ass.MainModule.Types);
277 if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
278 foreach (var t in ass.MainModule.ExportedTypes) {
279 var forwarded = t.Resolve ();
280 if (forwarded == null) {
281 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
283 types.Add (forwarded);
287 if (types.Count == 0) {
291 types.Sort (TypeReferenceComparer.Default);
293 XmlNode nss = document.CreateElement ("namespaces", null);
294 nassembly.AppendChild (nss);
296 string current_namespace = "$%&$&";
298 XmlNode classes = null;
299 foreach (TypeDefinition t in types) {
300 if (string.IsNullOrEmpty (t.Namespace))
303 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
306 if (t.DeclaringType != null)
307 continue; // enforce !nested
309 if (t.Namespace != current_namespace) {
310 current_namespace = t.Namespace;
311 ns = document.CreateElement ("namespace", null);
312 AddAttribute (ns, "name", current_namespace);
313 nss.AppendChild (ns);
314 classes = document.CreateElement ("classes", null);
315 ns.AppendChild (classes);
318 TypeData bd = new TypeData (document, classes, t);
324 abstract class MemberData : BaseData
326 MemberReference [] members;
328 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
329 : base (document, parent)
331 this.members = members;
334 public override void DoOutput ()
336 XmlNode mclass = document.CreateElement (ParentTag, null);
337 parent.AppendChild (mclass);
339 foreach (MemberReference member in members) {
340 XmlNode mnode = document.CreateElement (Tag, null);
341 mclass.AppendChild (mnode);
342 AddAttribute (mnode, "name", GetName (member));
343 if (!NoMemberAttributes)
344 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
346 AttributeData.OutputAttributes (document, mnode, (ICustomAttributeProvider) member);
348 AddExtraData (mnode, member);
352 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
356 protected virtual string GetName (MemberReference memberDefenition)
361 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
366 public virtual bool NoMemberAttributes {
367 get { return false; }
371 public virtual string ParentTag {
372 get { return "NoPARENTTAG"; }
375 public virtual string Tag {
376 get { return "NoTAG"; }
379 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
381 if (provider.GenericParameters.Count == 0)
384 var gparameters = provider.GenericParameters;
386 XmlElement ngeneric = document.CreateElement ("generic-parameters");
387 nclass.AppendChild (ngeneric);
389 foreach (GenericParameter gp in gparameters) {
390 XmlElement nparam = document.CreateElement ("generic-parameter");
391 nparam.SetAttribute ("name", gp.Name);
392 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
394 AttributeData.OutputAttributes (document, nparam, gp);
396 ngeneric.AppendChild (nparam);
398 var constraints = gp.Constraints;
399 if (constraints.Count == 0)
402 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
404 foreach (TypeReference constraint in constraints) {
405 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
406 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
407 nconstraint.AppendChild (ncons);
410 nparam.AppendChild (nconstraint);
415 class TypeData : MemberData
419 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
420 : base (document, parent, null)
424 public override void DoOutput ()
426 if (document == null)
427 throw new InvalidOperationException ("Document not set");
429 XmlNode nclass = document.CreateElement ("class", null);
430 AddAttribute (nclass, "name", type.Name);
431 string classType = GetClassType (type);
432 AddAttribute (nclass, "type", classType);
434 if (type.BaseType != null)
435 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
438 AddAttribute (nclass, "sealed", "true");
441 AddAttribute (nclass, "abstract", "true");
443 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
444 AddAttribute (nclass, "serializable", "true");
446 string charSet = GetCharSet (type);
447 AddAttribute (nclass, "charset", charSet);
449 string layout = GetLayout (type);
451 AddAttribute (nclass, "layout", layout);
453 if (type.PackingSize >= 0) {
454 AddAttribute (nclass, "pack", type.PackingSize.ToString ());
457 if (type.ClassSize >= 0) {
458 AddAttribute (nclass, "size", type.ClassSize.ToString ());
461 parent.AppendChild (nclass);
463 AttributeData.OutputAttributes (document, nclass, type);
465 XmlNode ifaces = null;
467 foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) {
468 if (!TypeHelper.IsPublic (iface))
469 // we're only interested in public interfaces
472 if (ifaces == null) {
473 ifaces = document.CreateElement ("interfaces", null);
474 nclass.AppendChild (ifaces);
477 XmlNode iface_node = document.CreateElement ("interface", null);
478 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
479 ifaces.AppendChild (iface_node);
482 MemberData.OutputGenericParameters (document, nclass, type);
484 ArrayList members = new ArrayList ();
486 FieldDefinition [] fields = GetFields (type);
487 if (fields.Length > 0) {
488 Array.Sort (fields, MemberReferenceComparer.Default);
489 FieldData fd = new FieldData (document, nclass, fields);
494 var value_type = GetEnumValueField (type);
495 if (value_type == null)
496 throw new NotSupportedException ();
498 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
501 if (!Driver.AbiMode) {
503 MethodDefinition [] ctors = GetConstructors (type);
504 if (ctors.Length > 0) {
505 Array.Sort (ctors, MethodDefinitionComparer.Default);
506 members.Add (new ConstructorData (document, nclass, ctors));
509 PropertyDefinition[] properties = GetProperties (type);
510 if (properties.Length > 0) {
511 Array.Sort (properties, PropertyDefinitionComparer.Default);
512 members.Add (new PropertyData (document, nclass, properties));
515 EventDefinition [] events = GetEvents (type);
516 if (events.Length > 0) {
517 Array.Sort (events, MemberReferenceComparer.Default);
518 members.Add (new EventData (document, nclass, events));
521 MethodDefinition [] methods = GetMethods (type);
522 if (methods.Length > 0) {
523 Array.Sort (methods, MethodDefinitionComparer.Default);
524 members.Add (new MethodData (document, nclass, methods));
528 foreach (MemberData md in members)
531 var nested = type.NestedTypes;
532 //remove non public(familiy) and nested in second degree
533 for (int i = nested.Count - 1; i >= 0; i--) {
534 TypeDefinition t = nested [i];
535 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
536 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
537 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
539 if (t.DeclaringType == type)
540 continue; // not nested of nested
546 if (nested.Count > 0) {
547 var nestedArray = nested.ToArray ();
548 Array.Sort (nestedArray, TypeReferenceComparer.Default);
550 XmlNode classes = document.CreateElement ("classes", null);
551 nclass.AppendChild (classes);
552 foreach (TypeDefinition t in nestedArray) {
553 TypeData td = new TypeData (document, classes, t);
559 static FieldReference GetEnumValueField (TypeDefinition type)
561 foreach (FieldDefinition field in type.Fields)
562 if (field.IsSpecialName && field.Name == "value__")
568 protected override string GetMemberAttributes (MemberReference member)
571 throw new InvalidOperationException ("odd");
573 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
576 public static bool MustDocumentMethod (MethodDefinition method) {
578 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
579 return maskedAccess == MethodAttributes.Public
580 || maskedAccess == MethodAttributes.Family
581 || maskedAccess == MethodAttributes.FamORAssem;
584 static string GetClassType (TypeDefinition t)
595 if (TypeHelper.IsDelegate(t))
604 static string GetCharSet (TypeDefinition type)
606 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
607 if (maskedStringFormat == TypeAttributes.AnsiClass)
608 return CharSet.Ansi.ToString ();
610 if (maskedStringFormat == TypeAttributes.AutoClass)
611 return CharSet.Auto.ToString ();
613 if (maskedStringFormat == TypeAttributes.UnicodeClass)
614 return CharSet.Unicode.ToString ();
616 return CharSet.None.ToString ();
619 static string GetLayout (TypeDefinition type)
621 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
622 if (maskedLayout == TypeAttributes.AutoLayout)
623 return LayoutKind.Auto.ToString ();
625 if (maskedLayout == TypeAttributes.ExplicitLayout)
626 return LayoutKind.Explicit.ToString ();
628 if (maskedLayout == TypeAttributes.SequentialLayout)
629 return LayoutKind.Sequential.ToString ();
634 FieldDefinition [] GetFields (TypeDefinition type) {
635 ArrayList list = new ArrayList ();
637 var fields = type.Fields;
638 foreach (FieldDefinition field in fields) {
639 if (field.IsSpecialName)
642 if (Driver.AbiMode && field.IsStatic)
645 // we're only interested in public or protected members
646 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
647 if (Driver.AbiMode && !field.IsNotSerialized) {
650 if (maskedVisibility == FieldAttributes.Public
651 || maskedVisibility == FieldAttributes.Family
652 || maskedVisibility == FieldAttributes.FamORAssem) {
658 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
662 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
663 ArrayList list = new ArrayList ();
665 var properties = type.Properties;//type.GetProperties (flags);
666 foreach (PropertyDefinition property in properties) {
667 MethodDefinition getMethod = property.GetMethod;
668 MethodDefinition setMethod = property.SetMethod;
670 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
671 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
673 // if neither the getter or setter should be documented, then
675 if (hasGetter || hasSetter) {
680 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
683 private MethodDefinition[] GetMethods (TypeDefinition type)
685 ArrayList list = new ArrayList ();
687 var methods = type.Methods;//type.GetMethods (flags);
688 foreach (MethodDefinition method in methods) {
689 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
692 // we're only interested in public or protected members
693 if (!MustDocumentMethod(method))
696 if (IsFinalizer (method)) {
697 string name = method.DeclaringType.Name;
698 int arity = name.IndexOf ('`');
700 name = name.Substring (0, arity);
702 method.Name = "~" + name;
708 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
711 static bool IsFinalizer (MethodDefinition method)
713 if (method.Name != "Finalize")
716 if (!method.IsVirtual)
719 if (method.Parameters.Count != 0)
725 private MethodDefinition [] GetConstructors (TypeDefinition type)
727 ArrayList list = new ArrayList ();
729 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
730 foreach (MethodDefinition constructor in ctors) {
731 // we're only interested in public or protected members
732 if (!MustDocumentMethod(constructor))
735 list.Add (constructor);
738 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
741 private EventDefinition[] GetEvents (TypeDefinition type)
743 ArrayList list = new ArrayList ();
745 var events = type.Events;//type.GetEvents (flags);
746 foreach (EventDefinition eventDef in events) {
747 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
749 if (addMethod == null || !MustDocumentMethod (addMethod))
755 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
759 class FieldData : MemberData
761 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
762 : base (document, parent, members)
766 protected override string GetName (MemberReference memberDefenition)
768 FieldDefinition field = (FieldDefinition) memberDefenition;
772 protected override string GetMemberAttributes (MemberReference memberDefenition)
774 FieldDefinition field = (FieldDefinition) memberDefenition;
775 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
778 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
780 base.AddExtraData (p, memberDefenition);
781 FieldDefinition field = (FieldDefinition) memberDefenition;
782 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
784 if (field.IsLiteral) {
785 object value = field.Constant;//object value = field.GetValue (null);
786 string stringValue = null;
787 //if (value is Enum) {
788 // // FIXME: when Mono bug #60090 has been
789 // // fixed, we should just be able to use
790 // // Convert.ToString
791 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
794 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
797 if (stringValue != null)
798 AddAttribute (p, "value", stringValue);
802 public override string ParentTag {
803 get { return "fields"; }
806 public override string Tag {
807 get { return "field"; }
811 class PropertyData : MemberData
813 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
814 : base (document, parent, members)
818 protected override string GetName (MemberReference memberDefenition)
820 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
824 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
826 base.AddExtraData (p, memberDefenition);
827 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
828 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
829 MethodDefinition _get = prop.GetMethod;
830 MethodDefinition _set = prop.SetMethod;
831 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
832 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
833 MethodDefinition [] methods;
835 if (haveGet && haveSet) {
836 methods = new MethodDefinition [] { _get, _set };
837 } else if (haveGet) {
838 methods = new MethodDefinition [] { _get };
839 } else if (haveSet) {
840 methods = new MethodDefinition [] { _set };
846 if (haveGet || _set.Parameters.Count > 1) {
847 string parms = Parameters.GetSignature (methods [0].Parameters);
848 if (!string.IsNullOrEmpty (parms))
849 AddAttribute (p, "params", parms);
852 MethodData data = new MethodData (document, p, methods);
853 //data.NoMemberAttributes = true;
857 protected override string GetMemberAttributes (MemberReference memberDefenition)
859 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
860 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
863 public override string ParentTag {
864 get { return "properties"; }
867 public override string Tag {
868 get { return "property"; }
872 class EventData : MemberData
874 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
875 : base (document, parent, members)
879 protected override string GetName (MemberReference memberDefenition)
881 EventDefinition evt = (EventDefinition) memberDefenition;
885 protected override string GetMemberAttributes (MemberReference memberDefenition)
887 EventDefinition evt = (EventDefinition) memberDefenition;
888 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
891 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
893 base.AddExtraData (p, memberDefenition);
894 EventDefinition evt = (EventDefinition) memberDefenition;
895 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
898 public override string ParentTag {
899 get { return "events"; }
902 public override string Tag {
903 get { return "event"; }
907 class MethodData : MemberData
911 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
912 : base (document, parent, members)
916 protected override string GetName (MemberReference memberDefenition)
918 MethodDefinition method = (MethodDefinition) memberDefenition;
919 string name = method.Name;
920 string parms = Parameters.GetSignature (method.Parameters);
922 return string.Format ("{0}({1})", name, parms);
925 protected override string GetMemberAttributes (MemberReference memberDefenition)
927 MethodDefinition method = (MethodDefinition) memberDefenition;
928 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
931 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
933 base.AddExtraData (p, memberDefenition);
935 if (!(memberDefenition is MethodDefinition))
938 MethodDefinition mbase = (MethodDefinition) memberDefenition;
940 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
943 if (mbase.IsAbstract)
944 AddAttribute (p, "abstract", "true");
946 AddAttribute (p, "virtual", "true");
947 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
948 AddAttribute (p, "sealed", "true");
950 AddAttribute (p, "static", "true");
952 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
953 if (rettype != "System.Void" || !mbase.IsConstructor)
954 AddAttribute (p, "returntype", (rettype));
956 AttributeData.OutputAttributes (document, p, mbase.MethodReturnType);
958 MemberData.OutputGenericParameters (document, p, mbase);
961 public override bool NoMemberAttributes {
962 get { return noAtts; }
963 set { noAtts = value; }
966 public override string ParentTag {
967 get { return "methods"; }
970 public override string Tag {
971 get { return "method"; }
975 class ConstructorData : MethodData
977 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
978 : base (document, parent, members)
982 public override string ParentTag {
983 get { return "constructors"; }
986 public override string Tag {
987 get { return "constructor"; }
991 class ParameterData : BaseData
993 private IList<ParameterDefinition> parameters;
995 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
996 : base (document, parent)
998 this.parameters = parameters;
1001 public override void DoOutput ()
1003 XmlNode parametersNode = document.CreateElement ("parameters");
1004 parent.AppendChild (parametersNode);
1006 foreach (ParameterDefinition parameter in parameters) {
1007 XmlNode paramNode = document.CreateElement ("parameter");
1008 parametersNode.AppendChild (paramNode);
1009 AddAttribute (paramNode, "name", parameter.Name);
1010 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1011 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
1013 string direction = "in";
1015 if (parameter.ParameterType is ByReferenceType)
1016 direction = parameter.IsOut ? "out" : "ref";
1018 TypeReference t = parameter.ParameterType;
1019 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
1021 if (parameter.IsOptional) {
1022 AddAttribute (paramNode, "optional", "true");
1023 if (parameter.HasConstant)
1024 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1027 if (direction != "in")
1028 AddAttribute (paramNode, "direction", direction);
1030 AttributeData.OutputAttributes (document, paramNode, parameter);
1035 class AttributeData : BaseData
1037 IList<CustomAttribute> atts;
1039 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1040 : base (doc, parent)
1045 public override void DoOutput ()
1047 if (document == null)
1048 throw new InvalidOperationException ("Document not set");
1050 if (atts == null || atts.Count == 0)
1053 XmlNode natts = parent.SelectSingleNode("attributes");
1054 if (natts == null) {
1055 natts = document.CreateElement ("attributes", null);
1056 parent.AppendChild (natts);
1059 foreach (var att in atts.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) {
1060 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1061 if (SkipAttribute (att))
1064 XmlNode node = document.CreateElement ("attribute");
1065 AddAttribute (node, "name", attName);
1067 XmlNode properties = null;
1069 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
1071 foreach (string name in attribute_mapping.Keys) {
1072 if (name == "TypeId")
1075 if (properties == null) {
1076 properties = node.AppendChild (document.CreateElement ("properties"));
1079 object o = attribute_mapping [name];
1081 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1082 AddAttribute (n, "name", name);
1085 AddAttribute (n, "value", "null");
1089 string value = o.ToString ();
1090 if (attName.EndsWith ("GuidAttribute"))
1091 value = value.ToUpper ();
1092 AddAttribute (n, "value", value);
1095 natts.AppendChild (node);
1099 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1101 var mapping = new Dictionary<string, object> ();
1103 PopulateMapping (mapping, attribute);
1105 var constructor = attribute.Constructor.Resolve ();
1106 if (constructor == null || !constructor.HasParameters)
1109 PopulateMapping (mapping, constructor, attribute);
1114 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1116 if (!attribute.HasProperties)
1119 foreach (var named_argument in attribute.Properties) {
1120 var name = named_argument.Name;
1121 var arg = named_argument.Argument;
1123 if (arg.Value is CustomAttributeArgument)
1124 arg = (CustomAttributeArgument) arg.Value;
1126 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1130 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1132 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1134 int? argument = null;
1136 foreach (Instruction instruction in constructor.Body.Instructions) {
1137 switch (instruction.OpCode.Code) {
1149 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1153 FieldReference field = (FieldReference) instruction.Operand;
1154 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1157 if (!argument.HasValue)
1160 if (!field_mapping.ContainsKey (field))
1161 field_mapping.Add (field, (int) argument - 1);
1168 return field_mapping;
1171 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1173 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1175 foreach (PropertyDefinition property in type.Properties) {
1176 if (property.GetMethod == null)
1178 if (!property.GetMethod.HasBody)
1181 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1182 if (instruction.OpCode.Code != Code.Ldfld)
1185 FieldReference field = (FieldReference) instruction.Operand;
1186 if (field.DeclaringType.FullName != type.FullName)
1189 property_mapping.Add (property, field);
1194 return property_mapping;
1197 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1199 if (!constructor.HasBody)
1202 // Custom handling for attributes with arguments which cannot be easily extracted
1203 var ca = attribute.ConstructorArguments;
1204 switch (constructor.DeclaringType.FullName) {
1205 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1206 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1207 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1208 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1210 mapping.Add ("Value", dca.Value);
1212 case "System.ComponentModel.BindableAttribute":
1216 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1217 mapping.Add ("Bindable", ca[0].Value);
1219 throw new NotImplementedException ();
1225 var field_mapping = CreateArgumentFieldMapping (constructor);
1226 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1228 foreach (var pair in property_mapping) {
1230 if (!field_mapping.TryGetValue (pair.Value, out argument))
1233 var ca_arg = ca [argument];
1234 if (ca_arg.Value is CustomAttributeArgument)
1235 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1237 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1241 static object GetArgumentValue (TypeReference reference, object value)
1243 var type = reference.Resolve ();
1248 if (IsFlaggedEnum (type))
1249 return GetFlaggedEnumValue (type, value);
1251 return GetEnumValue (type, value);
1257 static bool IsFlaggedEnum (TypeDefinition type)
1262 if (!type.HasCustomAttributes)
1265 foreach (CustomAttribute attribute in type.CustomAttributes)
1266 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1272 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1275 return GetFlaggedEnumValue (type, (ulong)value);
1277 long flags = Convert.ToInt64 (value);
1278 var signature = new StringBuilder ();
1280 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1281 FieldDefinition field = type.Fields [i];
1283 if (!field.HasConstant)
1286 long flag = Convert.ToInt64 (field.Constant);
1291 if ((flags & flag) == flag) {
1292 if (signature.Length != 0)
1293 signature.Append (", ");
1295 signature.Append (field.Name);
1300 return signature.ToString ();
1303 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1305 var signature = new StringBuilder ();
1307 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1308 FieldDefinition field = type.Fields [i];
1310 if (!field.HasConstant)
1313 ulong flag = Convert.ToUInt64 (field.Constant);
1318 if ((flags & flag) == flag) {
1319 if (signature.Length != 0)
1320 signature.Append (", ");
1322 signature.Append (field.Name);
1327 return signature.ToString ();
1330 static object GetEnumValue (TypeDefinition type, object value)
1332 foreach (FieldDefinition field in type.Fields) {
1333 if (!field.HasConstant)
1336 if (Comparer.Default.Compare (field.Constant, value) == 0)
1343 static bool SkipAttribute (CustomAttribute attribute)
1345 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1347 return !TypeHelper.IsPublic (attribute)
1348 || type_name.EndsWith ("TODOAttribute");
1351 public static void OutputAttributes (XmlDocument doc, XmlNode parent, ICustomAttributeProvider provider)
1353 if (!provider.HasCustomAttributes)
1356 AttributeData ad = new AttributeData (doc, parent, provider.CustomAttributes);
1361 static class Parameters {
1363 public static string GetSignature (IList<ParameterDefinition> infos)
1365 if (infos == null || infos.Count == 0)
1366 return string.Empty;
1368 var signature = new StringBuilder ();
1369 for (int i = 0; i < infos.Count; i++) {
1372 signature.Append (", ");
1374 ParameterDefinition info = infos [i];
1377 if ((info.Attributes & ParameterAttributes.In) != 0)
1379 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1382 modifier = string.Empty;
1384 if (modifier.Length > 0) {
1385 signature.Append (modifier);
1386 signature.Append (" ");
1389 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1392 return signature.ToString ();
1397 class TypeReferenceComparer : IComparer<TypeReference>
1399 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1401 public int Compare (TypeReference a, TypeReference b)
1403 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1407 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1411 class MemberReferenceComparer : IComparer
1413 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1415 public int Compare (object a, object b)
1417 MemberReference ma = (MemberReference) a;
1418 MemberReference mb = (MemberReference) b;
1419 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1423 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1425 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1427 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1429 int res = String.Compare (ma.Name, mb.Name);
1433 if (!ma.HasParameters && !mb.HasParameters)
1436 if (!ma.HasParameters)
1439 if (!mb.HasParameters)
1442 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1446 class MethodDefinitionComparer : IComparer
1448 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1450 public int Compare (object a, object b)
1452 MethodDefinition ma = (MethodDefinition) a;
1453 MethodDefinition mb = (MethodDefinition) b;
1454 int res = String.Compare (ma.Name, mb.Name);
1458 if (!ma.HasParameters && !mb.HasParameters)
1461 if (!ma.HasParameters)
1464 if (!mb.HasParameters)
1467 res = Compare (ma.Parameters, mb.Parameters);
1471 // operators can differ by only return type
1472 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1475 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1477 var res = pia.Count - pib.Count;
1481 string siga = Parameters.GetSignature (pia);
1482 string sigb = Parameters.GetSignature (pib);
1483 return String.Compare (siga, sigb);