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;
35 var acoll = new AssemblyCollection ();
37 var options = new Mono.Options.OptionSet {
38 { "h|help", "Show this help", v => showHelp = true },
39 { "abi", _ => AbiMode = true},
40 { "f|follow-forwarders", _ => FollowForwarders = true },
41 { "d|search-directory=", v => TypeHelper.Resolver.AddSearchDirectory (v) },
44 var asms = options.Parse (args);
46 if (showHelp || asms.Count == 0) {
47 Console.WriteLine (@"Usage: mono-api-info [options] <assemblies>");
49 Console.WriteLine ("Available options:");
50 options.WriteOptionDescriptions (Console.Out);
52 return showHelp? 0 :1;
55 string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
56 string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
57 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
59 foreach (string arg in asms) {
62 if (arg.Contains ("v3.0")) {
63 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
64 } else if (arg.Contains ("v3.5")) {
65 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
66 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
67 } else if (arg.Contains ("v4.0")) {
68 if (arg.Contains ("Silverlight")) {
69 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
71 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
72 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
75 TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
79 XmlDocument doc = new XmlDocument ();
83 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
84 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
85 doc.InsertBefore (decl, doc.DocumentElement);
90 internal static bool AbiMode { get; private set; }
91 internal static bool FollowForwarders { get; private set; }
96 public static string CleanupTypeName (TypeReference type)
98 return CleanupTypeName (type.FullName);
101 public static string CleanupTypeName (string t)
103 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
107 class AssemblyCollection
109 XmlDocument document;
110 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
112 public AssemblyCollection ()
116 public bool Add (string name)
118 AssemblyDefinition ass = LoadAssembly (name);
120 Console.Error.WriteLine ("Cannot load assembly file " + name);
124 assemblies.Add (ass);
128 public void DoOutput ()
130 if (document == null)
131 throw new InvalidOperationException ("Document not set");
133 XmlNode nassemblies = document.CreateElement ("assemblies", null);
134 document.AppendChild (nassemblies);
135 foreach (AssemblyDefinition a in assemblies) {
136 AssemblyData data = new AssemblyData (document, nassemblies, a);
141 public XmlDocument Document {
142 set { document = value; }
145 AssemblyDefinition LoadAssembly (string assembly)
148 if (File.Exists (assembly))
149 return TypeHelper.Resolver.ResolveFile (assembly);
151 return TypeHelper.Resolver.Resolve (assembly);
152 } catch (Exception e) {
153 Console.WriteLine (e);
159 abstract class BaseData
161 protected XmlDocument document;
162 protected XmlNode parent;
164 protected BaseData (XmlDocument doc, XmlNode parent)
167 this.parent = parent;
170 public abstract void DoOutput ();
172 protected void AddAttribute (XmlNode node, string name, string value)
174 XmlAttribute attr = document.CreateAttribute (name);
176 node.Attributes.Append (attr);
180 class TypeForwardedToData : BaseData
182 AssemblyDefinition ass;
184 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
185 : base (document, parent)
190 public override void DoOutput ()
192 XmlNode natts = parent.SelectSingleNode("attributes");
194 natts = document.CreateElement ("attributes", null);
195 parent.AppendChild (natts);
198 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
200 if (((uint)type.Attributes & 0x200000u) == 0)
203 XmlNode node = document.CreateElement ("attribute");
204 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
205 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
206 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
207 AddAttribute (property, "name", "Destination");
208 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
209 natts.AppendChild (node);
213 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
215 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
220 class AssemblyData : BaseData
222 AssemblyDefinition ass;
224 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
225 : base (document, parent)
230 public override void DoOutput ()
232 if (document == null)
233 throw new InvalidOperationException ("Document not set");
235 XmlNode nassembly = document.CreateElement ("assembly", null);
236 AssemblyNameDefinition aname = ass.Name;
237 AddAttribute (nassembly, "name", aname.Name);
238 AddAttribute (nassembly, "version", aname.Version.ToString ());
239 parent.AppendChild (nassembly);
241 if (!Driver.FollowForwarders) {
242 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
245 AttributeData.OutputAttributes (document, nassembly, ass);
247 var types = new List<TypeDefinition> ();
248 if (ass.MainModule.Types != null) {
249 types.AddRange (ass.MainModule.Types);
252 if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
253 foreach (var t in ass.MainModule.ExportedTypes) {
254 var forwarded = t.Resolve ();
255 if (forwarded == null) {
256 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
258 types.Add (forwarded);
262 if (types.Count == 0) {
266 types.Sort (TypeReferenceComparer.Default);
268 XmlNode nss = document.CreateElement ("namespaces", null);
269 nassembly.AppendChild (nss);
271 string current_namespace = "$%&$&";
273 XmlNode classes = null;
274 foreach (TypeDefinition t in types) {
275 if (string.IsNullOrEmpty (t.Namespace))
278 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
281 if (t.DeclaringType != null)
282 continue; // enforce !nested
284 if (t.Namespace != current_namespace) {
285 current_namespace = t.Namespace;
286 ns = document.CreateElement ("namespace", null);
287 AddAttribute (ns, "name", current_namespace);
288 nss.AppendChild (ns);
289 classes = document.CreateElement ("classes", null);
290 ns.AppendChild (classes);
293 TypeData bd = new TypeData (document, classes, t);
299 abstract class MemberData : BaseData
301 MemberReference [] members;
303 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
304 : base (document, parent)
306 this.members = members;
309 public override void DoOutput ()
311 XmlNode mclass = document.CreateElement (ParentTag, null);
312 parent.AppendChild (mclass);
314 foreach (MemberReference member in members) {
315 XmlNode mnode = document.CreateElement (Tag, null);
316 mclass.AppendChild (mnode);
317 AddAttribute (mnode, "name", GetName (member));
318 if (!NoMemberAttributes)
319 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
321 AttributeData.OutputAttributes (document, mnode, (ICustomAttributeProvider) member);
323 AddExtraData (mnode, member);
327 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
331 protected virtual string GetName (MemberReference memberDefenition)
336 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
341 public virtual bool NoMemberAttributes {
342 get { return false; }
346 public virtual string ParentTag {
347 get { return "NoPARENTTAG"; }
350 public virtual string Tag {
351 get { return "NoTAG"; }
354 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
356 if (provider.GenericParameters.Count == 0)
359 var gparameters = provider.GenericParameters;
361 XmlElement ngeneric = document.CreateElement ("generic-parameters");
362 nclass.AppendChild (ngeneric);
364 foreach (GenericParameter gp in gparameters) {
365 XmlElement nparam = document.CreateElement ("generic-parameter");
366 nparam.SetAttribute ("name", gp.Name);
367 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
369 AttributeData.OutputAttributes (document, nparam, gp);
371 ngeneric.AppendChild (nparam);
373 var constraints = gp.Constraints;
374 if (constraints.Count == 0)
377 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
379 foreach (TypeReference constraint in constraints) {
380 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
381 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
382 nconstraint.AppendChild (ncons);
385 nparam.AppendChild (nconstraint);
390 class TypeData : MemberData
394 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
395 : base (document, parent, null)
399 public override void DoOutput ()
401 if (document == null)
402 throw new InvalidOperationException ("Document not set");
404 XmlNode nclass = document.CreateElement ("class", null);
405 AddAttribute (nclass, "name", type.Name);
406 string classType = GetClassType (type);
407 AddAttribute (nclass, "type", classType);
409 if (type.BaseType != null)
410 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
413 AddAttribute (nclass, "sealed", "true");
416 AddAttribute (nclass, "abstract", "true");
418 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
419 AddAttribute (nclass, "serializable", "true");
421 string charSet = GetCharSet (type);
422 AddAttribute (nclass, "charset", charSet);
424 string layout = GetLayout (type);
426 AddAttribute (nclass, "layout", layout);
428 if (type.PackingSize >= 0) {
429 AddAttribute (nclass, "pack", type.PackingSize.ToString ());
432 if (type.ClassSize >= 0) {
433 AddAttribute (nclass, "size", type.ClassSize.ToString ());
436 parent.AppendChild (nclass);
438 AttributeData.OutputAttributes (document, nclass, type);
440 XmlNode ifaces = null;
442 foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) {
443 if (!TypeHelper.IsPublic (iface))
444 // we're only interested in public interfaces
447 if (ifaces == null) {
448 ifaces = document.CreateElement ("interfaces", null);
449 nclass.AppendChild (ifaces);
452 XmlNode iface_node = document.CreateElement ("interface", null);
453 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
454 ifaces.AppendChild (iface_node);
457 MemberData.OutputGenericParameters (document, nclass, type);
459 ArrayList members = new ArrayList ();
461 FieldDefinition [] fields = GetFields (type);
462 if (fields.Length > 0) {
463 Array.Sort (fields, MemberReferenceComparer.Default);
464 FieldData fd = new FieldData (document, nclass, fields);
469 var value_type = GetEnumValueField (type);
470 if (value_type == null)
471 throw new NotSupportedException ();
473 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
476 if (!Driver.AbiMode) {
478 MethodDefinition [] ctors = GetConstructors (type);
479 if (ctors.Length > 0) {
480 Array.Sort (ctors, MethodDefinitionComparer.Default);
481 members.Add (new ConstructorData (document, nclass, ctors));
484 PropertyDefinition[] properties = GetProperties (type);
485 if (properties.Length > 0) {
486 Array.Sort (properties, PropertyDefinitionComparer.Default);
487 members.Add (new PropertyData (document, nclass, properties));
490 EventDefinition [] events = GetEvents (type);
491 if (events.Length > 0) {
492 Array.Sort (events, MemberReferenceComparer.Default);
493 members.Add (new EventData (document, nclass, events));
496 MethodDefinition [] methods = GetMethods (type);
497 if (methods.Length > 0) {
498 Array.Sort (methods, MethodDefinitionComparer.Default);
499 members.Add (new MethodData (document, nclass, methods));
503 foreach (MemberData md in members)
506 var nested = type.NestedTypes;
507 //remove non public(familiy) and nested in second degree
508 for (int i = nested.Count - 1; i >= 0; i--) {
509 TypeDefinition t = nested [i];
510 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
511 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
512 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
514 if (t.DeclaringType == type)
515 continue; // not nested of nested
521 if (nested.Count > 0) {
522 var nestedArray = nested.ToArray ();
523 Array.Sort (nestedArray, TypeReferenceComparer.Default);
525 XmlNode classes = document.CreateElement ("classes", null);
526 nclass.AppendChild (classes);
527 foreach (TypeDefinition t in nestedArray) {
528 TypeData td = new TypeData (document, classes, t);
534 static FieldReference GetEnumValueField (TypeDefinition type)
536 foreach (FieldDefinition field in type.Fields)
537 if (field.IsSpecialName && field.Name == "value__")
543 protected override string GetMemberAttributes (MemberReference member)
546 throw new InvalidOperationException ("odd");
548 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
551 public static bool MustDocumentMethod (MethodDefinition method) {
553 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
554 return maskedAccess == MethodAttributes.Public
555 || maskedAccess == MethodAttributes.Family
556 || maskedAccess == MethodAttributes.FamORAssem;
559 static string GetClassType (TypeDefinition t)
570 if (TypeHelper.IsDelegate(t))
579 static string GetCharSet (TypeDefinition type)
581 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
582 if (maskedStringFormat == TypeAttributes.AnsiClass)
583 return CharSet.Ansi.ToString ();
585 if (maskedStringFormat == TypeAttributes.AutoClass)
586 return CharSet.Auto.ToString ();
588 if (maskedStringFormat == TypeAttributes.UnicodeClass)
589 return CharSet.Unicode.ToString ();
591 return CharSet.None.ToString ();
594 static string GetLayout (TypeDefinition type)
596 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
597 if (maskedLayout == TypeAttributes.AutoLayout)
598 return LayoutKind.Auto.ToString ();
600 if (maskedLayout == TypeAttributes.ExplicitLayout)
601 return LayoutKind.Explicit.ToString ();
603 if (maskedLayout == TypeAttributes.SequentialLayout)
604 return LayoutKind.Sequential.ToString ();
609 FieldDefinition [] GetFields (TypeDefinition type) {
610 ArrayList list = new ArrayList ();
612 var fields = type.Fields;
613 foreach (FieldDefinition field in fields) {
614 if (field.IsSpecialName)
617 if (Driver.AbiMode && field.IsStatic)
620 // we're only interested in public or protected members
621 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
622 if (Driver.AbiMode && !field.IsNotSerialized) {
625 if (maskedVisibility == FieldAttributes.Public
626 || maskedVisibility == FieldAttributes.Family
627 || maskedVisibility == FieldAttributes.FamORAssem) {
633 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
637 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
638 ArrayList list = new ArrayList ();
640 var properties = type.Properties;//type.GetProperties (flags);
641 foreach (PropertyDefinition property in properties) {
642 MethodDefinition getMethod = property.GetMethod;
643 MethodDefinition setMethod = property.SetMethod;
645 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
646 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
648 // if neither the getter or setter should be documented, then
650 if (hasGetter || hasSetter) {
655 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
658 private MethodDefinition[] GetMethods (TypeDefinition type)
660 ArrayList list = new ArrayList ();
662 var methods = type.Methods;//type.GetMethods (flags);
663 foreach (MethodDefinition method in methods) {
664 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
667 // we're only interested in public or protected members
668 if (!MustDocumentMethod(method))
671 if (IsFinalizer (method)) {
672 string name = method.DeclaringType.Name;
673 int arity = name.IndexOf ('`');
675 name = name.Substring (0, arity);
677 method.Name = "~" + name;
683 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
686 static bool IsFinalizer (MethodDefinition method)
688 if (method.Name != "Finalize")
691 if (!method.IsVirtual)
694 if (method.Parameters.Count != 0)
700 private MethodDefinition [] GetConstructors (TypeDefinition type)
702 ArrayList list = new ArrayList ();
704 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
705 foreach (MethodDefinition constructor in ctors) {
706 // we're only interested in public or protected members
707 if (!MustDocumentMethod(constructor))
710 list.Add (constructor);
713 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
716 private EventDefinition[] GetEvents (TypeDefinition type)
718 ArrayList list = new ArrayList ();
720 var events = type.Events;//type.GetEvents (flags);
721 foreach (EventDefinition eventDef in events) {
722 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
724 if (addMethod == null || !MustDocumentMethod (addMethod))
730 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
734 class FieldData : MemberData
736 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
737 : base (document, parent, members)
741 protected override string GetName (MemberReference memberDefenition)
743 FieldDefinition field = (FieldDefinition) memberDefenition;
747 protected override string GetMemberAttributes (MemberReference memberDefenition)
749 FieldDefinition field = (FieldDefinition) memberDefenition;
750 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
753 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
755 base.AddExtraData (p, memberDefenition);
756 FieldDefinition field = (FieldDefinition) memberDefenition;
757 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
759 if (field.IsLiteral) {
760 object value = field.Constant;//object value = field.GetValue (null);
761 string stringValue = null;
762 //if (value is Enum) {
763 // // FIXME: when Mono bug #60090 has been
764 // // fixed, we should just be able to use
765 // // Convert.ToString
766 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
769 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
772 if (stringValue != null)
773 AddAttribute (p, "value", stringValue);
777 public override string ParentTag {
778 get { return "fields"; }
781 public override string Tag {
782 get { return "field"; }
786 class PropertyData : MemberData
788 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
789 : base (document, parent, members)
793 protected override string GetName (MemberReference memberDefenition)
795 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
799 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
801 base.AddExtraData (p, memberDefenition);
802 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
803 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
804 MethodDefinition _get = prop.GetMethod;
805 MethodDefinition _set = prop.SetMethod;
806 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
807 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
808 MethodDefinition [] methods;
810 if (haveGet && haveSet) {
811 methods = new MethodDefinition [] { _get, _set };
812 } else if (haveGet) {
813 methods = new MethodDefinition [] { _get };
814 } else if (haveSet) {
815 methods = new MethodDefinition [] { _set };
821 if (haveGet || _set.Parameters.Count > 1) {
822 string parms = Parameters.GetSignature (methods [0].Parameters);
823 if (!string.IsNullOrEmpty (parms))
824 AddAttribute (p, "params", parms);
827 MethodData data = new MethodData (document, p, methods);
828 //data.NoMemberAttributes = true;
832 protected override string GetMemberAttributes (MemberReference memberDefenition)
834 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
835 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
838 public override string ParentTag {
839 get { return "properties"; }
842 public override string Tag {
843 get { return "property"; }
847 class EventData : MemberData
849 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
850 : base (document, parent, members)
854 protected override string GetName (MemberReference memberDefenition)
856 EventDefinition evt = (EventDefinition) memberDefenition;
860 protected override string GetMemberAttributes (MemberReference memberDefenition)
862 EventDefinition evt = (EventDefinition) memberDefenition;
863 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
866 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
868 base.AddExtraData (p, memberDefenition);
869 EventDefinition evt = (EventDefinition) memberDefenition;
870 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
873 public override string ParentTag {
874 get { return "events"; }
877 public override string Tag {
878 get { return "event"; }
882 class MethodData : MemberData
886 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
887 : base (document, parent, members)
891 protected override string GetName (MemberReference memberDefenition)
893 MethodDefinition method = (MethodDefinition) memberDefenition;
894 string name = method.Name;
895 string parms = Parameters.GetSignature (method.Parameters);
897 return string.Format ("{0}({1})", name, parms);
900 protected override string GetMemberAttributes (MemberReference memberDefenition)
902 MethodDefinition method = (MethodDefinition) memberDefenition;
903 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
906 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
908 base.AddExtraData (p, memberDefenition);
910 if (!(memberDefenition is MethodDefinition))
913 MethodDefinition mbase = (MethodDefinition) memberDefenition;
915 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
918 if (mbase.IsAbstract)
919 AddAttribute (p, "abstract", "true");
921 AddAttribute (p, "virtual", "true");
922 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
923 AddAttribute (p, "sealed", "true");
925 AddAttribute (p, "static", "true");
927 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
928 if (rettype != "System.Void" || !mbase.IsConstructor)
929 AddAttribute (p, "returntype", (rettype));
931 AttributeData.OutputAttributes (document, p, mbase.MethodReturnType);
933 MemberData.OutputGenericParameters (document, p, mbase);
936 public override bool NoMemberAttributes {
937 get { return noAtts; }
938 set { noAtts = value; }
941 public override string ParentTag {
942 get { return "methods"; }
945 public override string Tag {
946 get { return "method"; }
950 class ConstructorData : MethodData
952 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
953 : base (document, parent, members)
957 public override string ParentTag {
958 get { return "constructors"; }
961 public override string Tag {
962 get { return "constructor"; }
966 class ParameterData : BaseData
968 private IList<ParameterDefinition> parameters;
970 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
971 : base (document, parent)
973 this.parameters = parameters;
976 public override void DoOutput ()
978 XmlNode parametersNode = document.CreateElement ("parameters");
979 parent.AppendChild (parametersNode);
981 foreach (ParameterDefinition parameter in parameters) {
982 XmlNode paramNode = document.CreateElement ("parameter");
983 parametersNode.AppendChild (paramNode);
984 AddAttribute (paramNode, "name", parameter.Name);
985 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
986 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
988 string direction = "in";
990 if (parameter.ParameterType is ByReferenceType)
991 direction = parameter.IsOut ? "out" : "ref";
993 TypeReference t = parameter.ParameterType;
994 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
996 if (parameter.IsOptional) {
997 AddAttribute (paramNode, "optional", "true");
998 if (parameter.HasConstant)
999 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1002 if (direction != "in")
1003 AddAttribute (paramNode, "direction", direction);
1005 AttributeData.OutputAttributes (document, paramNode, parameter);
1010 class AttributeData : BaseData
1012 IList<CustomAttribute> atts;
1014 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1015 : base (doc, parent)
1020 public override void DoOutput ()
1022 if (document == null)
1023 throw new InvalidOperationException ("Document not set");
1025 if (atts == null || atts.Count == 0)
1028 XmlNode natts = parent.SelectSingleNode("attributes");
1029 if (natts == null) {
1030 natts = document.CreateElement ("attributes", null);
1031 parent.AppendChild (natts);
1034 foreach (var att in atts.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) {
1035 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1036 if (SkipAttribute (att))
1039 XmlNode node = document.CreateElement ("attribute");
1040 AddAttribute (node, "name", attName);
1042 XmlNode properties = null;
1044 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
1046 foreach (string name in attribute_mapping.Keys) {
1047 if (name == "TypeId")
1050 if (properties == null) {
1051 properties = node.AppendChild (document.CreateElement ("properties"));
1054 object o = attribute_mapping [name];
1056 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1057 AddAttribute (n, "name", name);
1060 AddAttribute (n, "value", "null");
1064 string value = o.ToString ();
1065 if (attName.EndsWith ("GuidAttribute"))
1066 value = value.ToUpper ();
1067 AddAttribute (n, "value", value);
1070 natts.AppendChild (node);
1074 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1076 var mapping = new Dictionary<string, object> ();
1078 PopulateMapping (mapping, attribute);
1080 var constructor = attribute.Constructor.Resolve ();
1081 if (constructor == null || !constructor.HasParameters)
1084 PopulateMapping (mapping, constructor, attribute);
1089 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1091 if (!attribute.HasProperties)
1094 foreach (var named_argument in attribute.Properties) {
1095 var name = named_argument.Name;
1096 var arg = named_argument.Argument;
1098 if (arg.Value is CustomAttributeArgument)
1099 arg = (CustomAttributeArgument) arg.Value;
1101 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1105 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1107 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1109 int? argument = null;
1111 foreach (Instruction instruction in constructor.Body.Instructions) {
1112 switch (instruction.OpCode.Code) {
1124 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1128 FieldReference field = (FieldReference) instruction.Operand;
1129 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1132 if (!argument.HasValue)
1135 if (!field_mapping.ContainsKey (field))
1136 field_mapping.Add (field, (int) argument - 1);
1143 return field_mapping;
1146 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1148 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1150 foreach (PropertyDefinition property in type.Properties) {
1151 if (property.GetMethod == null)
1153 if (!property.GetMethod.HasBody)
1156 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1157 if (instruction.OpCode.Code != Code.Ldfld)
1160 FieldReference field = (FieldReference) instruction.Operand;
1161 if (field.DeclaringType.FullName != type.FullName)
1164 property_mapping.Add (property, field);
1169 return property_mapping;
1172 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1174 if (!constructor.HasBody)
1177 // Custom handling for attributes with arguments which cannot be easily extracted
1178 var ca = attribute.ConstructorArguments;
1179 switch (constructor.DeclaringType.FullName) {
1180 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1181 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1182 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1183 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1185 mapping.Add ("Value", dca.Value);
1187 case "System.ComponentModel.BindableAttribute":
1191 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1192 mapping.Add ("Bindable", ca[0].Value);
1194 throw new NotImplementedException ();
1200 var field_mapping = CreateArgumentFieldMapping (constructor);
1201 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1203 foreach (var pair in property_mapping) {
1205 if (!field_mapping.TryGetValue (pair.Value, out argument))
1208 var ca_arg = ca [argument];
1209 if (ca_arg.Value is CustomAttributeArgument)
1210 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1212 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1216 static object GetArgumentValue (TypeReference reference, object value)
1218 var type = reference.Resolve ();
1223 if (IsFlaggedEnum (type))
1224 return GetFlaggedEnumValue (type, value);
1226 return GetEnumValue (type, value);
1232 static bool IsFlaggedEnum (TypeDefinition type)
1237 if (!type.HasCustomAttributes)
1240 foreach (CustomAttribute attribute in type.CustomAttributes)
1241 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1247 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1250 return GetFlaggedEnumValue (type, (ulong)value);
1252 long flags = Convert.ToInt64 (value);
1253 var signature = new StringBuilder ();
1255 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1256 FieldDefinition field = type.Fields [i];
1258 if (!field.HasConstant)
1261 long flag = Convert.ToInt64 (field.Constant);
1266 if ((flags & flag) == flag) {
1267 if (signature.Length != 0)
1268 signature.Append (", ");
1270 signature.Append (field.Name);
1275 return signature.ToString ();
1278 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1280 var signature = new StringBuilder ();
1282 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1283 FieldDefinition field = type.Fields [i];
1285 if (!field.HasConstant)
1288 ulong flag = Convert.ToUInt64 (field.Constant);
1293 if ((flags & flag) == flag) {
1294 if (signature.Length != 0)
1295 signature.Append (", ");
1297 signature.Append (field.Name);
1302 return signature.ToString ();
1305 static object GetEnumValue (TypeDefinition type, object value)
1307 foreach (FieldDefinition field in type.Fields) {
1308 if (!field.HasConstant)
1311 if (Comparer.Default.Compare (field.Constant, value) == 0)
1318 static bool SkipAttribute (CustomAttribute attribute)
1320 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1322 return !TypeHelper.IsPublic (attribute)
1323 || type_name.EndsWith ("TODOAttribute");
1326 public static void OutputAttributes (XmlDocument doc, XmlNode parent, ICustomAttributeProvider provider)
1328 if (!provider.HasCustomAttributes)
1331 AttributeData ad = new AttributeData (doc, parent, provider.CustomAttributes);
1336 static class Parameters {
1338 public static string GetSignature (IList<ParameterDefinition> infos)
1340 if (infos == null || infos.Count == 0)
1341 return string.Empty;
1343 var signature = new StringBuilder ();
1344 for (int i = 0; i < infos.Count; i++) {
1347 signature.Append (", ");
1349 ParameterDefinition info = infos [i];
1352 if ((info.Attributes & ParameterAttributes.In) != 0)
1354 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1357 modifier = string.Empty;
1359 if (modifier.Length > 0) {
1360 signature.Append (modifier);
1361 signature.Append (" ");
1364 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1367 return signature.ToString ();
1372 class TypeReferenceComparer : IComparer<TypeReference>
1374 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1376 public int Compare (TypeReference a, TypeReference b)
1378 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1382 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1386 class MemberReferenceComparer : IComparer
1388 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1390 public int Compare (object a, object b)
1392 MemberReference ma = (MemberReference) a;
1393 MemberReference mb = (MemberReference) b;
1394 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1398 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1400 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1402 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1404 int res = String.Compare (ma.Name, mb.Name);
1408 if (!ma.HasParameters && !mb.HasParameters)
1411 if (!ma.HasParameters)
1414 if (!mb.HasParameters)
1417 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1421 class MethodDefinitionComparer : IComparer
1423 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1425 public int Compare (object a, object b)
1427 MethodDefinition ma = (MethodDefinition) a;
1428 MethodDefinition mb = (MethodDefinition) b;
1429 int res = String.Compare (ma.Name, mb.Name);
1433 if (!ma.HasParameters && !mb.HasParameters)
1436 if (!ma.HasParameters)
1439 if (!mb.HasParameters)
1442 res = Compare (ma.Parameters, mb.Parameters);
1446 // operators can differ by only return type
1447 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1450 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1452 var res = pia.Count - pib.Count;
1456 string siga = Parameters.GetSignature (pia);
1457 string sigb = Parameters.GetSignature (pib);
1458 return String.Compare (siga, sigb);