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; }
122 static char[] CharsToCleanup = new char[] { '<', '>', '/' };
124 public static string CleanupTypeName (TypeReference type)
126 return CleanupTypeName (type.FullName);
129 public static string CleanupTypeName (string t)
131 if (t.IndexOfAny (CharsToCleanup) == -1)
133 var sb = new StringBuilder (t.Length);
134 for (int i = 0; i < t.Length; i++) {
151 return sb.ToString ();
155 class AssemblyCollection
158 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
160 public AssemblyCollection ()
164 public bool Add (string name)
166 AssemblyDefinition ass = LoadAssembly (name);
168 Console.Error.WriteLine ("Cannot load assembly file " + name);
172 assemblies.Add (ass);
176 public void DoOutput ()
179 throw new InvalidOperationException ("Document not set");
181 writer.WriteStartElement ("assemblies");
182 foreach (AssemblyDefinition a in assemblies) {
183 AssemblyData data = new AssemblyData (writer, a);
186 writer.WriteEndElement ();
189 public XmlWriter Writer {
190 set { writer = value; }
193 AssemblyDefinition LoadAssembly (string assembly)
196 if (File.Exists (assembly))
197 return TypeHelper.Resolver.ResolveFile (assembly);
199 return TypeHelper.Resolver.Resolve (assembly);
200 } catch (Exception e) {
201 Console.WriteLine (e);
207 abstract class BaseData
209 protected XmlWriter writer;
211 protected BaseData (XmlWriter writer)
213 this.writer = writer;
216 public abstract void DoOutput ();
218 protected void AddAttribute (string name, string value)
220 writer.WriteAttributeString (name, value);
224 class TypeForwardedToData : BaseData
226 AssemblyDefinition ass;
228 public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass)
234 public override void DoOutput ()
236 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
238 if (((uint)type.Attributes & 0x200000u) == 0)
241 writer.WriteStartElement ("attribute");
242 AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName);
243 writer.WriteStartElement ("properties");
244 writer.WriteStartElement ("property");
245 AddAttribute ("name", "Destination");
246 AddAttribute ("value", Utils.CleanupTypeName (type.FullName));
247 writer.WriteEndElement (); // properties
248 writer.WriteEndElement (); // properties
249 writer.WriteEndElement (); // attribute
253 public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass)
255 TypeForwardedToData tftd = new TypeForwardedToData (writer, ass);
260 class AssemblyData : BaseData
262 AssemblyDefinition ass;
264 public AssemblyData (XmlWriter writer, AssemblyDefinition ass)
270 public override void DoOutput ()
273 throw new InvalidOperationException ("Document not set");
275 writer.WriteStartElement ("assembly");
276 AssemblyNameDefinition aname = ass.Name;
277 AddAttribute ("name", aname.Name);
278 AddAttribute ("version", aname.Version.ToString ());
280 AttributeData.OutputAttributes (writer, ass);
282 var types = new List<TypeDefinition> ();
283 if (ass.MainModule.Types != null) {
284 types.AddRange (ass.MainModule.Types);
287 if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
288 foreach (var t in ass.MainModule.ExportedTypes) {
289 var forwarded = t.Resolve ();
290 if (forwarded == null) {
291 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
293 types.Add (forwarded);
297 if (types.Count == 0) {
298 writer.WriteEndElement (); // assembly
302 types.Sort (TypeReferenceComparer.Default);
304 writer.WriteStartElement ("namespaces");
306 string current_namespace = "$%&$&";
307 bool in_namespace = false;
308 foreach (TypeDefinition t in types) {
309 if (string.IsNullOrEmpty (t.Namespace))
312 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
315 if (t.DeclaringType != null)
316 continue; // enforce !nested
318 if (t.Namespace != current_namespace) {
319 current_namespace = t.Namespace;
321 writer.WriteEndElement (); // classes
322 writer.WriteEndElement (); // namespace
326 writer.WriteStartElement ("namespace");
327 AddAttribute ("name", current_namespace);
328 writer.WriteStartElement ("classes");
331 TypeData bd = new TypeData (writer, t);
337 writer.WriteEndElement (); // classes
338 writer.WriteEndElement (); // namespace
341 writer.WriteEndElement (); // namespaces
343 writer.WriteEndElement (); // assembly
347 abstract class MemberData : BaseData
349 MemberReference [] members;
351 public MemberData (XmlWriter writer, MemberReference [] members)
354 this.members = members;
357 protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
362 public override void DoOutput ()
364 writer.WriteStartElement (ParentTag);
366 foreach (MemberReference member in members) {
367 writer.WriteStartElement (Tag);
368 AddAttribute ("name", GetName (member));
369 if (!NoMemberAttributes)
370 AddAttribute ("attrib", GetMemberAttributes (member));
371 AddExtraAttributes (member);
373 AttributeData.OutputAttributes (writer, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member));
375 AddExtraData (member);
376 writer.WriteEndElement (); // Tag
379 writer.WriteEndElement (); // ParentTag
382 protected virtual void AddExtraData (MemberReference memberDefenition)
386 protected virtual void AddExtraAttributes (MemberReference memberDefinition)
390 protected virtual string GetName (MemberReference memberDefenition)
395 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
400 public virtual bool NoMemberAttributes {
401 get { return false; }
405 public virtual string ParentTag {
406 get { return "NoPARENTTAG"; }
409 public virtual string Tag {
410 get { return "NoTAG"; }
413 public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider)
415 if (provider.GenericParameters.Count == 0)
418 var gparameters = provider.GenericParameters;
420 writer.WriteStartElement ("generic-parameters");
422 foreach (GenericParameter gp in gparameters) {
423 writer.WriteStartElement ("generic-parameter");
424 writer.WriteAttributeString ("name", gp.Name);
425 writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ());
427 AttributeData.OutputAttributes (writer, gp);
429 var constraints = gp.Constraints;
430 if (constraints.Count == 0) {
431 writer.WriteEndElement (); // generic-parameter
435 writer.WriteStartElement ("generic-parameter-constraints");
437 foreach (TypeReference constraint in constraints) {
438 writer.WriteStartElement ("generic-parameter-constraint");
439 writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint));
440 writer.WriteEndElement (); // generic-parameter-constraint
443 writer.WriteEndElement (); // generic-parameter-constraints
445 writer.WriteEndElement (); // generic-parameter
448 writer.WriteEndElement (); // generic-parameters
452 class TypeData : MemberData
456 public TypeData (XmlWriter writer, TypeDefinition type)
457 : base (writer, null)
461 public override void DoOutput ()
464 throw new InvalidOperationException ("Document not set");
466 writer.WriteStartElement ("class");
467 AddAttribute ("name", type.Name);
468 string classType = GetClassType (type);
469 AddAttribute ("type", classType);
471 if (type.BaseType != null)
472 AddAttribute ("base", Utils.CleanupTypeName (type.BaseType));
475 AddAttribute ("sealed", "true");
478 AddAttribute ("abstract", "true");
480 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
481 AddAttribute ("serializable", "true");
483 string charSet = GetCharSet (type);
484 AddAttribute ("charset", charSet);
486 string layout = GetLayout (type);
488 AddAttribute ("layout", layout);
490 if (type.PackingSize >= 0) {
491 AddAttribute ("pack", type.PackingSize.ToString ());
494 if (type.ClassSize >= 0) {
495 AddAttribute ("size", type.ClassSize.ToString ());
499 var value_type = GetEnumValueField (type);
500 if (value_type == null)
501 throw new NotSupportedException ();
503 AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType));
506 AttributeData.OutputAttributes (writer, type);
508 var ifaces = TypeHelper.GetInterfaces (type).
509 Where ((iface) => TypeHelper.IsPublic (iface)). // we're only interested in public interfaces
510 OrderBy (s => s.FullName, StringComparer.Ordinal);
513 writer.WriteStartElement ("interfaces");
514 foreach (TypeReference iface in ifaces) {
515 writer.WriteStartElement ("interface");
516 AddAttribute ("name", Utils.CleanupTypeName (iface));
517 writer.WriteEndElement (); // interface
519 writer.WriteEndElement (); // interfaces
522 MemberData.OutputGenericParameters (writer, type);
524 ArrayList members = new ArrayList ();
526 FieldDefinition [] fields = GetFields (type);
527 if (fields.Length > 0) {
528 Array.Sort (fields, MemberReferenceComparer.Default);
529 FieldData fd = new FieldData (writer, fields);
533 if (!Driver.AbiMode) {
535 MethodDefinition [] ctors = GetConstructors (type);
536 if (ctors.Length > 0) {
537 Array.Sort (ctors, MethodDefinitionComparer.Default);
538 members.Add (new ConstructorData (writer, ctors));
541 PropertyDefinition[] properties = GetProperties (type);
542 if (properties.Length > 0) {
543 Array.Sort (properties, PropertyDefinitionComparer.Default);
544 members.Add (new PropertyData (writer, properties));
547 EventDefinition [] events = GetEvents (type);
548 if (events.Length > 0) {
549 Array.Sort (events, MemberReferenceComparer.Default);
550 members.Add (new EventData (writer, events));
553 MethodDefinition [] methods = GetMethods (type);
554 if (methods.Length > 0) {
555 Array.Sort (methods, MethodDefinitionComparer.Default);
556 members.Add (new MethodData (writer, methods));
560 foreach (MemberData md in members)
563 var nested = type.NestedTypes;
564 //remove non public(familiy) and nested in second degree
565 for (int i = nested.Count - 1; i >= 0; i--) {
566 TypeDefinition t = nested [i];
567 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
568 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
569 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
571 if (t.DeclaringType == type)
572 continue; // not nested of nested
578 if (nested.Count > 0) {
579 var nestedArray = nested.ToArray ();
580 Array.Sort (nestedArray, TypeReferenceComparer.Default);
582 writer.WriteStartElement ("classes");
583 foreach (TypeDefinition t in nestedArray) {
584 TypeData td = new TypeData (writer, t);
587 writer.WriteEndElement (); // classes
590 writer.WriteEndElement (); // class
593 static FieldReference GetEnumValueField (TypeDefinition type)
595 foreach (FieldDefinition field in type.Fields)
596 if (field.IsSpecialName && field.Name == "value__")
602 protected override string GetMemberAttributes (MemberReference member)
605 throw new InvalidOperationException ("odd");
607 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
610 public static bool MustDocumentMethod (MethodDefinition method) {
612 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
613 return maskedAccess == MethodAttributes.Public
614 || maskedAccess == MethodAttributes.Family
615 || maskedAccess == MethodAttributes.FamORAssem;
618 static string GetClassType (TypeDefinition t)
629 if (TypeHelper.IsDelegate(t))
638 static string GetCharSet (TypeDefinition type)
640 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
641 if (maskedStringFormat == TypeAttributes.AnsiClass)
642 return CharSet.Ansi.ToString ();
644 if (maskedStringFormat == TypeAttributes.AutoClass)
645 return CharSet.Auto.ToString ();
647 if (maskedStringFormat == TypeAttributes.UnicodeClass)
648 return CharSet.Unicode.ToString ();
650 return CharSet.None.ToString ();
653 static string GetLayout (TypeDefinition type)
655 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
656 if (maskedLayout == TypeAttributes.AutoLayout)
657 return LayoutKind.Auto.ToString ();
659 if (maskedLayout == TypeAttributes.ExplicitLayout)
660 return LayoutKind.Explicit.ToString ();
662 if (maskedLayout == TypeAttributes.SequentialLayout)
663 return LayoutKind.Sequential.ToString ();
668 FieldDefinition [] GetFields (TypeDefinition type) {
669 ArrayList list = new ArrayList ();
671 var fields = type.Fields;
672 foreach (FieldDefinition field in fields) {
673 if (field.IsSpecialName)
676 if (Driver.AbiMode && field.IsStatic)
679 // we're only interested in public or protected members
680 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
681 if (Driver.AbiMode && !field.IsNotSerialized) {
684 if (maskedVisibility == FieldAttributes.Public
685 || maskedVisibility == FieldAttributes.Family
686 || maskedVisibility == FieldAttributes.FamORAssem) {
692 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
696 internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
697 ArrayList list = new ArrayList ();
699 var properties = type.Properties;//type.GetProperties (flags);
700 foreach (PropertyDefinition property in properties) {
701 MethodDefinition getMethod = property.GetMethod;
702 MethodDefinition setMethod = property.SetMethod;
704 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
705 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
707 // if neither the getter or setter should be documented, then
709 if (hasGetter || hasSetter) {
714 return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
717 private MethodDefinition[] GetMethods (TypeDefinition type)
719 ArrayList list = new ArrayList ();
721 var methods = type.Methods;//type.GetMethods (flags);
722 foreach (MethodDefinition method in methods) {
723 if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
726 // we're only interested in public or protected members
727 if (!MustDocumentMethod(method))
730 if (IsFinalizer (method)) {
731 string name = method.DeclaringType.Name;
732 int arity = name.IndexOf ('`');
734 name = name.Substring (0, arity);
736 method.Name = "~" + name;
742 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
745 static bool IsFinalizer (MethodDefinition method)
747 if (method.Name != "Finalize")
750 if (!method.IsVirtual)
753 if (method.Parameters.Count != 0)
759 private MethodDefinition [] GetConstructors (TypeDefinition type)
761 ArrayList list = new ArrayList ();
763 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
764 foreach (MethodDefinition constructor in ctors) {
765 // we're only interested in public or protected members
766 if (!MustDocumentMethod(constructor))
769 list.Add (constructor);
772 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
775 private EventDefinition[] GetEvents (TypeDefinition type)
777 ArrayList list = new ArrayList ();
779 var events = type.Events;//type.GetEvents (flags);
780 foreach (EventDefinition eventDef in events) {
781 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
783 if (addMethod == null || !MustDocumentMethod (addMethod))
789 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
793 class FieldData : MemberData
795 public FieldData (XmlWriter writer, FieldDefinition [] members)
796 : base (writer, members)
800 protected override string GetName (MemberReference memberDefenition)
802 FieldDefinition field = (FieldDefinition) memberDefenition;
806 protected override string GetMemberAttributes (MemberReference memberDefenition)
808 FieldDefinition field = (FieldDefinition) memberDefenition;
809 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
812 protected override void AddExtraAttributes (MemberReference memberDefinition)
814 base.AddExtraAttributes (memberDefinition);
816 FieldDefinition field = (FieldDefinition) memberDefinition;
817 AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
819 if (field.IsLiteral) {
820 object value = field.Constant;//object value = field.GetValue (null);
821 string stringValue = null;
822 //if (value is Enum) {
823 // // FIXME: when Mono bug #60090 has been
824 // // fixed, we should just be able to use
825 // // Convert.ToString
826 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
829 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
832 if (stringValue != null)
833 AddAttribute ("value", stringValue);
837 public override string ParentTag {
838 get { return "fields"; }
841 public override string Tag {
842 get { return "field"; }
846 class PropertyData : MemberData
848 public PropertyData (XmlWriter writer, PropertyDefinition [] members)
849 : base (writer, members)
853 protected override string GetName (MemberReference memberDefenition)
855 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
859 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
861 MethodDefinition _get = prop.GetMethod;
862 MethodDefinition _set = prop.SetMethod;
863 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
864 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
865 haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
866 MethodDefinition [] methods;
868 if (haveGet && haveSet) {
869 methods = new MethodDefinition [] { _get, _set };
870 } else if (haveGet) {
871 methods = new MethodDefinition [] { _get };
872 } else if (haveSet) {
873 methods = new MethodDefinition [] { _set };
882 protected override void AddExtraAttributes (MemberReference memberDefinition)
884 base.AddExtraAttributes (memberDefinition);
886 PropertyDefinition prop = (PropertyDefinition) memberDefinition;
887 AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
890 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
892 if (methods != null && haveParameters) {
893 string parms = Parameters.GetSignature (methods [0].Parameters);
894 if (!string.IsNullOrEmpty (parms))
895 AddAttribute ("params", parms);
900 protected override void AddExtraData (MemberReference memberDefenition)
902 base.AddExtraData (memberDefenition);
905 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
910 MethodData data = new MethodData (writer, methods);
911 //data.NoMemberAttributes = true;
915 protected override string GetMemberAttributes (MemberReference memberDefenition)
917 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
918 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
921 public override string ParentTag {
922 get { return "properties"; }
925 public override string Tag {
926 get { return "property"; }
930 class EventData : MemberData
932 public EventData (XmlWriter writer, EventDefinition [] members)
933 : base (writer, members)
937 protected override string GetName (MemberReference memberDefenition)
939 EventDefinition evt = (EventDefinition) memberDefenition;
943 protected override string GetMemberAttributes (MemberReference memberDefenition)
945 EventDefinition evt = (EventDefinition) memberDefenition;
946 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
949 protected override void AddExtraAttributes (MemberReference memberDefinition)
951 base.AddExtraAttributes (memberDefinition);
953 EventDefinition evt = (EventDefinition) memberDefinition;
954 AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
957 public override string ParentTag {
958 get { return "events"; }
961 public override string Tag {
962 get { return "event"; }
966 class MethodData : MemberData
970 public MethodData (XmlWriter writer, MethodDefinition [] members)
971 : base (writer, members)
975 protected override string GetName (MemberReference memberDefenition)
977 MethodDefinition method = (MethodDefinition) memberDefenition;
978 string name = method.Name;
979 string parms = Parameters.GetSignature (method.Parameters);
981 return string.Format ("{0}({1})", name, parms);
984 protected override string GetMemberAttributes (MemberReference memberDefenition)
986 MethodDefinition method = (MethodDefinition) memberDefenition;
987 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
990 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
992 var mbase = (MethodDefinition) member;
993 return mbase.MethodReturnType;
996 protected override void AddExtraAttributes (MemberReference memberDefinition)
998 base.AddExtraAttributes (memberDefinition);
1000 if (!(memberDefinition is MethodDefinition))
1003 MethodDefinition mbase = (MethodDefinition) memberDefinition;
1005 if (mbase.IsAbstract)
1006 AddAttribute ("abstract", "true");
1007 if (mbase.IsVirtual)
1008 AddAttribute ("virtual", "true");
1009 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
1010 AddAttribute ("sealed", "true");
1012 AddAttribute ("static", "true");
1013 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
1014 if (rettype != "System.Void" || !mbase.IsConstructor)
1015 AddAttribute ("returntype", (rettype));
1017 // if (mbase.MethodReturnType.HasCustomAttributes)
1018 // AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
1021 protected override void AddExtraData (MemberReference memberDefenition)
1023 base.AddExtraData (memberDefenition);
1025 if (!(memberDefenition is MethodDefinition))
1028 MethodDefinition mbase = (MethodDefinition) memberDefenition;
1030 ParameterData parms = new ParameterData (writer, mbase.Parameters);
1033 MemberData.OutputGenericParameters (writer, mbase);
1036 public override bool NoMemberAttributes {
1037 get { return noAtts; }
1038 set { noAtts = value; }
1041 public override string ParentTag {
1042 get { return "methods"; }
1045 public override string Tag {
1046 get { return "method"; }
1050 class ConstructorData : MethodData
1052 public ConstructorData (XmlWriter writer, MethodDefinition [] members)
1053 : base (writer, members)
1057 public override string ParentTag {
1058 get { return "constructors"; }
1061 public override string Tag {
1062 get { return "constructor"; }
1066 class ParameterData : BaseData
1068 private IList<ParameterDefinition> parameters;
1070 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters)
1073 this.parameters = parameters;
1076 public override void DoOutput ()
1078 writer.WriteStartElement ("parameters");
1079 foreach (ParameterDefinition parameter in parameters) {
1080 writer.WriteStartElement ("parameter");
1081 AddAttribute ("name", parameter.Name);
1082 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1083 AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
1085 string direction = "in";
1087 if (parameter.ParameterType is ByReferenceType)
1088 direction = parameter.IsOut ? "out" : "ref";
1090 TypeReference t = parameter.ParameterType;
1091 AddAttribute ("type", Utils.CleanupTypeName (t));
1093 if (parameter.IsOptional) {
1094 AddAttribute ("optional", "true");
1095 if (parameter.HasConstant)
1096 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1099 if (direction != "in")
1100 AddAttribute ("direction", direction);
1102 AttributeData.OutputAttributes (writer, parameter);
1103 writer.WriteEndElement (); // parameter
1105 writer.WriteEndElement (); // parameters
1111 public static void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1114 throw new InvalidOperationException ("Document not set");
1116 if (providers == null || providers.Count == 0)
1119 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1122 writer.WriteStartElement ("attributes");
1124 foreach (var provider in providers) {
1125 if (provider == null)
1128 if (!provider.HasCustomAttributes)
1132 var ass = provider as AssemblyDefinition;
1133 if (ass != null && !Driver.FollowForwarders)
1134 TypeForwardedToData.OutputForwarders (writer, ass);
1136 var attributes = provider.CustomAttributes.
1137 Where ((att) => !SkipAttribute (att)).
1138 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1140 foreach (var att in attributes) {
1141 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1143 writer.WriteStartElement ("attribute");
1144 writer.WriteAttributeString ("name", attName);
1146 var attribute_mapping = CreateAttributeMapping (att);
1148 if (attribute_mapping != null) {
1149 var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId");
1150 if (mapping.Any ()) {
1151 writer.WriteStartElement ("properties");
1152 foreach (var kvp in mapping) {
1153 string name = kvp.Key;
1154 object o = kvp.Value;
1156 writer.WriteStartElement ("property");
1157 writer.WriteAttributeString ("name", name);
1160 writer.WriteAttributeString ("value", "null");
1162 string value = o.ToString ();
1163 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1164 value = value.ToUpper ();
1165 writer.WriteAttributeString ("value", value);
1168 writer.WriteEndElement (); // property
1170 writer.WriteEndElement (); // properties
1173 writer.WriteEndElement (); // attribute
1177 writer.WriteEndElement (); // attributes
1180 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1182 Dictionary<string, object> mapping = null;
1184 PopulateMapping (ref mapping, attribute);
1186 var constructor = attribute.Constructor.Resolve ();
1187 if (constructor == null || !constructor.HasParameters)
1190 PopulateMapping (ref mapping, constructor, attribute);
1195 static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
1197 if (!attribute.HasProperties)
1200 foreach (var named_argument in attribute.Properties) {
1201 var name = named_argument.Name;
1202 var arg = named_argument.Argument;
1204 if (arg.Value is CustomAttributeArgument)
1205 arg = (CustomAttributeArgument) arg.Value;
1207 if (mapping == null)
1208 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1209 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1213 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1215 Dictionary<FieldReference, int> field_mapping = null;
1217 int? argument = null;
1219 foreach (Instruction instruction in constructor.Body.Instructions) {
1220 switch (instruction.OpCode.Code) {
1232 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1236 FieldReference field = (FieldReference) instruction.Operand;
1237 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1240 if (!argument.HasValue)
1243 if (field_mapping == null)
1244 field_mapping = new Dictionary<FieldReference, int> ();
1246 if (!field_mapping.ContainsKey (field))
1247 field_mapping.Add (field, (int) argument - 1);
1254 return field_mapping;
1257 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1259 Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
1261 foreach (PropertyDefinition property in type.Properties) {
1262 if (property.GetMethod == null)
1264 if (!property.GetMethod.HasBody)
1267 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1268 if (instruction.OpCode.Code != Code.Ldfld)
1271 FieldReference field = (FieldReference) instruction.Operand;
1272 if (field.DeclaringType.FullName != type.FullName)
1275 if (property_mapping == null)
1276 property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1277 property_mapping.Add (property, field);
1282 return property_mapping;
1285 static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1287 if (!constructor.HasBody)
1290 // Custom handling for attributes with arguments which cannot be easily extracted
1291 var ca = attribute.ConstructorArguments;
1292 switch (constructor.DeclaringType.FullName) {
1293 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1294 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1295 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1296 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1298 if (mapping == null)
1299 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1300 mapping.Add ("Value", dca.Value);
1302 case "System.ComponentModel.BindableAttribute":
1306 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1307 if (mapping == null)
1308 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1309 mapping.Add ("Bindable", ca[0].Value);
1311 throw new NotImplementedException ();
1317 var field_mapping = CreateArgumentFieldMapping (constructor);
1318 if (field_mapping != null) {
1319 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1321 if (property_mapping != null) {
1322 foreach (var pair in property_mapping) {
1324 if (!field_mapping.TryGetValue (pair.Value, out argument))
1327 var ca_arg = ca [argument];
1328 if (ca_arg.Value is CustomAttributeArgument)
1329 ca_arg = (CustomAttributeArgument)ca_arg.Value;
1331 if (mapping == null)
1332 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1333 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1339 static object GetArgumentValue (TypeReference reference, object value)
1341 var type = reference.Resolve ();
1346 if (IsFlaggedEnum (type))
1347 return GetFlaggedEnumValue (type, value);
1349 return GetEnumValue (type, value);
1355 static bool IsFlaggedEnum (TypeDefinition type)
1360 if (!type.HasCustomAttributes)
1363 foreach (CustomAttribute attribute in type.CustomAttributes)
1364 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1370 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1373 return GetFlaggedEnumValue (type, (ulong)value);
1375 long flags = Convert.ToInt64 (value);
1376 var signature = new StringBuilder ();
1378 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1379 FieldDefinition field = type.Fields [i];
1381 if (!field.HasConstant)
1384 long flag = Convert.ToInt64 (field.Constant);
1389 if ((flags & flag) == flag) {
1390 if (signature.Length != 0)
1391 signature.Append (", ");
1393 signature.Append (field.Name);
1398 return signature.ToString ();
1401 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1403 var signature = new StringBuilder ();
1405 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1406 FieldDefinition field = type.Fields [i];
1408 if (!field.HasConstant)
1411 ulong flag = Convert.ToUInt64 (field.Constant);
1416 if ((flags & flag) == flag) {
1417 if (signature.Length != 0)
1418 signature.Append (", ");
1420 signature.Append (field.Name);
1425 return signature.ToString ();
1428 static object GetEnumValue (TypeDefinition type, object value)
1430 foreach (FieldDefinition field in type.Fields) {
1431 if (!field.HasConstant)
1434 if (Comparer.Default.Compare (field.Constant, value) == 0)
1441 static bool SkipAttribute (CustomAttribute attribute)
1443 if (!TypeHelper.IsPublic (attribute))
1446 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1449 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1451 AttributeData.DoOutput (writer, providers);
1455 static class Parameters {
1457 public static string GetSignature (IList<ParameterDefinition> infos)
1459 if (infos == null || infos.Count == 0)
1460 return string.Empty;
1462 var signature = new StringBuilder ();
1463 for (int i = 0; i < infos.Count; i++) {
1466 signature.Append (", ");
1468 ParameterDefinition info = infos [i];
1471 if ((info.Attributes & ParameterAttributes.In) != 0)
1473 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1476 modifier = string.Empty;
1478 if (modifier.Length > 0) {
1479 signature.Append (modifier);
1480 signature.Append (" ");
1483 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1486 return signature.ToString ();
1491 class TypeReferenceComparer : IComparer<TypeReference>
1493 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1495 public int Compare (TypeReference a, TypeReference b)
1497 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1501 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1505 class MemberReferenceComparer : IComparer
1507 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1509 public int Compare (object a, object b)
1511 MemberReference ma = (MemberReference) a;
1512 MemberReference mb = (MemberReference) b;
1513 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1517 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1519 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1521 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1523 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1527 if (!ma.HasParameters && !mb.HasParameters)
1530 if (!ma.HasParameters)
1533 if (!mb.HasParameters)
1536 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1540 class MethodDefinitionComparer : IComparer
1542 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1544 public int Compare (object a, object b)
1546 MethodDefinition ma = (MethodDefinition) a;
1547 MethodDefinition mb = (MethodDefinition) b;
1548 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1552 if (!ma.HasParameters && !mb.HasParameters)
1555 if (!ma.HasParameters)
1558 if (!mb.HasParameters)
1561 res = Compare (ma.Parameters, mb.Parameters);
1565 // operators can differ by only return type
1566 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1569 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1571 var res = pia.Count - pib.Count;
1575 string siga = Parameters.GetSignature (pia);
1576 string sigb = Parameters.GetSignature (pib);
1577 return String.Compare (siga, sigb, StringComparison.Ordinal);