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
1109 class AttributeData : BaseData
1111 IList<ICustomAttributeProvider> providers;
1113 AttributeData (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1116 this.providers = providers;
1119 public override void DoOutput ()
1122 throw new InvalidOperationException ("Document not set");
1124 if (providers == null || providers.Count == 0)
1127 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1130 writer.WriteStartElement ("attributes");
1132 foreach (var provider in providers) {
1133 if (provider == null)
1136 if (!provider.HasCustomAttributes)
1140 var ass = provider as AssemblyDefinition;
1141 if (ass != null && !Driver.FollowForwarders)
1142 TypeForwardedToData.OutputForwarders (writer, ass);
1144 var attributes = provider.CustomAttributes.
1145 Where ((att) => !SkipAttribute (att)).
1146 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1148 foreach (var att in attributes) {
1149 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1151 writer.WriteStartElement ("attribute");
1152 AddAttribute ("name", attName);
1154 var attribute_mapping = CreateAttributeMapping (att).Where ((kvp) => kvp.Key != "TypeId");
1156 if (attribute_mapping.Any ()) {
1157 writer.WriteStartElement ("properties");
1158 foreach (var kvp in attribute_mapping) {
1159 string name = kvp.Key;
1160 object o = kvp.Value;
1162 writer.WriteStartElement ("property");
1163 AddAttribute ("name", name);
1166 AddAttribute ("value", "null");
1168 string value = o.ToString ();
1169 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1170 value = value.ToUpper ();
1171 AddAttribute ("value", value);
1174 writer.WriteEndElement (); // property
1176 writer.WriteEndElement (); // properties
1178 writer.WriteEndElement (); // attribute
1182 writer.WriteEndElement (); // attributes
1185 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1187 var mapping = new Dictionary<string, object> ();
1189 PopulateMapping (mapping, attribute);
1191 var constructor = attribute.Constructor.Resolve ();
1192 if (constructor == null || !constructor.HasParameters)
1195 PopulateMapping (mapping, constructor, attribute);
1200 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1202 if (!attribute.HasProperties)
1205 foreach (var named_argument in attribute.Properties) {
1206 var name = named_argument.Name;
1207 var arg = named_argument.Argument;
1209 if (arg.Value is CustomAttributeArgument)
1210 arg = (CustomAttributeArgument) arg.Value;
1212 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1216 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1218 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1220 int? argument = null;
1222 foreach (Instruction instruction in constructor.Body.Instructions) {
1223 switch (instruction.OpCode.Code) {
1235 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1239 FieldReference field = (FieldReference) instruction.Operand;
1240 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1243 if (!argument.HasValue)
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 = new Dictionary<PropertyDefinition, FieldReference> ();
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 property_mapping.Add (property, field);
1280 return property_mapping;
1283 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1285 if (!constructor.HasBody)
1288 // Custom handling for attributes with arguments which cannot be easily extracted
1289 var ca = attribute.ConstructorArguments;
1290 switch (constructor.DeclaringType.FullName) {
1291 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1292 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1293 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1294 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1296 mapping.Add ("Value", dca.Value);
1298 case "System.ComponentModel.BindableAttribute":
1302 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1303 mapping.Add ("Bindable", ca[0].Value);
1305 throw new NotImplementedException ();
1311 var field_mapping = CreateArgumentFieldMapping (constructor);
1312 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1314 foreach (var pair in property_mapping) {
1316 if (!field_mapping.TryGetValue (pair.Value, out argument))
1319 var ca_arg = ca [argument];
1320 if (ca_arg.Value is CustomAttributeArgument)
1321 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1323 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1327 static object GetArgumentValue (TypeReference reference, object value)
1329 var type = reference.Resolve ();
1334 if (IsFlaggedEnum (type))
1335 return GetFlaggedEnumValue (type, value);
1337 return GetEnumValue (type, value);
1343 static bool IsFlaggedEnum (TypeDefinition type)
1348 if (!type.HasCustomAttributes)
1351 foreach (CustomAttribute attribute in type.CustomAttributes)
1352 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1358 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1361 return GetFlaggedEnumValue (type, (ulong)value);
1363 long flags = Convert.ToInt64 (value);
1364 var signature = new StringBuilder ();
1366 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1367 FieldDefinition field = type.Fields [i];
1369 if (!field.HasConstant)
1372 long flag = Convert.ToInt64 (field.Constant);
1377 if ((flags & flag) == flag) {
1378 if (signature.Length != 0)
1379 signature.Append (", ");
1381 signature.Append (field.Name);
1386 return signature.ToString ();
1389 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1391 var signature = new StringBuilder ();
1393 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1394 FieldDefinition field = type.Fields [i];
1396 if (!field.HasConstant)
1399 ulong flag = Convert.ToUInt64 (field.Constant);
1404 if ((flags & flag) == flag) {
1405 if (signature.Length != 0)
1406 signature.Append (", ");
1408 signature.Append (field.Name);
1413 return signature.ToString ();
1416 static object GetEnumValue (TypeDefinition type, object value)
1418 foreach (FieldDefinition field in type.Fields) {
1419 if (!field.HasConstant)
1422 if (Comparer.Default.Compare (field.Constant, value) == 0)
1429 static bool SkipAttribute (CustomAttribute attribute)
1431 if (!TypeHelper.IsPublic (attribute))
1434 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1437 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1439 AttributeData ad = new AttributeData (writer, providers);
1444 static class Parameters {
1446 public static string GetSignature (IList<ParameterDefinition> infos)
1448 if (infos == null || infos.Count == 0)
1449 return string.Empty;
1451 var signature = new StringBuilder ();
1452 for (int i = 0; i < infos.Count; i++) {
1455 signature.Append (", ");
1457 ParameterDefinition info = infos [i];
1460 if ((info.Attributes & ParameterAttributes.In) != 0)
1462 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1465 modifier = string.Empty;
1467 if (modifier.Length > 0) {
1468 signature.Append (modifier);
1469 signature.Append (" ");
1472 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1475 return signature.ToString ();
1480 class TypeReferenceComparer : IComparer<TypeReference>
1482 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1484 public int Compare (TypeReference a, TypeReference b)
1486 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1490 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1494 class MemberReferenceComparer : IComparer
1496 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1498 public int Compare (object a, object b)
1500 MemberReference ma = (MemberReference) a;
1501 MemberReference mb = (MemberReference) b;
1502 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1506 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1508 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1510 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1512 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1516 if (!ma.HasParameters && !mb.HasParameters)
1519 if (!ma.HasParameters)
1522 if (!mb.HasParameters)
1525 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1529 class MethodDefinitionComparer : IComparer
1531 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1533 public int Compare (object a, object b)
1535 MethodDefinition ma = (MethodDefinition) a;
1536 MethodDefinition mb = (MethodDefinition) b;
1537 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1541 if (!ma.HasParameters && !mb.HasParameters)
1544 if (!ma.HasParameters)
1547 if (!mb.HasParameters)
1550 res = Compare (ma.Parameters, mb.Parameters);
1554 // operators can differ by only return type
1555 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1558 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1560 var res = pia.Count - pib.Count;
1564 string siga = Parameters.GetSignature (pia);
1565 string sigb = Parameters.GetSignature (pib);
1566 return String.Compare (siga, sigb, StringComparison.Ordinal);