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 },
63 "Produces contract API with all members at each level of inheritance hierarchy",
64 v => FullAPISet = v != null },
67 var asms = options.Parse (args);
69 if (showHelp || asms.Count == 0) {
70 options.WriteOptionDescriptions (Console.Out);
72 return showHelp? 0 :1;
75 string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
76 string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
77 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
79 foreach (string arg in asms) {
82 if (arg.Contains ("v3.0")) {
83 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
84 } else if (arg.Contains ("v3.5")) {
85 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
86 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
87 } else if (arg.Contains ("v4.0")) {
88 if (arg.Contains ("Silverlight")) {
89 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
91 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
92 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
95 TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
99 StreamWriter outputStream = null;
100 if (!string.IsNullOrEmpty (output))
101 outputStream = new StreamWriter (output);
103 TextWriter outStream = outputStream ?? Console.Out;
104 var settings = new XmlWriterSettings ();
105 settings.Indent = true;
106 var textWriter = XmlWriter.Create (outStream, settings);
107 var writer = new WellFormedXmlWriter (textWriter);
108 writer.WriteStartDocument ();
109 acoll.Writer = writer;
111 writer.WriteEndDocument ();
114 if (outputStream != null)
115 outputStream.Dispose ();
120 internal static bool AbiMode { get; private set; }
121 internal static bool FollowForwarders { get; private set; }
122 internal static bool FullAPISet { get; set; }
126 static char[] CharsToCleanup = new char[] { '<', '>', '/' };
128 public static string CleanupTypeName (TypeReference type)
130 return CleanupTypeName (type.FullName);
133 public static string CleanupTypeName (string t)
135 if (t.IndexOfAny (CharsToCleanup) == -1)
137 var sb = new StringBuilder (t.Length);
138 for (int i = 0; i < t.Length; i++) {
155 return sb.ToString ();
159 class AssemblyCollection
162 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
164 public AssemblyCollection ()
168 public bool Add (string name)
170 AssemblyDefinition ass = LoadAssembly (name);
172 Console.Error.WriteLine ("Cannot load assembly file " + name);
176 assemblies.Add (ass);
180 public void DoOutput ()
183 throw new InvalidOperationException ("Document not set");
185 writer.WriteStartElement ("assemblies");
186 foreach (AssemblyDefinition a in assemblies) {
187 AssemblyData data = new AssemblyData (writer, a);
190 writer.WriteEndElement ();
193 public XmlWriter Writer {
194 set { writer = value; }
197 AssemblyDefinition LoadAssembly (string assembly)
200 if (File.Exists (assembly))
201 return TypeHelper.Resolver.ResolveFile (assembly);
203 return TypeHelper.Resolver.Resolve (assembly);
204 } catch (Exception e) {
205 Console.WriteLine (e);
211 abstract class BaseData
213 protected XmlWriter writer;
215 protected BaseData (XmlWriter writer)
217 this.writer = writer;
220 public abstract void DoOutput ();
222 protected void AddAttribute (string name, string value)
224 writer.WriteAttributeString (name, value);
228 class TypeForwardedToData : BaseData
230 AssemblyDefinition ass;
232 public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass)
238 public override void DoOutput ()
240 foreach (ExportedType type in ass.MainModule.ExportedTypes) {
242 if (((uint)type.Attributes & 0x200000u) == 0)
245 writer.WriteStartElement ("attribute");
246 AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName);
247 writer.WriteStartElement ("properties");
248 writer.WriteStartElement ("property");
249 AddAttribute ("name", "Destination");
250 AddAttribute ("value", Utils.CleanupTypeName (type.FullName));
251 writer.WriteEndElement (); // properties
252 writer.WriteEndElement (); // properties
253 writer.WriteEndElement (); // attribute
257 public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass)
259 TypeForwardedToData tftd = new TypeForwardedToData (writer, ass);
264 class AssemblyData : BaseData
266 AssemblyDefinition ass;
268 public AssemblyData (XmlWriter writer, AssemblyDefinition ass)
274 public override void DoOutput ()
277 throw new InvalidOperationException ("Document not set");
279 writer.WriteStartElement ("assembly");
280 AssemblyNameDefinition aname = ass.Name;
281 AddAttribute ("name", aname.Name);
282 AddAttribute ("version", aname.Version.ToString ());
284 AttributeData.OutputAttributes (writer, ass);
286 var types = new List<TypeDefinition> ();
287 if (ass.MainModule.Types != null) {
288 types.AddRange (ass.MainModule.Types);
291 if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
292 foreach (var t in ass.MainModule.ExportedTypes) {
293 var forwarded = t.Resolve ();
294 if (forwarded == null) {
295 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
297 types.Add (forwarded);
301 if (types.Count == 0) {
302 writer.WriteEndElement (); // assembly
306 types.Sort (TypeReferenceComparer.Default);
308 writer.WriteStartElement ("namespaces");
310 string current_namespace = "$%&$&";
311 bool in_namespace = false;
312 foreach (TypeDefinition t in types) {
313 if (string.IsNullOrEmpty (t.Namespace))
316 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
319 if (t.DeclaringType != null)
320 continue; // enforce !nested
322 if (t.Namespace != current_namespace) {
323 current_namespace = t.Namespace;
325 writer.WriteEndElement (); // classes
326 writer.WriteEndElement (); // namespace
330 writer.WriteStartElement ("namespace");
331 AddAttribute ("name", current_namespace);
332 writer.WriteStartElement ("classes");
335 TypeData bd = new TypeData (writer, t);
341 writer.WriteEndElement (); // classes
342 writer.WriteEndElement (); // namespace
345 writer.WriteEndElement (); // namespaces
347 writer.WriteEndElement (); // assembly
351 abstract class MemberData : BaseData
353 MemberReference [] members;
355 public MemberData (XmlWriter writer, MemberReference [] members)
358 this.members = members;
361 protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
366 public override void DoOutput ()
368 writer.WriteStartElement (ParentTag);
370 foreach (MemberReference member in members) {
371 writer.WriteStartElement (Tag);
372 AddAttribute ("name", GetName (member));
373 if (!NoMemberAttributes)
374 AddAttribute ("attrib", GetMemberAttributes (member));
375 AddExtraAttributes (member);
377 AttributeData.OutputAttributes (writer, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member));
379 AddExtraData (member);
380 writer.WriteEndElement (); // Tag
383 writer.WriteEndElement (); // ParentTag
386 protected virtual void AddExtraData (MemberReference memberDefenition)
390 protected virtual void AddExtraAttributes (MemberReference memberDefinition)
394 protected virtual string GetName (MemberReference memberDefenition)
399 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
404 public virtual bool NoMemberAttributes {
405 get { return false; }
409 public virtual string ParentTag {
410 get { return "NoPARENTTAG"; }
413 public virtual string Tag {
414 get { return "NoTAG"; }
417 public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider)
419 if (provider.GenericParameters.Count == 0)
422 var gparameters = provider.GenericParameters;
424 writer.WriteStartElement ("generic-parameters");
426 foreach (GenericParameter gp in gparameters) {
427 writer.WriteStartElement ("generic-parameter");
428 writer.WriteAttributeString ("name", gp.Name);
429 writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ());
431 AttributeData.OutputAttributes (writer, gp);
433 var constraints = gp.Constraints;
434 if (constraints.Count == 0) {
435 writer.WriteEndElement (); // generic-parameter
439 writer.WriteStartElement ("generic-parameter-constraints");
441 foreach (TypeReference constraint in constraints) {
442 writer.WriteStartElement ("generic-parameter-constraint");
443 writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint));
444 writer.WriteEndElement (); // generic-parameter-constraint
447 writer.WriteEndElement (); // generic-parameter-constraints
449 writer.WriteEndElement (); // generic-parameter
452 writer.WriteEndElement (); // generic-parameters
456 class TypeData : MemberData
460 public TypeData (XmlWriter writer, TypeDefinition type)
461 : base (writer, null)
465 public override void DoOutput ()
468 throw new InvalidOperationException ("Document not set");
470 writer.WriteStartElement ("class");
471 AddAttribute ("name", type.Name);
472 string classType = GetClassType (type);
473 AddAttribute ("type", classType);
475 if (type.BaseType != null)
476 AddAttribute ("base", Utils.CleanupTypeName (type.BaseType));
479 AddAttribute ("sealed", "true");
482 AddAttribute ("abstract", "true");
484 if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
485 AddAttribute ("serializable", "true");
487 string charSet = GetCharSet (type);
488 AddAttribute ("charset", charSet);
490 string layout = GetLayout (type);
492 AddAttribute ("layout", layout);
494 if (type.PackingSize >= 0) {
495 AddAttribute ("pack", type.PackingSize.ToString ());
498 if (type.ClassSize >= 0) {
499 AddAttribute ("size", type.ClassSize.ToString ());
503 var value_type = GetEnumValueField (type);
504 if (value_type == null)
505 throw new NotSupportedException ();
507 AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType));
510 AttributeData.OutputAttributes (writer, type);
512 var ifaces = TypeHelper.GetInterfaces (type).
513 Where ((iface) => TypeHelper.IsPublic (iface)). // we're only interested in public interfaces
514 OrderBy (s => s.FullName, StringComparer.Ordinal);
517 writer.WriteStartElement ("interfaces");
518 foreach (TypeReference iface in ifaces) {
519 writer.WriteStartElement ("interface");
520 AddAttribute ("name", Utils.CleanupTypeName (iface));
521 writer.WriteEndElement (); // interface
523 writer.WriteEndElement (); // interfaces
526 MemberData.OutputGenericParameters (writer, type);
528 ArrayList members = new ArrayList ();
530 FieldDefinition [] fields = GetFields (type);
531 if (fields.Length > 0) {
532 Array.Sort (fields, MemberReferenceComparer.Default);
533 FieldData fd = new FieldData (writer, fields);
537 if (!Driver.AbiMode) {
539 MethodDefinition [] ctors = GetConstructors (type);
540 if (ctors.Length > 0) {
541 Array.Sort (ctors, MethodDefinitionComparer.Default);
542 members.Add (new ConstructorData (writer, ctors));
545 PropertyDefinition[] properties = GetProperties (type, Driver.FullAPISet);
546 if (properties.Length > 0) {
547 Array.Sort (properties, PropertyDefinitionComparer.Default);
548 members.Add (new PropertyData (writer, properties));
551 EventDefinition [] events = GetEvents (type);
552 if (events.Length > 0) {
553 Array.Sort (events, MemberReferenceComparer.Default);
554 members.Add (new EventData (writer, events));
557 MethodDefinition [] methods = GetMethods (type, Driver.FullAPISet);
558 if (methods.Length > 0) {
559 Array.Sort (methods, MethodDefinitionComparer.Default);
560 members.Add (new MethodData (writer, methods));
564 foreach (MemberData md in members)
567 var nested = type.NestedTypes;
568 //remove non public(familiy) and nested in second degree
569 for (int i = nested.Count - 1; i >= 0; i--) {
570 TypeDefinition t = nested [i];
571 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
572 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
573 (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
575 if (t.DeclaringType == type)
576 continue; // not nested of nested
582 if (nested.Count > 0) {
583 var nestedArray = nested.ToArray ();
584 Array.Sort (nestedArray, TypeReferenceComparer.Default);
586 writer.WriteStartElement ("classes");
587 foreach (TypeDefinition t in nestedArray) {
588 TypeData td = new TypeData (writer, t);
591 writer.WriteEndElement (); // classes
594 writer.WriteEndElement (); // class
597 static FieldReference GetEnumValueField (TypeDefinition type)
599 foreach (FieldDefinition field in type.Fields)
600 if (field.IsSpecialName && field.Name == "value__")
606 protected override string GetMemberAttributes (MemberReference member)
609 throw new InvalidOperationException ("odd");
611 return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
614 public static bool MustDocumentMethod (MethodDefinition method) {
616 MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
617 return maskedAccess == MethodAttributes.Public
618 || maskedAccess == MethodAttributes.Family
619 || maskedAccess == MethodAttributes.FamORAssem;
622 static string GetClassType (TypeDefinition t)
633 if (TypeHelper.IsDelegate(t))
642 static string GetCharSet (TypeDefinition type)
644 TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
645 if (maskedStringFormat == TypeAttributes.AnsiClass)
646 return CharSet.Ansi.ToString ();
648 if (maskedStringFormat == TypeAttributes.AutoClass)
649 return CharSet.Auto.ToString ();
651 if (maskedStringFormat == TypeAttributes.UnicodeClass)
652 return CharSet.Unicode.ToString ();
654 return CharSet.None.ToString ();
657 static string GetLayout (TypeDefinition type)
659 TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
660 if (maskedLayout == TypeAttributes.AutoLayout)
661 return LayoutKind.Auto.ToString ();
663 if (maskedLayout == TypeAttributes.ExplicitLayout)
664 return LayoutKind.Explicit.ToString ();
666 if (maskedLayout == TypeAttributes.SequentialLayout)
667 return LayoutKind.Sequential.ToString ();
672 FieldDefinition [] GetFields (TypeDefinition type) {
673 ArrayList list = new ArrayList ();
675 var fields = type.Fields;
676 foreach (FieldDefinition field in fields) {
677 if (field.IsSpecialName)
680 if (Driver.AbiMode && field.IsStatic)
683 // we're only interested in public or protected members
684 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
685 if (Driver.AbiMode && !field.IsNotSerialized) {
688 if (maskedVisibility == FieldAttributes.Public
689 || maskedVisibility == FieldAttributes.Family
690 || maskedVisibility == FieldAttributes.FamORAssem) {
696 return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
700 internal static PropertyDefinition [] GetProperties (TypeDefinition type, bool fullAPI) {
701 var list = new List<PropertyDefinition> ();
705 var properties = t.Properties;//type.GetProperties (flags);
706 foreach (PropertyDefinition property in properties) {
707 MethodDefinition getMethod = property.GetMethod;
708 MethodDefinition setMethod = property.SetMethod;
710 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
711 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
713 // if neither the getter or setter should be documented, then
715 if (hasGetter || hasSetter) {
717 if (t != type && list.Any (l => l.Name == property.Name))
727 if (t.IsInterface || t.IsEnum)
730 if (t.BaseType == null || t.BaseType.FullName == "System.Object")
733 t = t.BaseType.Resolve ();
737 return list.ToArray ();
740 private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI)
742 var list = new List<MethodDefinition> ();
746 var methods = t.Methods;//type.GetMethods (flags);
747 foreach (MethodDefinition method in methods) {
748 if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
751 // we're only interested in public or protected members
752 if (!MustDocumentMethod (method))
755 if (t == type && IsFinalizer (method)) {
756 string name = method.DeclaringType.Name;
757 int arity = name.IndexOf ('`');
759 name = name.Substring (0, arity);
761 method.Name = "~" + name;
764 if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count &&
765 l.Parameters.SequenceEqual (method.Parameters, new ParameterComparer ())))
774 if (t.IsInterface || t.IsEnum)
777 if (t.BaseType == null || t.BaseType.FullName == "System.Object")
780 t = t.BaseType.Resolve ();
784 return list.ToArray ();
787 sealed class ParameterComparer : IEqualityComparer<ParameterDefinition>
789 public bool Equals (ParameterDefinition x, ParameterDefinition y)
791 return x.ParameterType.Name == y.ParameterType.Name;
794 public int GetHashCode (ParameterDefinition obj)
796 return obj.ParameterType.Name.GetHashCode ();
800 static bool IsFinalizer (MethodDefinition method)
802 if (method.Name != "Finalize")
805 if (!method.IsVirtual)
808 if (method.Parameters.Count != 0)
814 private MethodDefinition [] GetConstructors (TypeDefinition type)
816 ArrayList list = new ArrayList ();
818 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
819 foreach (MethodDefinition constructor in ctors) {
820 // we're only interested in public or protected members
821 if (!MustDocumentMethod(constructor))
824 list.Add (constructor);
827 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
830 private EventDefinition[] GetEvents (TypeDefinition type)
832 ArrayList list = new ArrayList ();
834 var events = type.Events;//type.GetEvents (flags);
835 foreach (EventDefinition eventDef in events) {
836 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
838 if (addMethod == null || !MustDocumentMethod (addMethod))
844 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
848 class FieldData : MemberData
850 public FieldData (XmlWriter writer, FieldDefinition [] members)
851 : base (writer, members)
855 protected override string GetName (MemberReference memberDefenition)
857 FieldDefinition field = (FieldDefinition) memberDefenition;
861 protected override string GetMemberAttributes (MemberReference memberDefenition)
863 FieldDefinition field = (FieldDefinition) memberDefenition;
864 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
867 protected override void AddExtraAttributes (MemberReference memberDefinition)
869 base.AddExtraAttributes (memberDefinition);
871 FieldDefinition field = (FieldDefinition) memberDefinition;
872 AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
874 if (field.IsLiteral) {
875 object value = field.Constant;//object value = field.GetValue (null);
876 string stringValue = null;
877 //if (value is Enum) {
878 // // FIXME: when Mono bug #60090 has been
879 // // fixed, we should just be able to use
880 // // Convert.ToString
881 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
884 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
887 if (stringValue != null)
888 AddAttribute ("value", stringValue);
892 public override string ParentTag {
893 get { return "fields"; }
896 public override string Tag {
897 get { return "field"; }
901 class PropertyData : MemberData
903 public PropertyData (XmlWriter writer, PropertyDefinition [] members)
904 : base (writer, members)
908 protected override string GetName (MemberReference memberDefenition)
910 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
914 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
916 MethodDefinition _get = prop.GetMethod;
917 MethodDefinition _set = prop.SetMethod;
918 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
919 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
920 haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
921 MethodDefinition [] methods;
923 if (haveGet && haveSet) {
924 methods = new MethodDefinition [] { _get, _set };
925 } else if (haveGet) {
926 methods = new MethodDefinition [] { _get };
927 } else if (haveSet) {
928 methods = new MethodDefinition [] { _set };
937 protected override void AddExtraAttributes (MemberReference memberDefinition)
939 base.AddExtraAttributes (memberDefinition);
941 PropertyDefinition prop = (PropertyDefinition) memberDefinition;
942 AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
945 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
947 if (methods != null && haveParameters) {
948 string parms = Parameters.GetSignature (methods [0].Parameters);
949 if (!string.IsNullOrEmpty (parms))
950 AddAttribute ("params", parms);
955 protected override void AddExtraData (MemberReference memberDefenition)
957 base.AddExtraData (memberDefenition);
960 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
965 MethodData data = new MethodData (writer, methods);
966 //data.NoMemberAttributes = true;
970 protected override string GetMemberAttributes (MemberReference memberDefenition)
972 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
973 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
976 public override string ParentTag {
977 get { return "properties"; }
980 public override string Tag {
981 get { return "property"; }
985 class EventData : MemberData
987 public EventData (XmlWriter writer, EventDefinition [] members)
988 : base (writer, members)
992 protected override string GetName (MemberReference memberDefenition)
994 EventDefinition evt = (EventDefinition) memberDefenition;
998 protected override string GetMemberAttributes (MemberReference memberDefenition)
1000 EventDefinition evt = (EventDefinition) memberDefenition;
1001 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
1004 protected override void AddExtraAttributes (MemberReference memberDefinition)
1006 base.AddExtraAttributes (memberDefinition);
1008 EventDefinition evt = (EventDefinition) memberDefinition;
1009 AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
1012 public override string ParentTag {
1013 get { return "events"; }
1016 public override string Tag {
1017 get { return "event"; }
1021 class MethodData : MemberData
1025 public MethodData (XmlWriter writer, MethodDefinition [] members)
1026 : base (writer, members)
1030 protected override string GetName (MemberReference memberDefenition)
1032 MethodDefinition method = (MethodDefinition) memberDefenition;
1033 string name = method.Name;
1034 string parms = Parameters.GetSignature (method.Parameters);
1036 return string.Format ("{0}({1})", name, parms);
1039 protected override string GetMemberAttributes (MemberReference memberDefenition)
1041 MethodDefinition method = (MethodDefinition) memberDefenition;
1042 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
1045 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
1047 var mbase = (MethodDefinition) member;
1048 return mbase.MethodReturnType;
1051 protected override void AddExtraAttributes (MemberReference memberDefinition)
1053 base.AddExtraAttributes (memberDefinition);
1055 if (!(memberDefinition is MethodDefinition))
1058 MethodDefinition mbase = (MethodDefinition) memberDefinition;
1060 if (mbase.IsAbstract)
1061 AddAttribute ("abstract", "true");
1062 if (mbase.IsVirtual)
1063 AddAttribute ("virtual", "true");
1064 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
1065 AddAttribute ("sealed", "true");
1067 AddAttribute ("static", "true");
1068 var baseMethod = TypeHelper.GetBaseMethodInTypeHierarchy (mbase);
1069 if (baseMethod != null && baseMethod != mbase) {
1070 // This indicates whether this method is an override of another method.
1071 // This information is not necessarily available in the api info for any
1072 // particular assembly, because a method is only overriding another if
1073 // there is a base virtual function with the same signature, and that
1074 // base method can come from another assembly.
1075 AddAttribute ("is-override", "true");
1077 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
1078 if (rettype != "System.Void" || !mbase.IsConstructor)
1079 AddAttribute ("returntype", (rettype));
1081 // if (mbase.MethodReturnType.HasCustomAttributes)
1082 // AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
1085 protected override void AddExtraData (MemberReference memberDefenition)
1087 base.AddExtraData (memberDefenition);
1089 if (!(memberDefenition is MethodDefinition))
1092 MethodDefinition mbase = (MethodDefinition) memberDefenition;
1094 ParameterData parms = new ParameterData (writer, mbase.Parameters);
1097 MemberData.OutputGenericParameters (writer, mbase);
1100 public override bool NoMemberAttributes {
1101 get { return noAtts; }
1102 set { noAtts = value; }
1105 public override string ParentTag {
1106 get { return "methods"; }
1109 public override string Tag {
1110 get { return "method"; }
1114 class ConstructorData : MethodData
1116 public ConstructorData (XmlWriter writer, MethodDefinition [] members)
1117 : base (writer, members)
1121 public override string ParentTag {
1122 get { return "constructors"; }
1125 public override string Tag {
1126 get { return "constructor"; }
1130 class ParameterData : BaseData
1132 private IList<ParameterDefinition> parameters;
1134 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters)
1137 this.parameters = parameters;
1140 public override void DoOutput ()
1142 writer.WriteStartElement ("parameters");
1143 foreach (ParameterDefinition parameter in parameters) {
1144 writer.WriteStartElement ("parameter");
1145 AddAttribute ("name", parameter.Name);
1146 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1147 AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
1149 string direction = "in";
1151 if (parameter.ParameterType is ByReferenceType)
1152 direction = parameter.IsOut ? "out" : "ref";
1154 TypeReference t = parameter.ParameterType;
1155 AddAttribute ("type", Utils.CleanupTypeName (t));
1157 if (parameter.IsOptional) {
1158 AddAttribute ("optional", "true");
1159 if (parameter.HasConstant)
1160 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1163 if (direction != "in")
1164 AddAttribute ("direction", direction);
1166 AttributeData.OutputAttributes (writer, parameter);
1167 writer.WriteEndElement (); // parameter
1169 writer.WriteEndElement (); // parameters
1175 public static void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1178 throw new InvalidOperationException ("Document not set");
1180 if (providers == null || providers.Count == 0)
1183 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1186 writer.WriteStartElement ("attributes");
1188 foreach (var provider in providers) {
1189 if (provider == null)
1192 if (!provider.HasCustomAttributes)
1196 var ass = provider as AssemblyDefinition;
1197 if (ass != null && !Driver.FollowForwarders)
1198 TypeForwardedToData.OutputForwarders (writer, ass);
1200 var attributes = provider.CustomAttributes.
1201 Where ((att) => !SkipAttribute (att)).
1202 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1204 foreach (var att in attributes) {
1205 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1207 writer.WriteStartElement ("attribute");
1208 writer.WriteAttributeString ("name", attName);
1210 var attribute_mapping = CreateAttributeMapping (att);
1212 if (attribute_mapping != null) {
1213 var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId");
1214 if (mapping.Any ()) {
1215 writer.WriteStartElement ("properties");
1216 foreach (var kvp in mapping) {
1217 string name = kvp.Key;
1218 object o = kvp.Value;
1220 writer.WriteStartElement ("property");
1221 writer.WriteAttributeString ("name", name);
1224 writer.WriteAttributeString ("value", "null");
1226 string value = o.ToString ();
1227 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1228 value = value.ToUpper ();
1229 writer.WriteAttributeString ("value", value);
1232 writer.WriteEndElement (); // property
1234 writer.WriteEndElement (); // properties
1237 writer.WriteEndElement (); // attribute
1241 writer.WriteEndElement (); // attributes
1244 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1246 Dictionary<string, object> mapping = null;
1248 PopulateMapping (ref mapping, attribute);
1250 var constructor = attribute.Constructor.Resolve ();
1251 if (constructor == null || !constructor.HasParameters)
1254 PopulateMapping (ref mapping, constructor, attribute);
1259 static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
1261 if (!attribute.HasProperties)
1264 foreach (var named_argument in attribute.Properties) {
1265 var name = named_argument.Name;
1266 var arg = named_argument.Argument;
1268 if (arg.Value is CustomAttributeArgument)
1269 arg = (CustomAttributeArgument) arg.Value;
1271 if (mapping == null)
1272 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1273 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1277 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1279 Dictionary<FieldReference, int> field_mapping = null;
1281 int? argument = null;
1283 foreach (Instruction instruction in constructor.Body.Instructions) {
1284 switch (instruction.OpCode.Code) {
1296 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1300 FieldReference field = (FieldReference) instruction.Operand;
1301 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1304 if (!argument.HasValue)
1307 if (field_mapping == null)
1308 field_mapping = new Dictionary<FieldReference, int> ();
1310 if (!field_mapping.ContainsKey (field))
1311 field_mapping.Add (field, (int) argument - 1);
1318 return field_mapping;
1321 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1323 Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
1325 foreach (PropertyDefinition property in type.Properties) {
1326 if (property.GetMethod == null)
1328 if (!property.GetMethod.HasBody)
1331 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1332 if (instruction.OpCode.Code != Code.Ldfld)
1335 FieldReference field = (FieldReference) instruction.Operand;
1336 if (field.DeclaringType.FullName != type.FullName)
1339 if (property_mapping == null)
1340 property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1341 property_mapping.Add (property, field);
1346 return property_mapping;
1349 static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1351 if (!constructor.HasBody)
1354 // Custom handling for attributes with arguments which cannot be easily extracted
1355 var ca = attribute.ConstructorArguments;
1356 switch (constructor.DeclaringType.FullName) {
1357 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1358 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1359 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1360 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1362 if (mapping == null)
1363 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1364 mapping.Add ("Value", dca.Value);
1366 case "System.ComponentModel.BindableAttribute":
1370 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1371 if (mapping == null)
1372 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1373 mapping.Add ("Bindable", ca[0].Value);
1375 throw new NotImplementedException ();
1381 var field_mapping = CreateArgumentFieldMapping (constructor);
1382 if (field_mapping != null) {
1383 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1385 if (property_mapping != null) {
1386 foreach (var pair in property_mapping) {
1388 if (!field_mapping.TryGetValue (pair.Value, out argument))
1391 var ca_arg = ca [argument];
1392 if (ca_arg.Value is CustomAttributeArgument)
1393 ca_arg = (CustomAttributeArgument)ca_arg.Value;
1395 if (mapping == null)
1396 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1397 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1403 static object GetArgumentValue (TypeReference reference, object value)
1405 var type = reference.Resolve ();
1410 if (IsFlaggedEnum (type))
1411 return GetFlaggedEnumValue (type, value);
1413 return GetEnumValue (type, value);
1419 static bool IsFlaggedEnum (TypeDefinition type)
1424 if (!type.HasCustomAttributes)
1427 foreach (CustomAttribute attribute in type.CustomAttributes)
1428 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1434 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1437 return GetFlaggedEnumValue (type, (ulong)value);
1439 long flags = Convert.ToInt64 (value);
1440 var signature = new StringBuilder ();
1442 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1443 FieldDefinition field = type.Fields [i];
1445 if (!field.HasConstant)
1448 long flag = Convert.ToInt64 (field.Constant);
1453 if ((flags & flag) == flag) {
1454 if (signature.Length != 0)
1455 signature.Append (", ");
1457 signature.Append (field.Name);
1462 return signature.ToString ();
1465 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1467 var signature = new StringBuilder ();
1469 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1470 FieldDefinition field = type.Fields [i];
1472 if (!field.HasConstant)
1475 ulong flag = Convert.ToUInt64 (field.Constant);
1480 if ((flags & flag) == flag) {
1481 if (signature.Length != 0)
1482 signature.Append (", ");
1484 signature.Append (field.Name);
1489 return signature.ToString ();
1492 static object GetEnumValue (TypeDefinition type, object value)
1494 foreach (FieldDefinition field in type.Fields) {
1495 if (!field.HasConstant)
1498 if (Comparer.Default.Compare (field.Constant, value) == 0)
1505 static bool SkipAttribute (CustomAttribute attribute)
1507 if (!TypeHelper.IsPublic (attribute))
1510 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1513 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1515 AttributeData.DoOutput (writer, providers);
1519 static class Parameters {
1521 public static string GetSignature (IList<ParameterDefinition> infos)
1523 if (infos == null || infos.Count == 0)
1524 return string.Empty;
1526 var signature = new StringBuilder ();
1527 for (int i = 0; i < infos.Count; i++) {
1530 signature.Append (", ");
1532 ParameterDefinition info = infos [i];
1534 if (info.ParameterType.IsByReference) {
1536 if ((info.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
1541 signature.Append (modifier);
1542 signature.Append (" ");
1545 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1548 return signature.ToString ();
1553 class TypeReferenceComparer : IComparer<TypeReference>
1555 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1557 public int Compare (TypeReference a, TypeReference b)
1559 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1563 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1567 class MemberReferenceComparer : IComparer
1569 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1571 public int Compare (object a, object b)
1573 MemberReference ma = (MemberReference) a;
1574 MemberReference mb = (MemberReference) b;
1575 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1579 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1581 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1583 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1585 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1589 if (!ma.HasParameters && !mb.HasParameters)
1592 if (!ma.HasParameters)
1595 if (!mb.HasParameters)
1598 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1602 class MethodDefinitionComparer : IComparer
1604 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1606 public int Compare (object a, object b)
1608 MethodDefinition ma = (MethodDefinition) a;
1609 MethodDefinition mb = (MethodDefinition) b;
1610 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1614 if (!ma.HasParameters && !mb.HasParameters)
1617 if (!ma.HasParameters)
1620 if (!mb.HasParameters)
1623 res = Compare (ma.Parameters, mb.Parameters);
1627 if (ma.HasGenericParameters != mb.HasGenericParameters)
1628 return ma.HasGenericParameters ? -1 : 1;
1630 if (ma.HasGenericParameters && mb.HasGenericParameters) {
1631 res = ma.GenericParameters.Count - mb.GenericParameters.Count;
1636 // operators can differ by only return type
1637 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1640 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1642 var res = pia.Count - pib.Count;
1646 string siga = Parameters.GetSignature (pia);
1647 string sigb = Parameters.GetSignature (pib);
1648 return String.Compare (siga, sigb, StringComparison.Ordinal);