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)
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) {
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"));
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"));
65 XmlDocument doc = new XmlDocument ();
69 var writer = new WellFormedXmlWriter (new XmlTextWriter (Console.Out) { Formatting = Formatting.Indented });
70 XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null);
71 doc.InsertBefore (decl, doc.DocumentElement);
76 internal static bool AbiMode { get; private set; }
81 public static string CleanupTypeName (TypeReference type)
83 return CleanupTypeName (type.FullName);
86 public static string CleanupTypeName (string t)
88 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
92 class AssemblyCollection
95 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
97 public AssemblyCollection ()
101 public bool Add (string name)
103 AssemblyDefinition ass = LoadAssembly (name);
105 Console.Error.WriteLine ("Cannot load assembly file " + name);
109 assemblies.Add (ass);
113 public void DoOutput ()
115 if (document == null)
116 throw new InvalidOperationException ("Document not set");
118 XmlNode nassemblies = document.CreateElement ("assemblies", null);
119 document.AppendChild (nassemblies);
120 foreach (AssemblyDefinition a in assemblies) {
121 AssemblyData data = new AssemblyData (document, nassemblies, a);
126 public XmlDocument Document {
127 set { document = value; }
130 AssemblyDefinition LoadAssembly (string assembly)
133 if (File.Exists (assembly))
134 return TypeHelper.Resolver.ResolveFile (assembly);
136 return TypeHelper.Resolver.Resolve (assembly);
137 } catch (Exception e) {
138 Console.WriteLine (e);
144 abstract class BaseData
146 protected XmlDocument document;
147 protected XmlNode parent;
149 protected BaseData (XmlDocument doc, XmlNode parent)
152 this.parent = parent;
155 public abstract void DoOutput ();
157 protected void AddAttribute (XmlNode node, string name, string value)
159 XmlAttribute attr = document.CreateAttribute (name);
161 node.Attributes.Append (attr);
165 class TypeForwardedToData : BaseData
167 AssemblyDefinition ass;
169 public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
170 : base (document, parent)
175 public override void DoOutput ()
177 XmlNode natts = parent.SelectSingleNode("attributes");
179 natts = document.CreateElement ("attributes", null);
180 parent.AppendChild (natts);
183 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
185 if (((uint)type.Attributes & 0x200000u) == 0)
188 XmlNode node = document.CreateElement ("attribute");
189 AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName);
190 XmlNode properties = node.AppendChild (document.CreateElement ("properties"));
191 XmlNode property = properties.AppendChild (document.CreateElement ("property"));
192 AddAttribute (property, "name", "Destination");
193 AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName));
194 natts.AppendChild (node);
198 public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
200 TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass);
205 class AssemblyData : BaseData
207 AssemblyDefinition ass;
209 public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass)
210 : base (document, parent)
215 public override void DoOutput ()
217 if (document == null)
218 throw new InvalidOperationException ("Document not set");
220 XmlNode nassembly = document.CreateElement ("assembly", null);
221 AssemblyNameDefinition aname = ass.Name;
222 AddAttribute (nassembly, "name", aname.Name);
223 AddAttribute (nassembly, "version", aname.Version.ToString ());
224 parent.AppendChild (nassembly);
225 TypeForwardedToData.OutputForwarders (document, nassembly, ass);
226 AttributeData.OutputAttributes (document, nassembly, ass.CustomAttributes);
227 var typesCollection = ass.MainModule.Types;
228 if (typesCollection == null || typesCollection.Count == 0)
230 object [] typesArray = new object [typesCollection.Count];
231 for (int i = 0; i < typesCollection.Count; i++) {
232 typesArray [i] = typesCollection [i];
234 Array.Sort (typesArray, TypeReferenceComparer.Default);
236 XmlNode nss = document.CreateElement ("namespaces", null);
237 nassembly.AppendChild (nss);
239 string current_namespace = "$%&$&";
241 XmlNode classes = null;
242 foreach (TypeDefinition t in typesArray) {
243 if (string.IsNullOrEmpty (t.Namespace))
246 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
249 if (t.DeclaringType != null)
250 continue; // enforce !nested
252 if (t.Namespace != current_namespace) {
253 current_namespace = t.Namespace;
254 ns = document.CreateElement ("namespace", null);
255 AddAttribute (ns, "name", current_namespace);
256 nss.AppendChild (ns);
257 classes = document.CreateElement ("classes", null);
258 ns.AppendChild (classes);
261 TypeData bd = new TypeData (document, classes, t);
267 abstract class MemberData : BaseData
269 MemberReference [] members;
271 public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members)
272 : base (document, parent)
274 this.members = members;
277 public override void DoOutput ()
279 XmlNode mclass = document.CreateElement (ParentTag, null);
280 parent.AppendChild (mclass);
282 foreach (MemberReference member in members) {
283 XmlNode mnode = document.CreateElement (Tag, null);
284 mclass.AppendChild (mnode);
285 AddAttribute (mnode, "name", GetName (member));
286 if (!NoMemberAttributes)
287 AddAttribute (mnode, "attrib", GetMemberAttributes (member));
289 AttributeData.OutputAttributes (document, mnode, GetCustomAttributes (member));
291 AddExtraData (mnode, member);
296 protected abstract IList<CustomAttribute> GetCustomAttributes (MemberReference member);
298 protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition)
302 protected virtual string GetName (MemberReference memberDefenition)
307 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
312 public virtual bool NoMemberAttributes {
313 get { return false; }
317 public virtual string ParentTag {
318 get { return "NoPARENTTAG"; }
321 public virtual string Tag {
322 get { return "NoTAG"; }
325 public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider)
327 if (provider.GenericParameters.Count == 0)
330 var gparameters = provider.GenericParameters;
332 XmlElement ngeneric = document.CreateElement (string.Format ("generic-parameters"));
333 nclass.AppendChild (ngeneric);
335 foreach (GenericParameter gp in gparameters) {
336 XmlElement nparam = document.CreateElement (string.Format ("generic-parameter"));
337 nparam.SetAttribute ("name", gp.Name);
338 nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ());
340 AttributeData.OutputAttributes (document, nparam, gp.CustomAttributes);
342 ngeneric.AppendChild (nparam);
344 var constraints = gp.Constraints;
345 if (constraints.Count == 0)
348 XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints");
350 foreach (TypeReference constraint in constraints) {
351 XmlElement ncons = document.CreateElement ("generic-parameter-constraint");
352 ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint));
353 nconstraint.AppendChild (ncons);
356 nparam.AppendChild (nconstraint);
361 class TypeData : MemberData
365 public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type)
366 : base (document, parent, null)
371 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
372 return ((TypeDefinition) member).CustomAttributes;
375 public override void DoOutput ()
377 if (document == null)
378 throw new InvalidOperationException ("Document not set");
380 XmlNode nclass = document.CreateElement ("class", null);
381 AddAttribute (nclass, "name", type.Name);
382 string classType = GetClassType (type);
383 AddAttribute (nclass, "type", classType);
385 if (type.BaseType != null)
386 AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType));
389 AddAttribute (nclass, "sealed", "true");
392 AddAttribute (nclass, "abstract", "true");
394 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
395 AddAttribute (nclass, "serializable", "true");
397 string charSet = GetCharSet (type);
398 AddAttribute (nclass, "charset", charSet);
400 string layout = GetLayout (type);
402 AddAttribute (nclass, "layout", layout);
404 if (type.PackingSize >= 0) {
405 AddAttribute (nclass, "pack", type.PackingSize.ToString ());
408 if (type.ClassSize >= 0) {
409 AddAttribute (nclass, "size", type.ClassSize.ToString ());
412 parent.AppendChild (nclass);
414 AttributeData.OutputAttributes (document, nclass, GetCustomAttributes(type));
416 XmlNode ifaces = null;
418 foreach (TypeReference iface in TypeHelper.GetInterfaces (type)) {
419 if (!TypeHelper.IsPublic (iface))
420 // we're only interested in public interfaces
423 if (ifaces == null) {
424 ifaces = document.CreateElement ("interfaces", null);
425 nclass.AppendChild (ifaces);
428 XmlNode iface_node = document.CreateElement ("interface", null);
429 AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface));
430 ifaces.AppendChild (iface_node);
433 MemberData.OutputGenericParameters (document, nclass, type);
435 ArrayList members = new ArrayList ();
437 FieldDefinition [] fields = GetFields (type);
438 if (fields.Length > 0) {
439 Array.Sort (fields, MemberReferenceComparer.Default);
440 FieldData fd = new FieldData (document, nclass, fields);
445 var value_type = GetEnumValueField (type);
446 if (value_type == null)
447 throw new NotSupportedException ();
449 AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType));
452 if (!Driver.AbiMode) {
454 MethodDefinition [] ctors = GetConstructors (type);
455 if (ctors.Length > 0) {
456 Array.Sort (ctors, MemberReferenceComparer.Default);
457 members.Add (new ConstructorData (document, nclass, ctors));
460 PropertyDefinition[] properties = GetProperties (type);
461 if (properties.Length > 0) {
462 Array.Sort (properties, MemberReferenceComparer.Default);
463 members.Add (new PropertyData (document, nclass, properties));
466 EventDefinition [] events = GetEvents (type);
467 if (events.Length > 0) {
468 Array.Sort (events, MemberReferenceComparer.Default);
469 members.Add (new EventData (document, nclass, events));
472 MethodDefinition [] methods = GetMethods (type);
473 if (methods.Length > 0) {
474 Array.Sort (methods, MemberReferenceComparer.Default);
475 members.Add (new MethodData (document, nclass, methods));
479 foreach (MemberData md in members)
482 var nested = type.NestedTypes;
483 //remove non public(familiy) and nested in second degree
484 for (int i = nested.Count - 1; i >= 0; i--) {
485 TypeDefinition t = nested [i];
486 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
487 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
488 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
490 if (t.DeclaringType == type)
491 continue; // not nested of nested
498 if (nested.Count > 0) {
499 XmlNode classes = document.CreateElement ("classes", null);
500 nclass.AppendChild (classes);
501 foreach (TypeDefinition t in nested) {
502 TypeData td = new TypeData (document, classes, t);
508 static FieldReference GetEnumValueField (TypeDefinition type)
510 foreach (FieldDefinition field in type.Fields)
511 if (field.IsSpecialName && field.Name == "value__")
517 protected override string GetMemberAttributes (MemberReference member)
520 throw new InvalidOperationException ("odd");
522 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
525 public static bool MustDocumentMethod (MethodDefinition method) {
527 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
528 return maskedAccess == MethodAttributes.Public
529 || maskedAccess == MethodAttributes.Family
530 || maskedAccess == MethodAttributes.FamORAssem;
533 static string GetClassType (TypeDefinition t)
544 if (TypeHelper.IsDelegate(t))
550 static string GetCharSet (TypeDefinition type)
552 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
553 if (maskedStringFormat == TypeAttributes.AnsiClass)
554 return CharSet.Ansi.ToString ();
556 if (maskedStringFormat == TypeAttributes.AutoClass)
557 return CharSet.Auto.ToString ();
559 if (maskedStringFormat == TypeAttributes.UnicodeClass)
560 return CharSet.Unicode.ToString ();
562 return CharSet.None.ToString ();
565 static string GetLayout (TypeDefinition type)
567 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
568 if (maskedLayout == TypeAttributes.AutoLayout)
569 return LayoutKind.Auto.ToString ();
571 if (maskedLayout == TypeAttributes.ExplicitLayout)
572 return LayoutKind.Explicit.ToString ();
574 if (maskedLayout == TypeAttributes.SequentialLayout)
575 return LayoutKind.Sequential.ToString ();
580 FieldDefinition [] GetFields (TypeDefinition type) {
581 ArrayList list = new ArrayList ();
583 var fields = type.Fields;
584 foreach (FieldDefinition field in fields) {
585 if (field.IsSpecialName)
588 if (Driver.AbiMode && field.IsStatic)
591 // we're only interested in public or protected members
592 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
593 if (Driver.AbiMode && !field.IsNotSerialized) {
596 if (maskedVisibility == FieldAttributes.Public
597 || maskedVisibility == FieldAttributes.Family
598 || maskedVisibility == FieldAttributes.FamORAssem) {
604 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
608 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
609 ArrayList list = new ArrayList ();
611 var properties = type.Properties;//type.GetProperties (flags);
612 foreach (PropertyDefinition property in properties) {
613 MethodDefinition getMethod = property.GetMethod;
614 MethodDefinition setMethod = property.SetMethod;
616 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
617 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
619 // if neither the getter or setter should be documented, then
621 if (hasGetter || hasSetter) {
626 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
629 private MethodDefinition[] GetMethods (TypeDefinition type)
631 ArrayList list = new ArrayList ();
633 var methods = type.Methods;//type.GetMethods (flags);
634 foreach (MethodDefinition method in methods) {
635 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
638 // we're only interested in public or protected members
639 if (!MustDocumentMethod(method))
642 if (IsFinalizer (method)) {
643 string name = method.DeclaringType.Name;
644 int arity = name.IndexOf ('`');
646 name = name.Substring (0, arity);
648 method.Name = "~" + name;
654 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
657 static bool IsFinalizer (MethodDefinition method)
659 if (method.Name != "Finalize")
662 if (!method.IsVirtual)
665 if (method.Parameters.Count != 0)
671 private MethodDefinition [] GetConstructors (TypeDefinition type)
673 ArrayList list = new ArrayList ();
675 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
676 foreach (MethodDefinition constructor in ctors) {
677 // we're only interested in public or protected members
678 if (!MustDocumentMethod(constructor))
681 list.Add (constructor);
684 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
687 private EventDefinition[] GetEvents (TypeDefinition type)
689 ArrayList list = new ArrayList ();
691 var events = type.Events;//type.GetEvents (flags);
692 foreach (EventDefinition eventDef in events) {
693 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
695 if (addMethod == null || !MustDocumentMethod (addMethod))
701 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
705 class FieldData : MemberData
707 public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members)
708 : base (document, parent, members)
712 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
713 return ((FieldDefinition) member).CustomAttributes;
716 protected override string GetName (MemberReference memberDefenition)
718 FieldDefinition field = (FieldDefinition) memberDefenition;
722 protected override string GetMemberAttributes (MemberReference memberDefenition)
724 FieldDefinition field = (FieldDefinition) memberDefenition;
725 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
728 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
730 base.AddExtraData (p, memberDefenition);
731 FieldDefinition field = (FieldDefinition) memberDefenition;
732 AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType));
734 if (field.IsLiteral) {
735 object value = field.Constant;//object value = field.GetValue (null);
736 string stringValue = null;
737 //if (value is Enum) {
738 // // FIXME: when Mono bug #60090 has been
739 // // fixed, we should just be able to use
740 // // Convert.ToString
741 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
744 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
747 if (stringValue != null)
748 AddAttribute (p, "value", stringValue);
752 public override string ParentTag {
753 get { return "fields"; }
756 public override string Tag {
757 get { return "field"; }
761 class PropertyData : MemberData
763 public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members)
764 : base (document, parent, members)
768 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
769 return ((PropertyDefinition) member).CustomAttributes;
772 protected override string GetName (MemberReference memberDefenition)
774 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
778 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
780 base.AddExtraData (p, memberDefenition);
781 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
782 AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType));
783 MethodDefinition _get = prop.GetMethod;
784 MethodDefinition _set = prop.SetMethod;
785 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
786 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
787 MethodDefinition [] methods;
789 if (haveGet && haveSet) {
790 methods = new MethodDefinition [] { _get, _set };
791 } else if (haveGet) {
792 methods = new MethodDefinition [] { _get };
793 } else if (haveSet) {
794 methods = new MethodDefinition [] { _set };
800 if (haveGet || _set.Parameters.Count > 1) {
801 string parms = Parameters.GetSignature (methods [0].Parameters);
802 if (!string.IsNullOrEmpty (parms))
803 AddAttribute (p, "params", parms);
806 MethodData data = new MethodData (document, p, methods);
807 //data.NoMemberAttributes = true;
811 protected override string GetMemberAttributes (MemberReference memberDefenition)
813 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
814 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
817 public override string ParentTag {
818 get { return "properties"; }
821 public override string Tag {
822 get { return "property"; }
826 class EventData : MemberData
828 public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members)
829 : base (document, parent, members)
833 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
834 return ((EventDefinition) member).CustomAttributes;
837 protected override string GetName (MemberReference memberDefenition)
839 EventDefinition evt = (EventDefinition) memberDefenition;
843 protected override string GetMemberAttributes (MemberReference memberDefenition)
845 EventDefinition evt = (EventDefinition) memberDefenition;
846 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
849 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
851 base.AddExtraData (p, memberDefenition);
852 EventDefinition evt = (EventDefinition) memberDefenition;
853 AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType));
856 public override string ParentTag {
857 get { return "events"; }
860 public override string Tag {
861 get { return "event"; }
865 class MethodData : MemberData
869 public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
870 : base (document, parent, members)
874 protected override IList<CustomAttribute> GetCustomAttributes (MemberReference member) {
875 return ((MethodDefinition) member).CustomAttributes;
878 protected override string GetName (MemberReference memberDefenition)
880 MethodDefinition method = (MethodDefinition) memberDefenition;
881 string name = method.Name;
882 string parms = Parameters.GetSignature (method.Parameters);
884 return string.Format ("{0}({1})", name, parms);
887 protected override string GetMemberAttributes (MemberReference memberDefenition)
889 MethodDefinition method = (MethodDefinition) memberDefenition;
890 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
893 protected override void AddExtraData (XmlNode p, MemberReference memberDefenition)
895 base.AddExtraData (p, memberDefenition);
897 if (!(memberDefenition is MethodDefinition))
900 MethodDefinition mbase = (MethodDefinition) memberDefenition;
902 ParameterData parms = new ParameterData (document, p, mbase.Parameters);
905 if (mbase.IsAbstract)
906 AddAttribute (p, "abstract", "true");
908 AddAttribute (p, "virtual", "true");
910 AddAttribute (p, "static", "true");
912 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
913 if (rettype != "System.Void" || !mbase.IsConstructor)
914 AddAttribute (p, "returntype", (rettype));
916 AttributeData.OutputAttributes (document, p, mbase.MethodReturnType.CustomAttributes);
918 MemberData.OutputGenericParameters (document, p, mbase);
921 public override bool NoMemberAttributes {
922 get { return noAtts; }
923 set { noAtts = value; }
926 public override string ParentTag {
927 get { return "methods"; }
930 public override string Tag {
931 get { return "method"; }
935 class ConstructorData : MethodData
937 public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members)
938 : base (document, parent, members)
942 public override string ParentTag {
943 get { return "constructors"; }
946 public override string Tag {
947 get { return "constructor"; }
951 class ParameterData : BaseData
953 private IList<ParameterDefinition> parameters;
955 public ParameterData (XmlDocument document, XmlNode parent, IList<ParameterDefinition> parameters)
956 : base (document, parent)
958 this.parameters = parameters;
961 public override void DoOutput ()
963 XmlNode parametersNode = document.CreateElement ("parameters");
964 parent.AppendChild (parametersNode);
966 foreach (ParameterDefinition parameter in parameters) {
967 XmlNode paramNode = document.CreateElement ("parameter");
968 parametersNode.AppendChild (paramNode);
969 AddAttribute (paramNode, "name", parameter.Name);
970 AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
971 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
973 string direction = "in";
975 if (parameter.ParameterType is ByReferenceType)
976 direction = parameter.IsOut ? "out" : "ref";
978 TypeReference t = parameter.ParameterType;
979 AddAttribute (paramNode, "type", Utils.CleanupTypeName (t));
981 if (parameter.IsOptional) {
982 AddAttribute (paramNode, "optional", "true");
983 if (parameter.HasConstant)
984 AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
987 if (direction != "in")
988 AddAttribute (paramNode, "direction", direction);
990 AttributeData.OutputAttributes (document, paramNode, parameter.CustomAttributes);
995 class AttributeData : BaseData
997 IList<CustomAttribute> atts;
999 AttributeData (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1000 : base (doc, parent)
1005 public override void DoOutput ()
1007 if (document == null)
1008 throw new InvalidOperationException ("Document not set");
1010 if (atts == null || atts.Count == 0)
1013 XmlNode natts = parent.SelectSingleNode("attributes");
1014 if (natts == null) {
1015 natts = document.CreateElement ("attributes", null);
1016 parent.AppendChild (natts);
1019 for (int i = 0; i < atts.Count; ++i) {
1020 CustomAttribute att = atts [i];
1022 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1023 if (SkipAttribute (att))
1026 XmlNode node = document.CreateElement ("attribute");
1027 AddAttribute (node, "name", attName);
1029 XmlNode properties = null;
1031 Dictionary<string, object> attribute_mapping = CreateAttributeMapping (att);
1033 foreach (string name in attribute_mapping.Keys) {
1034 if (name == "TypeId")
1037 if (properties == null) {
1038 properties = node.AppendChild (document.CreateElement ("properties"));
1041 object o = attribute_mapping [name];
1043 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
1044 AddAttribute (n, "name", name);
1047 AddAttribute (n, "value", "null");
1050 string value = o.ToString ();
1051 if (attName.EndsWith ("GuidAttribute"))
1052 value = value.ToUpper ();
1053 AddAttribute (n, "value", value);
1056 natts.AppendChild (node);
1060 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1062 var mapping = new Dictionary<string, object> ();
1064 PopulateMapping (mapping, attribute);
1066 var constructor = attribute.Constructor.Resolve ();
1067 if (constructor == null || constructor.Parameters.Count == 0)
1070 PopulateMapping (mapping, constructor, attribute);
1075 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1077 foreach (var named_argument in attribute.Properties) {
1078 var name = named_argument.Name;
1080 mapping.Add (name, GetArgumentValue (named_argument.Argument.Type, named_argument.Argument.Value));
1084 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1086 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1088 int? argument = null;
1090 foreach (Instruction instruction in constructor.Body.Instructions) {
1091 switch (instruction.OpCode.Code) {
1103 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1107 FieldReference field = (FieldReference) instruction.Operand;
1108 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1111 if (!argument.HasValue)
1114 if (!field_mapping.ContainsKey (field))
1115 field_mapping.Add (field, (int) argument - 1);
1122 return field_mapping;
1125 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1127 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1129 foreach (PropertyDefinition property in type.Properties) {
1130 if (property.GetMethod == null)
1132 if (!property.GetMethod.HasBody)
1135 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1136 if (instruction.OpCode.Code != Code.Ldfld)
1139 FieldReference field = (FieldReference) instruction.Operand;
1140 if (field.DeclaringType.FullName != type.FullName)
1143 property_mapping.Add (property, field);
1148 return property_mapping;
1151 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1153 if (!constructor.HasBody)
1156 var field_mapping = CreateArgumentFieldMapping (constructor);
1157 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1159 foreach (var pair in property_mapping) {
1161 if (!field_mapping.TryGetValue (pair.Value, out argument))
1164 var ca_arg = attribute.ConstructorArguments [argument];
1165 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1169 static object GetArgumentValue (TypeReference reference, object value)
1171 var type = reference.Resolve ();
1176 if (IsFlaggedEnum (type))
1177 return GetFlaggedEnumValue (type, value);
1179 return GetEnumValue (type, value);
1185 static bool IsFlaggedEnum (TypeDefinition type)
1190 if (type.CustomAttributes.Count == 0)
1193 foreach (CustomAttribute attribute in type.CustomAttributes)
1194 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1200 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1202 long flags = Convert.ToInt64 (value);
1203 var signature = new StringBuilder ();
1205 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1206 FieldDefinition field = type.Fields [i];
1208 if (!field.HasConstant)
1211 long flag = Convert.ToInt64 (field.Constant);
1216 if ((flags & flag) == flag) {
1217 if (signature.Length != 0)
1218 signature.Append (", ");
1220 signature.Append (field.Name);
1225 return signature.ToString ();
1228 static object GetEnumValue (TypeDefinition type, object value)
1230 foreach (FieldDefinition field in type.Fields) {
1231 if (!field.HasConstant)
1234 if (Comparer.Default.Compare (field.Constant, value) == 0)
1241 static bool SkipAttribute (CustomAttribute attribute)
1243 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1245 return !TypeHelper.IsPublic (attribute)
1246 || type_name.EndsWith ("TODOAttribute");
1249 public static void OutputAttributes (XmlDocument doc, XmlNode parent, IList<CustomAttribute> attributes)
1251 AttributeData ad = new AttributeData (doc, parent, attributes);
1256 static class Parameters {
1258 public static string GetSignature (IList<ParameterDefinition> infos)
1260 if (infos == null || infos.Count == 0)
1263 var signature = new StringBuilder ();
1264 for (int i = 0; i < infos.Count; i++) {
1267 signature.Append (", ");
1269 ParameterDefinition info = infos [i];
1272 if ((info.Attributes & ParameterAttributes.In) != 0)
1274 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1277 modifier = string.Empty;
1279 if (modifier.Length > 0)
1280 signature.AppendFormat ("{0} ", modifier);
1282 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1285 return signature.ToString ();
1290 class TypeReferenceComparer : IComparer
1292 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1294 public int Compare (object a, object b)
1296 TypeReference ta = (TypeReference) a;
1297 TypeReference tb = (TypeReference) b;
1298 int result = String.Compare (ta.Namespace, tb.Namespace);
1302 return String.Compare (ta.Name, tb.Name);
1306 class MemberReferenceComparer : IComparer
1308 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1310 public int Compare (object a, object b)
1312 MemberReference ma = (MemberReference) a;
1313 MemberReference mb = (MemberReference) b;
1314 return String.Compare (ma.Name, mb.Name);
1318 class MethodDefinitionComparer : IComparer
1320 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1322 public int Compare (object a, object b)
1324 MethodDefinition ma = (MethodDefinition) a;
1325 MethodDefinition mb = (MethodDefinition) b;
1326 int res = String.Compare (ma.Name, mb.Name);
1330 IList<ParameterDefinition> pia = ma.Parameters ;
1331 IList<ParameterDefinition> pib = mb.Parameters;
1332 res = pia.Count - pib.Count;
1336 string siga = Parameters.GetSignature (pia);
1337 string sigb = Parameters.GetSignature (pib);
1338 return String.Compare (siga, sigb);