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 var attributes = provider.CustomAttributes.
1124 Where ((att) => !SkipAttribute (att)).
1125 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1127 foreach (var att in attributes) {
1128 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1130 writer.WriteStartElement ("attribute");
1131 AddAttribute ("name", attName);
1133 var attribute_mapping = CreateAttributeMapping (att).Where ((kvp) => kvp.Key != "TypeId");
1135 if (attribute_mapping.Any ()) {
1136 writer.WriteStartElement ("properties");
1137 foreach (var kvp in attribute_mapping) {
1138 string name = kvp.Key;
1139 object o = kvp.Value;
1141 writer.WriteStartElement ("property");
1142 AddAttribute ("name", name);
1145 AddAttribute ("value", "null");
1147 string value = o.ToString ();
1148 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1149 value = value.ToUpper ();
1150 AddAttribute ("value", value);
1153 writer.WriteEndElement (); // property
1155 writer.WriteEndElement (); // properties
1157 writer.WriteEndElement (); // attribute
1161 writer.WriteEndElement (); // attributes
1164 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1166 var mapping = new Dictionary<string, object> ();
1168 PopulateMapping (mapping, attribute);
1170 var constructor = attribute.Constructor.Resolve ();
1171 if (constructor == null || !constructor.HasParameters)
1174 PopulateMapping (mapping, constructor, attribute);
1179 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1181 if (!attribute.HasProperties)
1184 foreach (var named_argument in attribute.Properties) {
1185 var name = named_argument.Name;
1186 var arg = named_argument.Argument;
1188 if (arg.Value is CustomAttributeArgument)
1189 arg = (CustomAttributeArgument) arg.Value;
1191 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1195 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1197 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1199 int? argument = null;
1201 foreach (Instruction instruction in constructor.Body.Instructions) {
1202 switch (instruction.OpCode.Code) {
1214 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1218 FieldReference field = (FieldReference) instruction.Operand;
1219 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1222 if (!argument.HasValue)
1225 if (!field_mapping.ContainsKey (field))
1226 field_mapping.Add (field, (int) argument - 1);
1233 return field_mapping;
1236 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1238 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1240 foreach (PropertyDefinition property in type.Properties) {
1241 if (property.GetMethod == null)
1243 if (!property.GetMethod.HasBody)
1246 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1247 if (instruction.OpCode.Code != Code.Ldfld)
1250 FieldReference field = (FieldReference) instruction.Operand;
1251 if (field.DeclaringType.FullName != type.FullName)
1254 property_mapping.Add (property, field);
1259 return property_mapping;
1262 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1264 if (!constructor.HasBody)
1267 // Custom handling for attributes with arguments which cannot be easily extracted
1268 var ca = attribute.ConstructorArguments;
1269 switch (constructor.DeclaringType.FullName) {
1270 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1271 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1272 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1273 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1275 mapping.Add ("Value", dca.Value);
1277 case "System.ComponentModel.BindableAttribute":
1281 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1282 mapping.Add ("Bindable", ca[0].Value);
1284 throw new NotImplementedException ();
1290 var field_mapping = CreateArgumentFieldMapping (constructor);
1291 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1293 foreach (var pair in property_mapping) {
1295 if (!field_mapping.TryGetValue (pair.Value, out argument))
1298 var ca_arg = ca [argument];
1299 if (ca_arg.Value is CustomAttributeArgument)
1300 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1302 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1306 static object GetArgumentValue (TypeReference reference, object value)
1308 var type = reference.Resolve ();
1313 if (IsFlaggedEnum (type))
1314 return GetFlaggedEnumValue (type, value);
1316 return GetEnumValue (type, value);
1322 static bool IsFlaggedEnum (TypeDefinition type)
1327 if (!type.HasCustomAttributes)
1330 foreach (CustomAttribute attribute in type.CustomAttributes)
1331 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1337 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1340 return GetFlaggedEnumValue (type, (ulong)value);
1342 long flags = Convert.ToInt64 (value);
1343 var signature = new StringBuilder ();
1345 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1346 FieldDefinition field = type.Fields [i];
1348 if (!field.HasConstant)
1351 long flag = Convert.ToInt64 (field.Constant);
1356 if ((flags & flag) == flag) {
1357 if (signature.Length != 0)
1358 signature.Append (", ");
1360 signature.Append (field.Name);
1365 return signature.ToString ();
1368 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1370 var signature = new StringBuilder ();
1372 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1373 FieldDefinition field = type.Fields [i];
1375 if (!field.HasConstant)
1378 ulong flag = Convert.ToUInt64 (field.Constant);
1383 if ((flags & flag) == flag) {
1384 if (signature.Length != 0)
1385 signature.Append (", ");
1387 signature.Append (field.Name);
1392 return signature.ToString ();
1395 static object GetEnumValue (TypeDefinition type, object value)
1397 foreach (FieldDefinition field in type.Fields) {
1398 if (!field.HasConstant)
1401 if (Comparer.Default.Compare (field.Constant, value) == 0)
1408 static bool SkipAttribute (CustomAttribute attribute)
1410 if (!TypeHelper.IsPublic (attribute))
1413 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1416 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1418 AttributeData ad = new AttributeData (writer, providers);
1423 static class Parameters {
1425 public static string GetSignature (IList<ParameterDefinition> infos)
1427 if (infos == null || infos.Count == 0)
1428 return string.Empty;
1430 var signature = new StringBuilder ();
1431 for (int i = 0; i < infos.Count; i++) {
1434 signature.Append (", ");
1436 ParameterDefinition info = infos [i];
1439 if ((info.Attributes & ParameterAttributes.In) != 0)
1441 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1444 modifier = string.Empty;
1446 if (modifier.Length > 0) {
1447 signature.Append (modifier);
1448 signature.Append (" ");
1451 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1454 return signature.ToString ();
1459 class TypeReferenceComparer : IComparer<TypeReference>
1461 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1463 public int Compare (TypeReference a, TypeReference b)
1465 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1469 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1473 class MemberReferenceComparer : IComparer
1475 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1477 public int Compare (object a, object b)
1479 MemberReference ma = (MemberReference) a;
1480 MemberReference mb = (MemberReference) b;
1481 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1485 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1487 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1489 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1491 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1495 if (!ma.HasParameters && !mb.HasParameters)
1498 if (!ma.HasParameters)
1501 if (!mb.HasParameters)
1504 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1508 class MethodDefinitionComparer : IComparer
1510 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1512 public int Compare (object a, object b)
1514 MethodDefinition ma = (MethodDefinition) a;
1515 MethodDefinition mb = (MethodDefinition) b;
1516 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1520 if (!ma.HasParameters && !mb.HasParameters)
1523 if (!ma.HasParameters)
1526 if (!mb.HasParameters)
1529 res = Compare (ma.Parameters, mb.Parameters);
1533 // operators can differ by only return type
1534 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1537 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1539 var res = pia.Count - pib.Count;
1543 string siga = Parameters.GetSignature (pia);
1544 string sigb = Parameters.GetSignature (pib);
1545 return String.Compare (siga, sigb, StringComparison.Ordinal);