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 StreamWriter outputStream = null;
97 if (!string.IsNullOrEmpty (output))
98 outputStream = new StreamWriter (output);
100 TextWriter outStream = outputStream ?? Console.Out;
101 var settings = new XmlWriterSettings ();
102 settings.Indent = true;
103 var textWriter = XmlWriter.Create (outStream, settings);
104 var writer = new WellFormedXmlWriter (textWriter);
105 writer.WriteStartDocument ();
106 acoll.Writer = writer;
108 writer.WriteEndDocument ();
111 if (outputStream != null)
112 outputStream.Dispose ();
117 internal static bool AbiMode { get; private set; }
118 internal static bool FollowForwarders { get; private set; }
123 public static string CleanupTypeName (TypeReference type)
125 return CleanupTypeName (type.FullName);
128 public static string CleanupTypeName (string t)
130 return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
134 class AssemblyCollection
137 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
139 public AssemblyCollection ()
143 public bool Add (string name)
145 AssemblyDefinition ass = LoadAssembly (name);
147 Console.Error.WriteLine ("Cannot load assembly file " + name);
151 assemblies.Add (ass);
155 public void DoOutput ()
158 throw new InvalidOperationException ("Document not set");
160 writer.WriteStartElement ("assemblies");
161 foreach (AssemblyDefinition a in assemblies) {
162 AssemblyData data = new AssemblyData (writer, a);
165 writer.WriteEndElement ();
168 public XmlWriter Writer {
169 set { writer = value; }
172 AssemblyDefinition LoadAssembly (string assembly)
175 if (File.Exists (assembly))
176 return TypeHelper.Resolver.ResolveFile (assembly);
178 return TypeHelper.Resolver.Resolve (assembly);
179 } catch (Exception e) {
180 Console.WriteLine (e);
186 abstract class BaseData
188 protected XmlWriter writer;
190 protected BaseData (XmlWriter writer)
192 this.writer = writer;
195 public abstract void DoOutput ();
197 protected void AddAttribute (string name, string value)
199 writer.WriteAttributeString (name, value);
203 class TypeForwardedToData : BaseData
205 AssemblyDefinition ass;
207 public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass)
213 public override void DoOutput ()
215 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
217 if (((uint)type.Attributes & 0x200000u) == 0)
220 writer.WriteStartElement ("attribute");
221 AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName);
222 writer.WriteStartElement ("properties");
223 writer.WriteStartElement ("property");
224 AddAttribute ("name", "Destination");
225 AddAttribute ("value", Utils.CleanupTypeName (type.FullName));
226 writer.WriteEndElement (); // properties
227 writer.WriteEndElement (); // properties
228 writer.WriteEndElement (); // attribute
232 public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass)
234 TypeForwardedToData tftd = new TypeForwardedToData (writer, ass);
239 class AssemblyData : BaseData
241 AssemblyDefinition ass;
243 public AssemblyData (XmlWriter writer, AssemblyDefinition ass)
249 public override void DoOutput ()
252 throw new InvalidOperationException ("Document not set");
254 writer.WriteStartElement ("assembly");
255 AssemblyNameDefinition aname = ass.Name;
256 AddAttribute ("name", aname.Name);
257 AddAttribute ("version", aname.Version.ToString ());
259 AttributeData.OutputAttributes (writer, ass);
261 var types = new List<TypeDefinition> ();
262 if (ass.MainModule.Types != null) {
263 types.AddRange (ass.MainModule.Types);
266 if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
267 foreach (var t in ass.MainModule.ExportedTypes) {
268 var forwarded = t.Resolve ();
269 if (forwarded == null) {
270 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
272 types.Add (forwarded);
276 if (types.Count == 0) {
277 writer.WriteEndElement (); // assembly
281 types.Sort (TypeReferenceComparer.Default);
283 writer.WriteStartElement ("namespaces");
285 string current_namespace = "$%&$&";
286 bool in_namespace = false;
287 foreach (TypeDefinition t in types) {
288 if (string.IsNullOrEmpty (t.Namespace))
291 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
294 if (t.DeclaringType != null)
295 continue; // enforce !nested
297 if (t.Namespace != current_namespace) {
298 current_namespace = t.Namespace;
300 writer.WriteEndElement (); // classes
301 writer.WriteEndElement (); // namespace
305 writer.WriteStartElement ("namespace");
306 AddAttribute ("name", current_namespace);
307 writer.WriteStartElement ("classes");
310 TypeData bd = new TypeData (writer, t);
316 writer.WriteEndElement (); // classes
317 writer.WriteEndElement (); // namespace
320 writer.WriteEndElement (); // namespaces
322 writer.WriteEndElement (); // assembly
326 abstract class MemberData : BaseData
328 MemberReference [] members;
330 public MemberData (XmlWriter writer, MemberReference [] members)
333 this.members = members;
336 protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
341 public override void DoOutput ()
343 writer.WriteStartElement (ParentTag);
345 foreach (MemberReference member in members) {
346 writer.WriteStartElement (Tag);
347 AddAttribute ("name", GetName (member));
348 if (!NoMemberAttributes)
349 AddAttribute ("attrib", GetMemberAttributes (member));
350 AddExtraAttributes (member);
352 AttributeData.OutputAttributes (writer, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member));
354 AddExtraData (member);
355 writer.WriteEndElement (); // Tag
358 writer.WriteEndElement (); // ParentTag
361 protected virtual void AddExtraData (MemberReference memberDefenition)
365 protected virtual void AddExtraAttributes (MemberReference memberDefinition)
369 protected virtual string GetName (MemberReference memberDefenition)
374 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
379 public virtual bool NoMemberAttributes {
380 get { return false; }
384 public virtual string ParentTag {
385 get { return "NoPARENTTAG"; }
388 public virtual string Tag {
389 get { return "NoTAG"; }
392 public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider)
394 if (provider.GenericParameters.Count == 0)
397 var gparameters = provider.GenericParameters;
399 writer.WriteStartElement ("generic-parameters");
401 foreach (GenericParameter gp in gparameters) {
402 writer.WriteStartElement ("generic-parameter");
403 writer.WriteAttributeString ("name", gp.Name);
404 writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ());
406 AttributeData.OutputAttributes (writer, gp);
408 var constraints = gp.Constraints;
409 if (constraints.Count == 0) {
410 writer.WriteEndElement (); // generic-parameter
414 writer.WriteStartElement ("generic-parameter-constraints");
416 foreach (TypeReference constraint in constraints) {
417 writer.WriteStartElement ("generic-parameter-constraint");
418 writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint));
419 writer.WriteEndElement (); // generic-parameter-constraint
422 writer.WriteEndElement (); // generic-parameter-constraints
424 writer.WriteEndElement (); // generic-parameter
427 writer.WriteEndElement (); // generic-parameters
431 class TypeData : MemberData
435 public TypeData (XmlWriter writer, TypeDefinition type)
436 : base (writer, null)
440 public override void DoOutput ()
443 throw new InvalidOperationException ("Document not set");
445 writer.WriteStartElement ("class");
446 AddAttribute ("name", type.Name);
447 string classType = GetClassType (type);
448 AddAttribute ("type", classType);
450 if (type.BaseType != null)
451 AddAttribute ("base", Utils.CleanupTypeName (type.BaseType));
454 AddAttribute ("sealed", "true");
457 AddAttribute ("abstract", "true");
459 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
460 AddAttribute ("serializable", "true");
462 string charSet = GetCharSet (type);
463 AddAttribute ("charset", charSet);
465 string layout = GetLayout (type);
467 AddAttribute ("layout", layout);
469 if (type.PackingSize >= 0) {
470 AddAttribute ("pack", type.PackingSize.ToString ());
473 if (type.ClassSize >= 0) {
474 AddAttribute ("size", type.ClassSize.ToString ());
478 var value_type = GetEnumValueField (type);
479 if (value_type == null)
480 throw new NotSupportedException ();
482 AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType));
485 AttributeData.OutputAttributes (writer, type);
487 var ifaces = TypeHelper.GetInterfaces (type).
488 Where ((iface) => TypeHelper.IsPublic (iface)). // we're only interested in public interfaces
489 OrderBy (s => s.FullName, StringComparer.Ordinal);
492 writer.WriteStartElement ("interfaces");
493 foreach (TypeReference iface in ifaces) {
494 writer.WriteStartElement ("interface");
495 AddAttribute ("name", Utils.CleanupTypeName (iface));
496 writer.WriteEndElement (); // interface
498 writer.WriteEndElement (); // interfaces
501 MemberData.OutputGenericParameters (writer, type);
503 ArrayList members = new ArrayList ();
505 FieldDefinition [] fields = GetFields (type);
506 if (fields.Length > 0) {
507 Array.Sort (fields, MemberReferenceComparer.Default);
508 FieldData fd = new FieldData (writer, fields);
512 if (!Driver.AbiMode) {
514 MethodDefinition [] ctors = GetConstructors (type);
515 if (ctors.Length > 0) {
516 Array.Sort (ctors, MethodDefinitionComparer.Default);
517 members.Add (new ConstructorData (writer, ctors));
520 PropertyDefinition[] properties = GetProperties (type);
521 if (properties.Length > 0) {
522 Array.Sort (properties, PropertyDefinitionComparer.Default);
523 members.Add (new PropertyData (writer, properties));
526 EventDefinition [] events = GetEvents (type);
527 if (events.Length > 0) {
528 Array.Sort (events, MemberReferenceComparer.Default);
529 members.Add (new EventData (writer, events));
532 MethodDefinition [] methods = GetMethods (type);
533 if (methods.Length > 0) {
534 Array.Sort (methods, MethodDefinitionComparer.Default);
535 members.Add (new MethodData (writer, methods));
539 foreach (MemberData md in members)
542 var nested = type.NestedTypes;
543 //remove non public(familiy) and nested in second degree
544 for (int i = nested.Count - 1; i >= 0; i--) {
545 TypeDefinition t = nested [i];
546 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
547 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
548 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
550 if (t.DeclaringType == type)
551 continue; // not nested of nested
557 if (nested.Count > 0) {
558 var nestedArray = nested.ToArray ();
559 Array.Sort (nestedArray, TypeReferenceComparer.Default);
561 writer.WriteStartElement ("classes");
562 foreach (TypeDefinition t in nestedArray) {
563 TypeData td = new TypeData (writer, t);
566 writer.WriteEndElement (); // classes
569 writer.WriteEndElement (); // class
572 static FieldReference GetEnumValueField (TypeDefinition type)
574 foreach (FieldDefinition field in type.Fields)
575 if (field.IsSpecialName && field.Name == "value__")
581 protected override string GetMemberAttributes (MemberReference member)
584 throw new InvalidOperationException ("odd");
586 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
589 public static bool MustDocumentMethod (MethodDefinition method) {
591 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
592 return maskedAccess == MethodAttributes.Public
593 || maskedAccess == MethodAttributes.Family
594 || maskedAccess == MethodAttributes.FamORAssem;
597 static string GetClassType (TypeDefinition t)
608 if (TypeHelper.IsDelegate(t))
617 static string GetCharSet (TypeDefinition type)
619 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
620 if (maskedStringFormat == TypeAttributes.AnsiClass)
621 return CharSet.Ansi.ToString ();
623 if (maskedStringFormat == TypeAttributes.AutoClass)
624 return CharSet.Auto.ToString ();
626 if (maskedStringFormat == TypeAttributes.UnicodeClass)
627 return CharSet.Unicode.ToString ();
629 return CharSet.None.ToString ();
632 static string GetLayout (TypeDefinition type)
634 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
635 if (maskedLayout == TypeAttributes.AutoLayout)
636 return LayoutKind.Auto.ToString ();
638 if (maskedLayout == TypeAttributes.ExplicitLayout)
639 return LayoutKind.Explicit.ToString ();
641 if (maskedLayout == TypeAttributes.SequentialLayout)
642 return LayoutKind.Sequential.ToString ();
647 FieldDefinition [] GetFields (TypeDefinition type) {
648 ArrayList list = new ArrayList ();
650 var fields = type.Fields;
651 foreach (FieldDefinition field in fields) {
652 if (field.IsSpecialName)
655 if (Driver.AbiMode && field.IsStatic)
658 // we're only interested in public or protected members
659 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
660 if (Driver.AbiMode && !field.IsNotSerialized) {
663 if (maskedVisibility == FieldAttributes.Public
664 || maskedVisibility == FieldAttributes.Family
665 || maskedVisibility == FieldAttributes.FamORAssem) {
671 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
675 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
676 ArrayList list = new ArrayList ();
678 var properties = type.Properties;//type.GetProperties (flags);
679 foreach (PropertyDefinition property in properties) {
680 MethodDefinition getMethod = property.GetMethod;
681 MethodDefinition setMethod = property.SetMethod;
683 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
684 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
686 // if neither the getter or setter should be documented, then
688 if (hasGetter || hasSetter) {
693 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
696 private MethodDefinition[] GetMethods (TypeDefinition type)
698 ArrayList list = new ArrayList ();
700 var methods = type.Methods;//type.GetMethods (flags);
701 foreach (MethodDefinition method in methods) {
702 if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
705 // we're only interested in public or protected members
706 if (!MustDocumentMethod(method))
709 if (IsFinalizer (method)) {
710 string name = method.DeclaringType.Name;
711 int arity = name.IndexOf ('`');
713 name = name.Substring (0, arity);
715 method.Name = "~" + name;
721 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
724 static bool IsFinalizer (MethodDefinition method)
726 if (method.Name != "Finalize")
729 if (!method.IsVirtual)
732 if (method.Parameters.Count != 0)
738 private MethodDefinition [] GetConstructors (TypeDefinition type)
740 ArrayList list = new ArrayList ();
742 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
743 foreach (MethodDefinition constructor in ctors) {
744 // we're only interested in public or protected members
745 if (!MustDocumentMethod(constructor))
748 list.Add (constructor);
751 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
754 private EventDefinition[] GetEvents (TypeDefinition type)
756 ArrayList list = new ArrayList ();
758 var events = type.Events;//type.GetEvents (flags);
759 foreach (EventDefinition eventDef in events) {
760 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
762 if (addMethod == null || !MustDocumentMethod (addMethod))
768 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
772 class FieldData : MemberData
774 public FieldData (XmlWriter writer, FieldDefinition [] members)
775 : base (writer, members)
779 protected override string GetName (MemberReference memberDefenition)
781 FieldDefinition field = (FieldDefinition) memberDefenition;
785 protected override string GetMemberAttributes (MemberReference memberDefenition)
787 FieldDefinition field = (FieldDefinition) memberDefenition;
788 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
791 protected override void AddExtraAttributes (MemberReference memberDefinition)
793 base.AddExtraAttributes (memberDefinition);
795 FieldDefinition field = (FieldDefinition) memberDefinition;
796 AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
798 if (field.IsLiteral) {
799 object value = field.Constant;//object value = field.GetValue (null);
800 string stringValue = null;
801 //if (value is Enum) {
802 // // FIXME: when Mono bug #60090 has been
803 // // fixed, we should just be able to use
804 // // Convert.ToString
805 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
808 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
811 if (stringValue != null)
812 AddAttribute ("value", stringValue);
816 public override string ParentTag {
817 get { return "fields"; }
820 public override string Tag {
821 get { return "field"; }
825 class PropertyData : MemberData
827 public PropertyData (XmlWriter writer, PropertyDefinition [] members)
828 : base (writer, members)
832 protected override string GetName (MemberReference memberDefenition)
834 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
838 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
840 MethodDefinition _get = prop.GetMethod;
841 MethodDefinition _set = prop.SetMethod;
842 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
843 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
844 haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
845 MethodDefinition [] methods;
847 if (haveGet && haveSet) {
848 methods = new MethodDefinition [] { _get, _set };
849 } else if (haveGet) {
850 methods = new MethodDefinition [] { _get };
851 } else if (haveSet) {
852 methods = new MethodDefinition [] { _set };
861 protected override void AddExtraAttributes (MemberReference memberDefinition)
863 base.AddExtraAttributes (memberDefinition);
865 PropertyDefinition prop = (PropertyDefinition) memberDefinition;
866 AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
869 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
871 if (methods != null && haveParameters) {
872 string parms = Parameters.GetSignature (methods [0].Parameters);
873 if (!string.IsNullOrEmpty (parms))
874 AddAttribute ("params", parms);
879 protected override void AddExtraData (MemberReference memberDefenition)
881 base.AddExtraData (memberDefenition);
884 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
889 MethodData data = new MethodData (writer, methods);
890 //data.NoMemberAttributes = true;
894 protected override string GetMemberAttributes (MemberReference memberDefenition)
896 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
897 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
900 public override string ParentTag {
901 get { return "properties"; }
904 public override string Tag {
905 get { return "property"; }
909 class EventData : MemberData
911 public EventData (XmlWriter writer, EventDefinition [] members)
912 : base (writer, members)
916 protected override string GetName (MemberReference memberDefenition)
918 EventDefinition evt = (EventDefinition) memberDefenition;
922 protected override string GetMemberAttributes (MemberReference memberDefenition)
924 EventDefinition evt = (EventDefinition) memberDefenition;
925 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
928 protected override void AddExtraAttributes (MemberReference memberDefinition)
930 base.AddExtraAttributes (memberDefinition);
932 EventDefinition evt = (EventDefinition) memberDefinition;
933 AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
936 public override string ParentTag {
937 get { return "events"; }
940 public override string Tag {
941 get { return "event"; }
945 class MethodData : MemberData
949 public MethodData (XmlWriter writer, MethodDefinition [] members)
950 : base (writer, members)
954 protected override string GetName (MemberReference memberDefenition)
956 MethodDefinition method = (MethodDefinition) memberDefenition;
957 string name = method.Name;
958 string parms = Parameters.GetSignature (method.Parameters);
960 return string.Format ("{0}({1})", name, parms);
963 protected override string GetMemberAttributes (MemberReference memberDefenition)
965 MethodDefinition method = (MethodDefinition) memberDefenition;
966 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
969 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
971 var mbase = (MethodDefinition) member;
972 return mbase.MethodReturnType;
975 protected override void AddExtraAttributes (MemberReference memberDefinition)
977 base.AddExtraAttributes (memberDefinition);
979 if (!(memberDefinition is MethodDefinition))
982 MethodDefinition mbase = (MethodDefinition) memberDefinition;
984 if (mbase.IsAbstract)
985 AddAttribute ("abstract", "true");
987 AddAttribute ("virtual", "true");
988 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
989 AddAttribute ("sealed", "true");
991 AddAttribute ("static", "true");
992 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
993 if (rettype != "System.Void" || !mbase.IsConstructor)
994 AddAttribute ("returntype", (rettype));
996 // if (mbase.MethodReturnType.HasCustomAttributes)
997 // AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
1000 protected override void AddExtraData (MemberReference memberDefenition)
1002 base.AddExtraData (memberDefenition);
1004 if (!(memberDefenition is MethodDefinition))
1007 MethodDefinition mbase = (MethodDefinition) memberDefenition;
1009 ParameterData parms = new ParameterData (writer, mbase.Parameters);
1012 MemberData.OutputGenericParameters (writer, mbase);
1015 public override bool NoMemberAttributes {
1016 get { return noAtts; }
1017 set { noAtts = value; }
1020 public override string ParentTag {
1021 get { return "methods"; }
1024 public override string Tag {
1025 get { return "method"; }
1029 class ConstructorData : MethodData
1031 public ConstructorData (XmlWriter writer, MethodDefinition [] members)
1032 : base (writer, members)
1036 public override string ParentTag {
1037 get { return "constructors"; }
1040 public override string Tag {
1041 get { return "constructor"; }
1045 class ParameterData : BaseData
1047 private IList<ParameterDefinition> parameters;
1049 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters)
1052 this.parameters = parameters;
1055 public override void DoOutput ()
1057 writer.WriteStartElement ("parameters");
1058 foreach (ParameterDefinition parameter in parameters) {
1059 writer.WriteStartElement ("parameter");
1060 AddAttribute ("name", parameter.Name);
1061 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1062 AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
1064 string direction = "in";
1066 if (parameter.ParameterType is ByReferenceType)
1067 direction = parameter.IsOut ? "out" : "ref";
1069 TypeReference t = parameter.ParameterType;
1070 AddAttribute ("type", Utils.CleanupTypeName (t));
1072 if (parameter.IsOptional) {
1073 AddAttribute ("optional", "true");
1074 if (parameter.HasConstant)
1075 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1078 if (direction != "in")
1079 AddAttribute ("direction", direction);
1081 AttributeData.OutputAttributes (writer, parameter);
1082 writer.WriteEndElement (); // parameter
1084 writer.WriteEndElement (); // parameters
1088 class AttributeData : BaseData
1090 IList<ICustomAttributeProvider> providers;
1092 AttributeData (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1095 this.providers = providers;
1098 public override void DoOutput ()
1101 throw new InvalidOperationException ("Document not set");
1103 if (providers == null || providers.Count == 0)
1106 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1109 writer.WriteStartElement ("attributes");
1111 foreach (var provider in providers) {
1112 if (provider == null)
1115 if (!provider.HasCustomAttributes)
1119 var ass = provider as AssemblyDefinition;
1120 if (ass != null && !Driver.FollowForwarders)
1121 TypeForwardedToData.OutputForwarders (writer, ass);
1123 foreach (var att in provider.CustomAttributes.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) {
1124 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1125 if (SkipAttribute (att))
1128 writer.WriteStartElement ("attribute");
1129 AddAttribute ("name", attName);
1131 var attribute_mapping = CreateAttributeMapping (att).Where ((kvp) => kvp.Key != "TypeId");
1133 if (attribute_mapping.Any ()) {
1134 writer.WriteStartElement ("properties");
1135 foreach (var kvp in attribute_mapping) {
1136 string name = kvp.Key;
1137 object o = kvp.Value;
1139 writer.WriteStartElement ("property");
1140 AddAttribute ("name", name);
1143 AddAttribute ("value", "null");
1145 string value = o.ToString ();
1146 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1147 value = value.ToUpper ();
1148 AddAttribute ("value", value);
1151 writer.WriteEndElement (); // property
1153 writer.WriteEndElement (); // properties
1155 writer.WriteEndElement (); // attribute
1159 writer.WriteEndElement (); // attributes
1162 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1164 var mapping = new Dictionary<string, object> ();
1166 PopulateMapping (mapping, attribute);
1168 var constructor = attribute.Constructor.Resolve ();
1169 if (constructor == null || !constructor.HasParameters)
1172 PopulateMapping (mapping, constructor, attribute);
1177 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1179 if (!attribute.HasProperties)
1182 foreach (var named_argument in attribute.Properties) {
1183 var name = named_argument.Name;
1184 var arg = named_argument.Argument;
1186 if (arg.Value is CustomAttributeArgument)
1187 arg = (CustomAttributeArgument) arg.Value;
1189 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1193 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1195 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1197 int? argument = null;
1199 foreach (Instruction instruction in constructor.Body.Instructions) {
1200 switch (instruction.OpCode.Code) {
1212 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1216 FieldReference field = (FieldReference) instruction.Operand;
1217 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1220 if (!argument.HasValue)
1223 if (!field_mapping.ContainsKey (field))
1224 field_mapping.Add (field, (int) argument - 1);
1231 return field_mapping;
1234 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1236 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1238 foreach (PropertyDefinition property in type.Properties) {
1239 if (property.GetMethod == null)
1241 if (!property.GetMethod.HasBody)
1244 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1245 if (instruction.OpCode.Code != Code.Ldfld)
1248 FieldReference field = (FieldReference) instruction.Operand;
1249 if (field.DeclaringType.FullName != type.FullName)
1252 property_mapping.Add (property, field);
1257 return property_mapping;
1260 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1262 if (!constructor.HasBody)
1265 // Custom handling for attributes with arguments which cannot be easily extracted
1266 var ca = attribute.ConstructorArguments;
1267 switch (constructor.DeclaringType.FullName) {
1268 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1269 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1270 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1271 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1273 mapping.Add ("Value", dca.Value);
1275 case "System.ComponentModel.BindableAttribute":
1279 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1280 mapping.Add ("Bindable", ca[0].Value);
1282 throw new NotImplementedException ();
1288 var field_mapping = CreateArgumentFieldMapping (constructor);
1289 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1291 foreach (var pair in property_mapping) {
1293 if (!field_mapping.TryGetValue (pair.Value, out argument))
1296 var ca_arg = ca [argument];
1297 if (ca_arg.Value is CustomAttributeArgument)
1298 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1300 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1304 static object GetArgumentValue (TypeReference reference, object value)
1306 var type = reference.Resolve ();
1311 if (IsFlaggedEnum (type))
1312 return GetFlaggedEnumValue (type, value);
1314 return GetEnumValue (type, value);
1320 static bool IsFlaggedEnum (TypeDefinition type)
1325 if (!type.HasCustomAttributes)
1328 foreach (CustomAttribute attribute in type.CustomAttributes)
1329 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1335 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1338 return GetFlaggedEnumValue (type, (ulong)value);
1340 long flags = Convert.ToInt64 (value);
1341 var signature = new StringBuilder ();
1343 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1344 FieldDefinition field = type.Fields [i];
1346 if (!field.HasConstant)
1349 long flag = Convert.ToInt64 (field.Constant);
1354 if ((flags & flag) == flag) {
1355 if (signature.Length != 0)
1356 signature.Append (", ");
1358 signature.Append (field.Name);
1363 return signature.ToString ();
1366 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1368 var signature = new StringBuilder ();
1370 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1371 FieldDefinition field = type.Fields [i];
1373 if (!field.HasConstant)
1376 ulong flag = Convert.ToUInt64 (field.Constant);
1381 if ((flags & flag) == flag) {
1382 if (signature.Length != 0)
1383 signature.Append (", ");
1385 signature.Append (field.Name);
1390 return signature.ToString ();
1393 static object GetEnumValue (TypeDefinition type, object value)
1395 foreach (FieldDefinition field in type.Fields) {
1396 if (!field.HasConstant)
1399 if (Comparer.Default.Compare (field.Constant, value) == 0)
1406 static bool SkipAttribute (CustomAttribute attribute)
1408 var type_name = Utils.CleanupTypeName (attribute.Constructor.DeclaringType);
1410 return !TypeHelper.IsPublic (attribute)
1411 || type_name.EndsWith ("TODOAttribute");
1414 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1416 AttributeData ad = new AttributeData (writer, providers);
1421 static class Parameters {
1423 public static string GetSignature (IList<ParameterDefinition> infos)
1425 if (infos == null || infos.Count == 0)
1426 return string.Empty;
1428 var signature = new StringBuilder ();
1429 for (int i = 0; i < infos.Count; i++) {
1432 signature.Append (", ");
1434 ParameterDefinition info = infos [i];
1437 if ((info.Attributes & ParameterAttributes.In) != 0)
1439 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1442 modifier = string.Empty;
1444 if (modifier.Length > 0) {
1445 signature.Append (modifier);
1446 signature.Append (" ");
1449 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1452 return signature.ToString ();
1457 class TypeReferenceComparer : IComparer<TypeReference>
1459 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1461 public int Compare (TypeReference a, TypeReference b)
1463 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1467 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1471 class MemberReferenceComparer : IComparer
1473 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1475 public int Compare (object a, object b)
1477 MemberReference ma = (MemberReference) a;
1478 MemberReference mb = (MemberReference) b;
1479 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1483 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1485 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1487 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1489 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1493 if (!ma.HasParameters && !mb.HasParameters)
1496 if (!ma.HasParameters)
1499 if (!mb.HasParameters)
1502 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1506 class MethodDefinitionComparer : IComparer
1508 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1510 public int Compare (object a, object b)
1512 MethodDefinition ma = (MethodDefinition) a;
1513 MethodDefinition mb = (MethodDefinition) b;
1514 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1518 if (!ma.HasParameters && !mb.HasParameters)
1521 if (!ma.HasParameters)
1524 if (!mb.HasParameters)
1527 res = Compare (ma.Parameters, mb.Parameters);
1531 // operators can differ by only return type
1532 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1535 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1537 var res = pia.Count - pib.Count;
1541 string siga = Parameters.GetSignature (pia);
1542 string sigb = Parameters.GetSignature (pib);
1543 return String.Compare (siga, sigb, StringComparison.Ordinal);