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).Where ((kvp) => kvp.Key != "TypeId");
1148 if (attribute_mapping.Any ()) {
1149 writer.WriteStartElement ("properties");
1150 foreach (var kvp in attribute_mapping) {
1151 string name = kvp.Key;
1152 object o = kvp.Value;
1154 writer.WriteStartElement ("property");
1155 writer.WriteAttributeString ("name", name);
1158 writer.WriteAttributeString ("value", "null");
1160 string value = o.ToString ();
1161 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1162 value = value.ToUpper ();
1163 writer.WriteAttributeString ("value", value);
1166 writer.WriteEndElement (); // property
1168 writer.WriteEndElement (); // properties
1170 writer.WriteEndElement (); // attribute
1174 writer.WriteEndElement (); // attributes
1177 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1179 var mapping = new Dictionary<string, object> ();
1181 PopulateMapping (mapping, attribute);
1183 var constructor = attribute.Constructor.Resolve ();
1184 if (constructor == null || !constructor.HasParameters)
1187 PopulateMapping (mapping, constructor, attribute);
1192 static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
1194 if (!attribute.HasProperties)
1197 foreach (var named_argument in attribute.Properties) {
1198 var name = named_argument.Name;
1199 var arg = named_argument.Argument;
1201 if (arg.Value is CustomAttributeArgument)
1202 arg = (CustomAttributeArgument) arg.Value;
1204 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1208 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1210 Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
1212 int? argument = null;
1214 foreach (Instruction instruction in constructor.Body.Instructions) {
1215 switch (instruction.OpCode.Code) {
1227 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1231 FieldReference field = (FieldReference) instruction.Operand;
1232 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1235 if (!argument.HasValue)
1238 if (!field_mapping.ContainsKey (field))
1239 field_mapping.Add (field, (int) argument - 1);
1246 return field_mapping;
1249 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1251 Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1253 foreach (PropertyDefinition property in type.Properties) {
1254 if (property.GetMethod == null)
1256 if (!property.GetMethod.HasBody)
1259 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1260 if (instruction.OpCode.Code != Code.Ldfld)
1263 FieldReference field = (FieldReference) instruction.Operand;
1264 if (field.DeclaringType.FullName != type.FullName)
1267 property_mapping.Add (property, field);
1272 return property_mapping;
1275 static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1277 if (!constructor.HasBody)
1280 // Custom handling for attributes with arguments which cannot be easily extracted
1281 var ca = attribute.ConstructorArguments;
1282 switch (constructor.DeclaringType.FullName) {
1283 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1284 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1285 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1286 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1288 mapping.Add ("Value", dca.Value);
1290 case "System.ComponentModel.BindableAttribute":
1294 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1295 mapping.Add ("Bindable", ca[0].Value);
1297 throw new NotImplementedException ();
1303 var field_mapping = CreateArgumentFieldMapping (constructor);
1304 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1306 foreach (var pair in property_mapping) {
1308 if (!field_mapping.TryGetValue (pair.Value, out argument))
1311 var ca_arg = ca [argument];
1312 if (ca_arg.Value is CustomAttributeArgument)
1313 ca_arg = (CustomAttributeArgument) ca_arg.Value;
1315 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1319 static object GetArgumentValue (TypeReference reference, object value)
1321 var type = reference.Resolve ();
1326 if (IsFlaggedEnum (type))
1327 return GetFlaggedEnumValue (type, value);
1329 return GetEnumValue (type, value);
1335 static bool IsFlaggedEnum (TypeDefinition type)
1340 if (!type.HasCustomAttributes)
1343 foreach (CustomAttribute attribute in type.CustomAttributes)
1344 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1350 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1353 return GetFlaggedEnumValue (type, (ulong)value);
1355 long flags = Convert.ToInt64 (value);
1356 var signature = new StringBuilder ();
1358 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1359 FieldDefinition field = type.Fields [i];
1361 if (!field.HasConstant)
1364 long flag = Convert.ToInt64 (field.Constant);
1369 if ((flags & flag) == flag) {
1370 if (signature.Length != 0)
1371 signature.Append (", ");
1373 signature.Append (field.Name);
1378 return signature.ToString ();
1381 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1383 var signature = new StringBuilder ();
1385 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1386 FieldDefinition field = type.Fields [i];
1388 if (!field.HasConstant)
1391 ulong flag = Convert.ToUInt64 (field.Constant);
1396 if ((flags & flag) == flag) {
1397 if (signature.Length != 0)
1398 signature.Append (", ");
1400 signature.Append (field.Name);
1405 return signature.ToString ();
1408 static object GetEnumValue (TypeDefinition type, object value)
1410 foreach (FieldDefinition field in type.Fields) {
1411 if (!field.HasConstant)
1414 if (Comparer.Default.Compare (field.Constant, value) == 0)
1421 static bool SkipAttribute (CustomAttribute attribute)
1423 if (!TypeHelper.IsPublic (attribute))
1426 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1429 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1431 AttributeData.DoOutput (writer, providers);
1435 static class Parameters {
1437 public static string GetSignature (IList<ParameterDefinition> infos)
1439 if (infos == null || infos.Count == 0)
1440 return string.Empty;
1442 var signature = new StringBuilder ();
1443 for (int i = 0; i < infos.Count; i++) {
1446 signature.Append (", ");
1448 ParameterDefinition info = infos [i];
1451 if ((info.Attributes & ParameterAttributes.In) != 0)
1453 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1456 modifier = string.Empty;
1458 if (modifier.Length > 0) {
1459 signature.Append (modifier);
1460 signature.Append (" ");
1463 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1466 return signature.ToString ();
1471 class TypeReferenceComparer : IComparer<TypeReference>
1473 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1475 public int Compare (TypeReference a, TypeReference b)
1477 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1481 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1485 class MemberReferenceComparer : IComparer
1487 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1489 public int Compare (object a, object b)
1491 MemberReference ma = (MemberReference) a;
1492 MemberReference mb = (MemberReference) b;
1493 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1497 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1499 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1501 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1503 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1507 if (!ma.HasParameters && !mb.HasParameters)
1510 if (!ma.HasParameters)
1513 if (!mb.HasParameters)
1516 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1520 class MethodDefinitionComparer : IComparer
1522 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1524 public int Compare (object a, object b)
1526 MethodDefinition ma = (MethodDefinition) a;
1527 MethodDefinition mb = (MethodDefinition) b;
1528 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1532 if (!ma.HasParameters && !mb.HasParameters)
1535 if (!ma.HasParameters)
1538 if (!mb.HasParameters)
1541 res = Compare (ma.Parameters, mb.Parameters);
1545 // operators can differ by only return type
1546 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1549 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1551 var res = pia.Count - pib.Count;
1555 string siga = Parameters.GetSignature (pia);
1556 string sigb = Parameters.GetSignature (pib);
1557 return String.Compare (siga, sigb, StringComparison.Ordinal);